Always use --output tsv when storing an az CLI value in a variable

To explain why to use the --output tsv, assume the example of assigning a role to a web app’s managed identity which fails with an error Cannot find user or service principal in graph database which looks like a permissions problem. The identity exists and the role name is right.

So what is the problem here?

The error

In the following az commands, I first capture the principal ID into a variable, then use it in a role assignment for a Cosmos DB:

principalId=$(az webapp identity assign \
  --resource-group <resource-group> \
  --name <web-app-name> \
  --query principalId)

az role assignment create \
  --assignee $principalId \
  --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.DocumentDB/databaseAccounts/<account-name>" \
  --role "Cosmos DB Account Reader Role"

The error thrown is:

Cannot find user or service principal in graph database for '"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"'.

The quoting is what matters in the ID-value '"aaaaaaaa-..."'. The single quotes belong to the error message, the double quotes inside them are part of the value. The CLI looked up a principal whose ID starts with a " character, and no such principal exists.

Why it happens

The Azure CLI defaults to json output. A query that returns a single string returns a quoted JSON string.

Command substitution does not strip those quotes — to the shell they are ordinary characters in the output. The variable ends up holding 38 characters instead of a GUID’s 36.

The fix

Ask for TSV output:

principalId=$(az webapp identity assign \
  --resource-group <resource-group> \
  --name <web-app-name> \
  --query principalId \
  --output tsv)

The role assignment then goes through with no error.

comments powered by Disqus