I'm trying to update the scopes for a app registration in Entra ID using the CLI authV2 extension but am seeing weird json handling when running from a pipeline in Azure DevOps.
The block of code essentially is this:
$appId = 'xxxxxx'
# get the API app reg details
$appRegApi = (az ad app show --id $appId --query 'api' | ConvertFrom-Json)
# check for scope
$scopes = $appRegApi.oauth2PermissionScopes
$scopeId = [guid]::NewGuid().Guid
$userImpersonationScope = [ordered]@{
adminConsentDescription = "user impersonation"
adminConsentDisplayName = "user_impersonation"
id = "$scopeId"
isEnabled = "true"
type = "User"
userConsentDescription = "user impersonation"
userConsentDisplayName = "user_impersonation"
value = "user_impersonation"
}
$update = @{
oauth2PermissionScopes = @($scopes; @($userImpersonationScope))
}
$updateJson = ConvertTo-Json $update -Depth 4 -Compress
$escapedJson = ConvertTo-Json $updateJson
az ad app update --id $appId --set api=$escapedJson --debug
If I run this locally, in the output from the --debug flag, I can see the payload looks like
{"api": {"oauth2PermissionScopes": [{"adminConsentDisplayName": "user_impersonation", "userConsentDisplayName": "user_impersonation", "value": "user_impersonation", "id": "xxxxxx", "type": "User", "isEnabled": "true", "userConsentDescription": "user impersonation", "adminConsentDescription": "user impersonation"}]}}
But from my pipeline, it looks like this:
{"api": "{\"oauth2PermissionScopes\":[{\"adminConsentDescription\":\"user", "impersonation\",\"adminConsentDisplayName\":\"user_impersonation\",\"id\":\"xxxxxx\",\"isEnabled\":\"true\",\"type\":\"User\",\"userConsentDescription\":\"user": "", "impersonation\",\"userConsentDisplayName\":\"user_impersonation\",\"value\":\"user_impersonation\"}]}": ""}
It is running in an AzureCLI@2 task on a windows-latest agent and the powershell version matches the one I'm running locally (7.6.2) as does the CLI version (2.67.0)
Anyone have any clue why the json is being handled differently and what I need to do to get it working in the pipeline?
Update:
I've been doing some more debugging today and have seen that the values for $updateJson and $escapedJson are identical in the pipeline and locally so I don't think that the double use of ConvertTo-Json is the problem. I have also checked and both the pipeline and my machine are using v0.1.3 of the authV2 extension, but clearly this is the thing that is behaving differently on the pipeline agents
Based on your description, I created the following YAML pipeline to conduct tests. Please note that the results obtained when executing the az ad app update
command using api=$updateJson
and api=$updateJson
in this pipeline are consistent with those observed when running the command in a local PowerShell Core environment.
pool:
vmImage: windows-latest
parameters:
- name: json
default: $escapedJson
values:
- $updateJson
- $escapedJson
variables:
system.debug: true
appId: xxxxx
steps:
- checkout: none
- task: AzureCLI@2
inputs:
azureSubscription: 'ARMSvcCnnWIFRootMG'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$appId = "$(appId)"
# get the API app reg details
$appRegApi = (az ad app show --id $appId --query 'api' | ConvertFrom-Json)
# check for scope
$scopes = $appRegApi.oauth2PermissionScopes
$scopeId = [guid]::NewGuid().Guid
$userImpersonationScope = [ordered]@{
adminConsentDescription = "user impersonation"
adminConsentDisplayName = "user_impersonation"
id = "$scopeId"
isEnabled = "true"
type = "User"
userConsentDescription = "user impersonation"
userConsentDisplayName = "user_impersonation"
value = "user_impersonation"
}
$update = @{
oauth2PermissionScopes = @($scopes; @($userImpersonationScope))
}
$updateJson = ConvertTo-Json $update -Depth 4 -Compress
$escapedJson = ConvertTo-Json $updateJson
Write-Host '================ Check $updateJson ================'
$updateJson
Write-Host '================ Check $escapedJson ================'
$escapedJson
Write-Host '================ Set api permission with ${{ parameters.json }} ================'
az ad app update --id $appId --set api=${{ parameters.json }} # --debug
As demonstrated in the provided images, the behavior is consistent in both the Azure DevOps pipeline and the local PowerShell Core environment. Therefore, the issue does not appear to be related to Azure Pipelines.
Additionally, as outlined in the document of Azure CLI ,
If the JSON value contains double quotes, you must escape them.
When working with JSON parameter values, consider using Azure CLI's
@<file>
convention and bypass the shell's interpretation mechanisms.