Azure Pipeline中PowerShell传递数组至ARM模板时出现JToken类型不匹配错误求助
这个问题我之前也碰到过,核心原因很明确:你的ARM模板里fooBar参数定义的是object类型,但通过Pipeline传递时,实际传过去的是JSON字符串,ARM根本没法把字符串自动解析成它需要的对象类型,所以就报了那个类型不匹配的错误。
下面给你两种解决方案,优先推荐第一种,因为复杂对象用参数文件传递最靠谱:
方案一:用ARM参数文件传递复杂对象
这是处理复杂参数最稳妥的方式,咱们直接生成符合ARM规范的参数文件,而不是用变量传递:
1. 修改PowerShell脚本生成参数文件
把原来设置变量的代码改成生成参数文件的逻辑,这样脚本跑完后会输出一个ARM能直接识别的参数文件:
param( [string][parameter(Mandatory = $true)] $keyVaultName, [string][parameter(Mandatory = $true)] $resourceGroupName ) $keyVault = Get-AzKeyVault -Name $keyVaultName -ResourceGroupName $resourceGroupName if ($null -ne $keyVault) { $keyVaultAccessPolicies = $keyVault.AccessPolicies $armAccessPolicies = @() if($keyVaultAccessPolicies) { foreach($keyVaultAccessPolicy in $keyVaultAccessPolicies) { $armAccessPolicy = [pscustomobject]@{ tenantId = $keyVaultAccessPolicy.TenantId; objectId = $keyVaultAccessPolicy.ObjectId } $armAccessPolicyPermissions = [pscustomobject]@{ keys = $keyVaultAccessPolicy.PermissionsToKeys; secrets = $keyVaultAccessPolicy.PermissionsToSecrets; certificates = $keyVaultAccessPolicy.PermissionsToCertificates; storage = $keyVaultAccessPolicy.PermissionsToStorage } $armAccessPolicy | Add-Member -MemberType NoteProperty -Name permissions -Value $armAccessPolicyPermissions $armAccessPolicies += $armAccessPolicy } } # 构建ARM参数文件的标准结构 $parameterFileContent = [pscustomobject]@{ "$schema" = "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#" contentVersion = "1.0.0.0" parameters = [pscustomobject]@{ name = [pscustomobject]@{ value = $keyVaultName } fooBar = [pscustomobject]@{ value = [pscustomobject]@{ list = $armAccessPolicies } } } } # 把参数文件保存到你的artifact目录里,路径根据你实际的结构调整 $outputPath = "$(System.DefaultWorkingDirectory)/$(Provisioning.Package.Name)/Templates/key-vault-params.json" $parameterFileContent | ConvertTo-Json -Depth 5 | Out-File $outputPath -Force }
2. 更新Pipeline的YAML配置
接下来修改部署任务,指定咱们生成的参数文件,要是还有其他需要覆盖的参数(比如name想用Pipeline变量),直接在overrideParameters里加就行:
- task: AzureResourceManagerTemplateDeployment@3 displayName: 'Provision Key Vault' inputs: deploymentScope: 'Resource Group' azureResourceManagerConnection: ${{ parameters.azureSubscriptionName }} subscriptionId: ${{ parameters.azureSubscriptionId }} action: 'Create Or Update Resource Group' resourceGroupName: '$(Resource.Group.Name)' location: '$(Region)' templateLocation: 'Linked artifact' csmFile: '$(Provisioning.Package.Name)/Templates/key-vault-deploy.json' # 指定刚才生成的参数文件 csmParametersFile: '$(Provisioning.Package.Name)/Templates/key-vault-params.json' deploymentMode: 'Incremental' # 这里可以覆盖参数文件里的参数值,比如用Pipeline变量替换name overrideParameters: >- -name "$(KeyVault.Name)"
方案二:直接传递JSON字符串(不推荐,容易踩坑)
要是你不想用参数文件,也可以试试调整变量传递的方式,但这种方式很容易因为转义问题出错,尤其是JSON里有特殊字符的时候:
- 先把PowerShell里的
ConvertTo-Json命令去掉-Compress参数,保留格式化的JSON; - 在Pipeline的
overrideParameters里,用双引号把变量包起来,确保内部的双引号能被正确解析:
overrideParameters: >- -name "$(KeyVault.Name)" -fooBar "$(Infra.KeyVault.AccessPolicies)"
不过还是那句话,这种方式不如参数文件稳定,能不用就不用。
内容的提问来源于stack exchange,提问作者Dr Schizo
相关产品推荐
相关产品推荐

