Azure DevOps YAML扩展模板Unrecognized value 'else'报错解决
YAML扩展阶段模板else表达式报错问题
在job.steps的foreach循环内添加else条件时,会触发报错:Unrecognized value: 'else'. Located at position 1 within expression: else
测试用构建YAML
resources: repositories: - repository: self type: git ref: refs/heads/Development - repository: AdoRestrictions type: git name: utl-yaml-templates ref: refs/heads/main trigger: none pool: name: PROD extends: template: ADO_Stage_Restrictions_Dev.yml@AdoRestrictions parameters: stageObjs: - stage: 'BuildStage' displayName: 'Build Test' jobs: - job: 'BuildJob' displayName: 'Build' steps: - task: PowerShell@2 displayName: 'PS Hello World' inputs: targetType: inline script: | Write-Host "Hello World"
可正常运行的基础扩展模板
未添加else分支时,模板可正常解析运行:
parameters: - name: stageObjs type: stageList default: [] stages: - ${{ each stage in parameters.stageObjs }}: - stage: ${{ stage.stage }} displayName: ${{ stage.displayName }} jobs: - ${{ each job in stage.jobs }}: - job: ${{ job.job }} displayName: ${{ job.displayName }} steps: - ${{ each step in job.steps }}: - ${{ if or(startsWith(step.task, 'PowerShell'),startsWith(step.task, 'CmdLine'),startsWith(step.task, 'Bash'),startsWith(step.task, 'ShellScript'),containsValue(step.task, 'Script'),containsValue(step.task, 'CLI'),containsValue(step.task, 'PowerShell')) }}: - task: PowerShell@2 displayName: 'Unapproved - ${{ step.displayName }}' inputs: targetType: inline script: Write-Output "Unapproved Task - Scripting and CLI tasks are not approved for use in yaml pipelines"
添加else分支后的异常模板
添加else分支后模板解析失败:
parameters: - name: stageObjs type: stageList default: [] stages: - ${{ each stage in parameters.stageObjs }}: - stage: ${{ stage.stage }} displayName: ${{ stage.displayName }} jobs: - ${{ each job in stage.jobs }}: - job: ${{ job.job }} displayName: ${{ job.displayName }} steps: - ${{ each step in job.steps }}: - ${{ if or(startsWith(step.task, 'PowerShell'),startsWith(step.task, 'CmdLine'),startsWith(step.task, 'Bash'),startsWith(step.task, 'ShellScript'),containsValue(step.task, 'Script'),containsValue(step.task, 'CLI'),containsValue(step.task, 'PowerShell')) }}: - task: PowerShell@2 displayName: 'Unapproved - ${{ step.displayName }}' inputs: targetType: inline script: Write-Output "Unapproved Task - Scripting and CLI tasks are not approved for use in yaml pipelines" - ${{ else }}: - ${{ step }}
完整报错信息
(Line: 22, Col: 13): Unrecognized value: 'else'. Located at position 1 within expression: else. (Line: 22, Col: 13): Expected at least one key-value pair in the mapping
报错原因
Azure DevOps YAML模板解析器在each循环生成序列的上下文中,无法正确绑定独立作为序列项的${{ else }}表达式和前置的if条件,导致解析失败。
可用解决方案
放弃直接使用${{ else }}语法,改为对条件取反后写独立的if分支实现相同逻辑,同时可扩展更多校验规则,验证可用的模板代码如下:
parameters: - name: stageObjs type: stageList default: [] stages: - ${{ each stage in parameters.stageObjs }}: - stage: ${{ stage.stage }} displayName: ${{ stage.displayName }} jobs: - ${{ each job in stage.jobs }}: - job: ${{ job.job }} displayName: ${{ job.displayName }} steps: - ${{ each step in job.steps }}: # 拦截所有未获批的脚本类任务 - ${{ if or(startsWith(step.task, 'PowerShell'),startsWith(step.task, 'CmdLine'),startsWith(step.task, 'Bash'),startsWith(step.task, 'ShellScript'),contains(step.task, 'Script'),contains(step.task, 'CLI'),contains(step.task, 'PowerShell')) }}: - task: PowerShell@2 displayName: 'Unapproved Task - ${{ step.displayName }}' inputs: targetType: inline script: throw "Unapproved Task - Scripting and CLI tasks are not approved for use in yaml pipelines" # 非脚本类任务执行额外校验 - ${{ if and(not(startsWith(step.task, 'PowerShell')),not(startsWith(step.task, 'CmdLine')),not(startsWith(step.task, 'Bash')),not(startsWith(step.task, 'ShellScript')),not(contains(step.task, 'Script')),not(contains(step.task, 'CLI')),not(contains(step.task, 'PowerShell')) ) }}: # 校验Azure相关任务的订阅是否在允许列表内 - ${{ if contains(step.task, 'Azure') }}: - ${{ each pair in step }}: ${{ if eq(pair.key, 'inputs') }}: inputs: ${{ each attribute in pair.value }}: ${{ if contains(attribute.key, 'Subscription') }}: ${{ if and(ne(attribute.value, 'sub-name1'), ne(attribute.value, 'sub-name2'), ne(attribute.value, 'sub-name3')) }}: ${{ attribute.value }}: '' ${{ if or(eq(attribute.value, 'sub-name1'), eq(attribute.value, 'sub-name2'), eq(attribute.value, 'sub-anme3')) }}: ${{ pair.key }}: ${{ pair.value }} ${{ if ne(pair.key, 'inputs') }}: ${{ if eq(pair.key, 'displayName') }}: ${{ pair.key }}: 'Invalid Azure Subscription - ${{ pair.value }}' ${{ if ne(pair.key, 'displayName') }}: ${{ pair.key }}: ${{ pair.value }} # 其余非Azure类任务直接放行 - ${{ if not(contains(step.task, 'Azure')) }}: - ${{ step }}
该方案实现的校验逻辑:
- 第一层拦截所有未获批的脚本/CLI类任务,替换为抛出错误的PowerShell任务
- 第二层对非脚本类任务做额外校验,针对Azure相关任务校验订阅是否在允许列表内,非Azure类任务直接放行
内容的提问来源于stack exchange,提问作者Bri
相关产品推荐
相关产品推荐

