如何通过PowerShell脚本启用/禁用生成管道任务及报错排查
问题场景
通过修改JSON配置的方式更新TFS生成管道的任务禁用状态,核心逻辑为通过$TaskDetail.enabled = "false"设置任务禁用属性后,将更新后的JSON提交至TFS接口,使用的原始PowerShell脚本如下:
$BuildName = "Test-demo" $buildTaskName = 'Print Hello World' $BuildDefinitions = Invoke-WebRequest -Headers $headers -Uri ("{0}/_apis/build/definitions?api-version=5.0" -f $TFSProjectURL) $BuildDefinitionsDetail = convertFrom-JSON $BuildDefinitions.Content foreach($BuildDetail in $BuildDefinitionsDetail.value){ if($BuildDetail.name -eq $BuildName) { $Id = $BuildDetail.id $name = $BuildDetail.name $Project = $BuildDetail.project.name $BuildTask = Invoke-WebRequest -Headers $headers -Uri ("{0}/_apis/build/definitions/$($Id)?api-version=5.0" -f $TFSProjectURL) $BuildTaskDetails = convertFrom-JSON $BuildTask.Content foreach($TaskDetail in $BuildTaskDetails.process.phases.steps){ if($TaskDetail.displayName -eq $buildTaskName) { $taskName = $TaskDetail.displayName $TaskDetail.enabled = "false" } } Write-Host $BuildTaskDetails $Updatedbuilddef = ConvertTo-Json $BuildTaskDetails buildUri = "$TFSProjectURL//_apis/build/definitions/$Id?api-version=5." $buildResponse =Invoke-WebRequest -Headers $headers -Uri $buildUri -Method Put -ContentType "application/json" -Body $Updatedbuilddef } }
脚本执行时抛出如下异常:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.","typeName":"System.Web.Http.HttpResponseException, System.Web.Http","typeKey":"HttpResponseException","errorCode":0,"eventId":0}
At C:\Users\Z004APNA\Desktop\BuildPipelineScript\BuildDefinition_edit.ps1:145 char:26
- ... dResponse = Invoke-RestMethod -Uri $buildUri -Method Post -Headers $h ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
- FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
根因定位
脚本存在4个直接触发接口报错的问题:
- 接口请求配置错误:
buildUri变量前漏写PowerShell变量必需的$前缀;地址中存在多余双斜杠//_apis;api-version=5.版本号不完整;且报错信息显示实际执行时误用了Post请求方法(更新现有生成定义必须用Put方法,Post仅用于新建定义)。 - 字段类型不匹配:TFS接口要求
enabled字段为布尔类型,原始代码传的是字符串值"false",类型校验不通过。 - JSON序列化深度不足:PowerShell自带的
ConvertTo-Json命令默认序列化深度仅为2层,生成管道配置对象层级远大于2,深层结构会被序列化为纯字符串,导致提交的JSON结构不符合接口规范。 - 隐性校验问题:序列化过程如果丢失了定义自带的
revision版本校验字段,也会触发接口的并发更新校验报错。
修复方案
针对以上问题逐点修正,修正后可正常运行的脚本如下:
$BuildName = "Test-demo" $buildTaskName = 'Print Hello World' $BuildDefinitions = Invoke-WebRequest -Headers $headers -Uri ("{0}/_apis/build/definitions?api-version=5.0" -f $TFSProjectURL) $BuildDefinitionsDetail = ConvertFrom-Json $BuildDefinitions.Content foreach($BuildDetail in $BuildDefinitionsDetail.value){ if($BuildDetail.name -eq $BuildName) { $Id = $BuildDetail.id $BuildTask = Invoke-WebRequest -Headers $headers -Uri ("{0}/_apis/build/definitions/$($Id)?api-version=5.0" -f $TFSProjectURL) $BuildTaskDetails = ConvertFrom-Json $BuildTask.Content foreach($TaskDetail in $BuildTaskDetails.process.phases.steps){ if($TaskDetail.displayName -eq $buildTaskName) { # 传布尔值而非字符串 $TaskDetail.enabled = $false } } # 加-Depth参数保证深层结构完整序列化,移除多余斜杠、补全版本号、变量加$前缀 $Updatedbuilddef = ConvertTo-Json $BuildTaskDetails -Depth 10 $buildUri = "$TFSProjectURL/_apis/build/definitions/$Id?api-version=5.0" # 明确使用Put方法,不要误用Post $buildResponse = Invoke-WebRequest -Headers $headers -Uri $buildUri -Method Put -ContentType "application/json" -Body $Updatedbuilddef } }
如果执行仍有报错,可以先把$Updatedbuilddef输出到本地文件,检查JSON结构是否完整、字段类型是否符合要求,再提交接口即可。
内容的提问来源于stack exchange,提问作者Avin Verma

