# 构建和测试 PowerShell

了解如何创建持续集成 (CI) 工作流来构建和测试 PowerShell 项目。

##

简介 本指南演示如何将 PowerShell 用于 CI。

本文介绍如何使用 Pester、安装依赖项、测试模块并发布到PowerShell Gallery。

GitHub 托管运行器具有一个带预装软件的工具缓存，包括 PowerShell 和 Pester。

## 有关最新软件和 PowerShell 和 Pester 预装版本的完整列表，请参阅“[GitHub 托管的运行程序](/zh/enterprise-cloud@latest/actions/using-github-hosted-runners/about-github-hosted-runners#supported-software)”。

先决条件 你应该熟悉 YAML 和 GitHub Actions 的语法。

有关详细信息，请参阅“[撰写工作流程](/zh/enterprise-cloud@latest/actions/learn-github-actions)”。 建议您对 PowerShell 和 Pester 有个基本的了解。

* 有关详细信息，请参阅：
* ```
          [开始使用 PowerShell](https://docs.microsoft.com/powershell/scripting/learn/ps101/01-getting-started)
  ```

##

```
          [Pester](https://pester.dev)
```

为 Pester 添加工作流程

要使用 PowerShell 和 Pester 自动化您的测试，您可以添加一个在每次有更改推送到您的代码库时运行的工作流程。

```yaml
name: Test PowerShell on Ubuntu
on: push

jobs:
  pester-test:
    name: Pester test
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository code
        uses: actions/checkout@v5
      - name: Perform a Pester test from the command-line
        shell: pwsh
        run: Test-Path resultsfile.log | Should -Be $true
      - name: Perform a Pester test from the Tests.ps1 file
        shell: pwsh
        run: |
          Invoke-Pester Unit.Tests.ps1 -Passthru
```

* 在以下示例中，`Test-Path` 用于检查名为 `resultsfile.log` 的文件是否存在。

* 必须将此示例工作流文件添加到存储库的 `.github/workflows/` 目录：

* ```
          `shell: pwsh` - 将作业配置为在运行 `run` 命令时使用 PowerShell。 
          `run: Test-Path resultsfile.log` - 检查存储库的根目录中是否存在名为 `resultsfile.log` 的文件。 
          `Should -Be $true` - 使用 Pester 定义预期结果。
  ```

  ![如果结果是非预期的，则 GitHub Actions 会将此标记为失败的测试。 例如：](/assets/images/help/repository/actions-failed-pester-test-updated.png)

* 屏幕截图显示 Pester 测试的工作流运行失败。 测试报告“预期为 $true，结果为 $false”和“错误：进程完成时显示退出代码 1”。

  ```powershell
  Describe "Check results file is present" {
      It "Check results file is present" {
          Test-Path resultsfile.log | Should -Be $true
      }
  }
  ```

##

```
          `Invoke-Pester Unit.Tests.ps1 -Passthru` - 使用 Pester 执行在名为 `Unit.Tests.ps1` 的文件中定义的测试。
```

例如，若要执行上述相同的测试，`Unit.Tests.ps1` 将包含以下命令：

<div class="ghd-tool rowheaders">

|| PowerShell 模块位置 | 下表描述了每个 GitHub 托管的运行器中各个 PowerShell 模块的位置。 | <div class="ghd-tool rowheaders">
|
\|------|-------|------|----------|
|Ubuntu |`/opt/microsoft/powershell/7/Modules/*`|`/usr/local/microsoft/powershell/7/Modules/*`|`C:\program files\powershell\7\Modules\*`|
|macOS|`/usr/local/share/powershell/Modules/*`|`/usr/local/share/powershell/Modules/*`|`C:\Modules\*`|
|Windows|`/home/runner/.local/share/powershell/Modules/*`|`/Users/runner/.local/share/powershell/Modules/*`|`C:\Users\runneradmin\Documents\PowerShell\Modules\*`|

</div>

> \[!NOTE]
> PowerShell 系统模块

## PowerShell 插件模块

用户安装的模块 </div>

> \[!NOTE]
> 在 Ubuntu 运行程序上，Azure PowerShell模块存储在 `/usr/share/` 中，而不是 PowerShell 加载项模块的默认位置（即`/usr/local/share/powershell/Modules/`）。 安装依赖

GitHub 托管的运行器安装了 PowerShell 7 和 Pester。 在生成和测试代码之前，可以使用 `Install-Module` 从PowerShell Gallery安装其他依赖项。

由 GitHub 托管的运行器使用的预安装包（如 Pester）会定期更新，并且可能会引入重大更改。

```yaml
jobs:
  install-dependencies:
    name: Install dependencies
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install from PSGallery
        shell: pwsh
        run: |
          Set-PSRepository PSGallery -InstallationPolicy Trusted
          Install-Module SqlServer, PSScriptAnalyzer
```

> \[!NOTE]
> 因此，建议始终通过将 `Install-Module` 与 `-MaximumVersion` 结合使用来指定所需的包版本。 可以缓存依赖项来加快工作流运行。

### 有关详细信息，请参阅“[依赖项缓存参考](/zh/enterprise-cloud@latest/actions/using-workflows/caching-dependencies-to-speed-up-workflows)”。

例如，以下作业安装 `SqlServer` 和 `PSScriptAnalyzer` 模块： 默认情况下，PowerShell 不信任任何存储库。

从PowerShell Gallery安装模块时，必须将 `PSGallery` 的安装策略显式设置为 `Trusted`。 缓存依赖项

```yaml
steps:
  - uses: actions/checkout@v5
  - name: Setup PowerShell module cache
    id: cacher
    uses: actions/cache@v4
    with:
      path: "~/.local/share/powershell/Modules"
      key: ${{ runner.os }}-SqlServer-PSScriptAnalyzer
  - name: Install required PowerShell modules
    if: steps.cacher.outputs.cache-hit != 'true'
    shell: pwsh
    run: |
      Set-PSRepository PSGallery -InstallationPolicy Trusted
      Install-Module SqlServer, PSScriptAnalyzer -ErrorAction Stop
```

## 可使用唯一的键来缓存 PowerShell 依赖项，这样就可以通过 [`cache`](https://github.com/marketplace/actions/cache) 操作还原未来工作流的依赖项。

有关详细信息，请参阅“[依赖项缓存参考](/zh/enterprise-cloud@latest/actions/using-workflows/caching-dependencies-to-speed-up-workflows)”。

### PowerShell 根据运行器的操作系统将其依赖项缓存在不同的位置。

例如，以下 Ubuntu 示例中使用的 `path` 位置对于Windows作系统将有所不同。 测试代码

```yaml
  lint-with-PSScriptAnalyzer:
    name: Install and run PSScriptAnalyzer
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install PSScriptAnalyzer module
        shell: pwsh
        run: |
          Set-PSRepository PSGallery -InstallationPolicy Trusted
          Install-Module PSScriptAnalyzer -ErrorAction Stop
      - name: Lint with PSScriptAnalyzer
        shell: pwsh
        run: |
          Invoke-ScriptAnalyzer -Path *.ps1 -Recurse -Outvariable issues
          $errors   = $issues.Where({$_.Severity -eq 'Error'})
          $warnings = $issues.Where({$_.Severity -eq 'Warning'})
          if ($errors) {
              Write-Error "There were $($errors.Count) errors and $($warnings.Count) warnings total." -ErrorAction Stop
          } else {
              Write-Output "There were $($errors.Count) errors and $($warnings.Count) warnings total."
          }
```

## 您可以使用与本地相同的命令来构建和测试代码。

使用 PSScriptAnalyzer 链接代码 以下示例安装 `PSScriptAnalyzer` 并使用它对存储库中的所有 `ps1` 文件执行 lint 操作。 有关详细信息，请参阅 GitHub</c0> 上的 <c0>PSScriptAnalyzer。

将工作流数据打包为构件 您可以在工作流程完成后上传构件以查看。

```yaml
name: Upload artifact from Ubuntu

on: [push]

jobs:
  upload-pester-results:
    name: Run Pester and upload results
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Test with Pester
        shell: pwsh
        run: Invoke-Pester Unit.Tests.ps1 -Passthru | Export-CliXml -Path Unit.Tests.xml
      - name: Upload test results
        uses: actions/upload-artifact@v4
        with:
          name: ubuntu-Unit-Tests
          path: Unit.Tests.xml
    if: ${{ always() }}
```

例如，您可能需要保存日志文件、核心转储、测试结果或屏幕截图。 有关详细信息，请参阅“[使用工作流工件存储和共享数据](/zh/enterprise-cloud@latest/actions/using-workflows/storing-workflow-data-as-artifacts)”。

## 以下示例演示如何使用 `upload-artifact` 操作来存档从 `Invoke-Pester` 收到的测试结果。

有关详细信息，请参阅 [`upload-artifact` 操作](https://github.com/actions/upload-artifact)。
`always()` 函数将作业配置为即使存在测试失败也要继续处理。 有关详细信息，请参阅“[上下文参考](/zh/enterprise-cloud@latest/actions/learn-github-actions/contexts#always)”。

发布到PowerShell Gallery

```yaml
name: Publish PowerShell Module

on:
  release:
    types: [created]

jobs:
  publish-to-gallery:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Build and publish
        env:
          NUGET_KEY: ${{ secrets.NUGET_KEY }}
        shell: pwsh
        run: |
          ./build.ps1 -Path /tmp/samplemodule
          Publish-Module -Path /tmp/samplemodule -NuGetApiKey $env:NUGET_KEY -Verbose
```