使用 PowerShell 脚本来自定义管道

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

当你不满足于学习编译和测试代码这些基础知识时,可使用 PowerShell 脚本将你的团队的业务逻辑添加到你的生成管道。 可以在任何平台上的 Windows 生成代理或 PowerShell Core 上运行 Windows PowerShell。

使用 PowerShell 任务 PowerShell 任务时,PowerShell 脚本会在管道中运行。 可以使用 PowerShell 访问 Azure DevOps REST API,处理 Azure DevOps 工作项和测试管理,并根据需要调用其他服务。

添加 PowerShell 脚本

包括 PowerShell Core 的语法与 Windows PowerShell 的语法略有不同。

  1. 将 PowerShell 脚本推送到存储库。

  2. 在管道中添加 pwshpowershell 步骤。pwsh 关键字是 PowerShell Core 的 PowerShell 任务 的快捷方式。 powershell 关键字是 PowerShell 任务的另一快捷方式。

示例:

# for PowerShell Core
steps:
- pwsh: ./my-script.ps1

# for Windows PowerShell
steps:
- powershell: .\my-script.ps1

示例 PowerShell 脚本:版本程序集

下面是用于对程序集进行版本控制的示例脚本。 要让脚本成功运行,需要更新内部版本号以使用包含四个句点的格式(示例:$(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r))。 生成号也可以称为运行号。

可以使用 name 属性在 YAML 管道中自定义生成号

name: $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)

pool:
  vmImage: windows-latest

steps:
- pwsh: echo $(Build.BuildNumber) //output updated build number

示例 PowerShell 脚本:

# If found use it to version the assemblies.
#
# For example, if the 'Build number format' build pipeline parameter 
# $(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)
# then your build numbers come out like this:
# "Build HelloWorld_2013.07.19.1"
# This script would then apply version 2013.07.19.1 to your assemblies.
	
# Enable -Verbose option
[CmdletBinding()]
	
# Regular expression pattern to find the version in the build number 
# and then apply it to the assemblies
$VersionRegex = "\d+\.\d+\.\d+\.\d+"
	
# If this script is not running on a build server, remind user to 
# set environment variables so that this script can be debugged
if(-not ($Env:BUILD_SOURCESDIRECTORY -and $Env:BUILD_BUILDNUMBER))
{
	Write-Error "You must set the following environment variables"
	Write-Error "to test this script interactively."
	Write-Host '$Env:BUILD_SOURCESDIRECTORY - For example, enter something like:'
	Write-Host '$Env:BUILD_SOURCESDIRECTORY = "C:\code\FabrikamTFVC\HelloWorld"'
	Write-Host '$Env:BUILD_BUILDNUMBER - For example, enter something like:'
	Write-Host '$Env:BUILD_BUILDNUMBER = "Build HelloWorld_0000.00.00.0"'
	exit 1
}
	
# Make sure path to source code directory is available
if (-not $Env:BUILD_SOURCESDIRECTORY)
{
	Write-Error ("BUILD_SOURCESDIRECTORY environment variable is missing.")
	exit 1
}
elseif (-not (Test-Path $Env:BUILD_SOURCESDIRECTORY))
{
	Write-Error "BUILD_SOURCESDIRECTORY does not exist: $Env:BUILD_SOURCESDIRECTORY"
	exit 1
}
Write-Verbose "BUILD_SOURCESDIRECTORY: $Env:BUILD_SOURCESDIRECTORY"
	
# Make sure there is a build number
if (-not $Env:BUILD_BUILDNUMBER)
{
	Write-Error ("BUILD_BUILDNUMBER environment variable is missing.")
	exit 1
}
Write-Verbose "BUILD_BUILDNUMBER: $Env:BUILD_BUILDNUMBER"
	
# Get and validate the version data
$VersionData = [regex]::matches($Env:BUILD_BUILDNUMBER,$VersionRegex)
switch($VersionData.Count)
{
   0		
      { 
         Write-Error "Could not find version number data in BUILD_BUILDNUMBER."
         exit 1
      }
   1 {}
   default 
      { 
         Write-Warning "Found more than instance of version data in BUILD_BUILDNUMBER." 
         Write-Warning "Will assume first instance is version."
      }
}
$NewVersion = $VersionData[0]
Write-Verbose "Version: $NewVersion"
	
# Apply the version to the assembly property files
$files = gci $Env:BUILD_SOURCESDIRECTORY -recurse -include "*Properties*","My Project" | 
	?{ $_.PSIsContainer } | 
	foreach { gci -Path $_.FullName -Recurse -include AssemblyInfo.* }
if($files)
{
	Write-Verbose "Will apply $NewVersion to $($files.count) files."
	
	foreach ($file in $files) {
		$filecontent = Get-Content($file)
		attrib $file -r
		$filecontent -replace $VersionRegex, $NewVersion | Out-File $file
		Write-Verbose "$file.FullName - version applied"
	}
}
else
{
	Write-Warning "Found no files."
}

示例 PowerShell 脚本:访问 REST API

在此示例中,将使用 SYSTEM_ACCESSTOKEN 变量来访问 Azure Pipelines REST API

可以在 YAML 管道的脚本中使用 $env:SYSTEM_ACCESSTOKEN 来访问 OAuth 令牌。

下面的内联 PowerShell 脚本示例使用 OAuth 令牌来访问可检索管道定义的 Azure Pipelines REST API。

- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
              Write-Host "URL: $url"
              $pipeline = Invoke-RestMethod -Uri $url -Headers @{
                  Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
              }
              Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"
  env:
     SYSTEM_ACCESSTOKEN: $(System.AccessToken)

常见问题解答

哪些变量可供我在脚本中使用?

可以在脚本中使用预定义变量。 有关可用变量及其使用方法的详细信息,请参阅使用预定义变量

如何设置变量,以便后续脚本和任务可以读取它?

要详细了解如何在脚本中定义生成变量,请参阅在脚本中定义和修改生成变量

要详细了解如何在脚本中定义发布变量,请参阅在脚本中定义和修改发布变量

此生成运行脚本的哪个分支?

此生成使用代码的活动分支。 如果管道运行使用 main 分支,则脚本也可使用 main 分支。

我可以使用哪些类型的参数?

可以使用命名参数。 不支持其他类型的参数,例如开关参数。 如果尝试使用开关参数,将会看到错误。

我在本地使用 TFS,但没有看到其中某些功能。 为什么看不到?

其中某些功能仅在 Azure Pipelines 上可用,在本地尚不可用。 如果你已升级到最新版本的 TFS,则可在本地使用这些功能。