You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure DevOps中PowerShell创建发布阶段遇VS402877错误求助

问题:Azure DevOps发布流程创建阶段时VS402877错误

尝试使用PowerShell脚本在Azure DevOps的发布流程中创建名为TestAvo的阶段,但无论将preDeployApprovals设为null还是空数组@(),始终报错VS402877,提示该阶段的预审批或后审批为空,请指定审批信息后重试。

报错详情

Error: 
Invoke-WebRequest : {"$id":"1","innerException":null,"message":"VS402877: Pre-approvals or post-approvals in stage 'TestAvo' are empty. Specify approvals and try 
again.","typeName":"Microsoft.VisualStudio.Services.ReleaseManagement.Data.Exceptions.InvalidRequestException, 
Microsoft.VisualStudio.Services.ReleaseManagement2.Data","typeKey":"InvalidRequestException","errorCode":0,"eventId":3000}

原脚本

#--------------------------------------------Configuration--------------------------------------------
$global:token = "X"
$global:token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$global:header = @{authorization = "Basic $token"}
$organization = 'X'
$project = 'X'
$definitionID = 1
$stageName = 'TestAvo'

#------------------------------------------------Functions------------------------------------------------

function Get_Release ($definitionID){
    $URI = 'https://vsrm.dev.azure.com/'+$organization+'/'+$project+'/_apis/release/definitions/'+$definitionID+'?api-version=6.0'
    $response = Invoke-WebRequest -Method GET -Uri $URI -Headers @{Authorization = "Basic $token"} -ErrorAction Stop
    if ($response.StatusCode -eq 200) {
        $Release = $response.Content | ConvertFrom-Json
        # Add retention policy to stage
        foreach ($stage in $Release.environments) {
            if ($stage.name -eq $stageName) {
                $stage.retentionPolicy = @{
                    daysToKeep = 7
                    releasesToKeep = 3
                    retainBuild = "false"
                }
            }
        }
        return $Release
    } else {
        Write-Error "Failed to get release definition. Status code: $($response.StatusCode)"
        return $null
    }
}


function Export_Release($release){
    $output_name = $release.name
    $release = $release | ConvertTo-Json -Depth 99
    $release | Out-File ('C:\Temp\Releases\'+$output_name+'.txt')
    
}

function Invoke_Release($Release){

    $Release = $Release | ConvertTo-Json -Depth 99
    $URI = 'https://vsrm.dev.azure.com/'+$organization+'/'+$project+'/_apis/release/definitions/'+$definitionID+'?api-version=6.0'
    $response = Invoke-WebRequest -Uri $URI -Method PUT -Headers $header -UseBasicParsing -Body $Release -ContentType application/json -ErrorAction Stop
    if ($response.StatusCode -ne 200) {
        Write-Error "Failed to update release. Status code: $($response.StatusCode)"
    }
}

#------------------------------------------------Main------------------------------------------------

$Release = Get_Release $definitionID

if ($release) {
    # Check if stage already exists
    if ($release.environments | Where-Object {$_.name -eq $stageName}) {
        Write-Warning "Stage '$stageName' already exists."
    } else {
        # Create new stage
        $retention = @{
            daysToKeep = 7
            releasesToKeep = 3
            retainBuild = "false"
        }
        $newStage = @{
            name = $stageName
            rank = $release.environments.Count + 1
            retentionPolicy = $retention
            preDeployApprovals = @()
        }
        $release.environments += $newStage
        Invoke_Release $release
        Write-Host "Stage '$stageName' created successfully."
    }
}

解决方案

Azure DevOps Release API要求阶段的审批配置不能是单纯的空数组或null,必须提供包含approvals数组和approvalOptions的完整结构。即使不需要审批,也需要将approvalOptions中的requiredApproverCount设为0,以此满足API的结构校验要求。

修改脚本中创建新阶段的部分,为preDeployApprovals和postDeployApprovals补充完整的结构:

# Create new stage
$retention = @{
    daysToKeep = 7
    releasesToKeep = 3
    retainBuild = "false"
}
$approvalOptions = @{
    requiredApproverCount = 0
    releaseCreatorCanBeApprover = $true
    autoTriggeredAndPreviousEnvironmentApprovedCanBeSkipped = $false
    enforceIdentityRevalidation = $false
    timeoutInMinutes = 0
    executionOrder = "beforeGates"
}
$postApprovalOptions = $approvalOptions.PSObject.Copy()
$postApprovalOptions.executionOrder = "afterGates"

$newStage = @{
    name = $stageName
    rank = $release.environments.Count + 1
    retentionPolicy = $retention
    preDeployApprovals = @{
        approvals = @()
        approvalOptions = $approvalOptions
    }
    postDeployApprovals = @{
        approvals = @()
        approvalOptions = $postApprovalOptions
    }
}
$release.environments += $newStage
Invoke_Release $release
Write-Host "Stage '$stageName' created successfully."

说明

  • requiredApproverCount = 0:表示不需要任何审批人,阶段会自动跳过审批步骤
  • 必须同时提供preDeployApprovals和postDeployApprovals的完整结构,避免API校验报错
  • 复制approvalOptions并修改executionOrder,确保前后审批的配置符合API要求

内容的提问来源于stack exchange,提问作者kolieyr42

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:24:55