How to create scope using Azure CLI (az ad app) - azure

Using the Azure CLI 2.x, I cannot find a way to "add a Scope" under the expose an API section in Azure AD Portal.
What I do see is if I pass the --identifier-uris when the app is created, the APP ID URI and a Scope get automatically set:
`az ad app create --display-name "$appName" --identifier-uris "https://$tenantDomain/$appName" --reply-urls "$replyUrl" --oauth2-allow-implicit-flow true`
Not what I expected nor what I want
So, I removed --identifier-urls from the create command and added the scope I wanted in manually. then I see via manifest what I'm looking for under OAuth2Permissions as shown below. Can I put this in manifest.json with a new guid and insert it somehow?
What CLI command supports the explicit support to define a Scope?
Then Adding a Client application I would need to select the defined Scope, how is this referenced?
Documentation is very sparse, IMO. This reference is very helpful but nothing in here talks about adding scopes and clients. https://learn.microsoft.com/en-us/cli/azure/ad?view=azure-cli-latest. Any help towards samples or documentation much appreciated.

As of 7/29/22 the latest Azure CLI command "az ad app update" does not include the oauth2permissions anymore. If you try the above, you will bang you head and hopefully find this post. The new location of these permissions on the app regs are located at api.oauth2PermissionScopes as an array.
In order to get around this I used a combination of a few items from this post and had to get creative as the Azure docs are also still incorrect.
It still stands true that if you have an existing API exposed, you have to disable it to modify the scopes. If you have a fresh app registration you can apply this direct without issue. Hopefully this helps someone like me that has automations that are now broken due to the changes to how apps are registered and the manifest changes. If you don't know about changes to app registrations, I recommend you review. If you got this far though, I assume you already did.
# Add API Read Scope:
$scopeGUID = [guid]::NewGuid()
$scopeJSONHash = #{
adminConsentDescription="$apiName on $svrAppRegName"
adminConsentDisplayName="$apiName on $svrAppRegName"
id="$scopeGUID"
isEnabled=$true
type="User"
userConsentDescription="$apiName on $svrAppRegName"
userConsentDisplayName="$apiName on $svrAppRegName"
value="$apiName"
}
$azAppOID = (az ad app show --id $serverApplicationId | ConvertFrom-JSON).id
$accesstoken = (Get-AzAccessToken -Resource "https://graph.microsoft.com/").Token
$header = #{
'Content-Type' = 'application/json'
'Authorization' = 'Bearer ' + $accesstoken
}
$bodyAPIAccess = #{
'api' = #{
'oauth2PermissionScopes' = #($scopeJSONHash)
}
}|ConvertTo-Json -d 3
#You can try az rest, I used Invoke-RestMethod though.
#$graphURL="https://graph.microsoft.com/v1.0/applications/$azAppOID"
#az rest --method PATCH --uri $graphurl --headers $header --body $bodyAPIAccess
Invoke-RestMethod -Method Patch -Uri "https://graph.microsoft.com/v1.0/applications/$azAppOID" -Headers $header -Body $bodyAPIAccess

From this article Azure CLI: Create an Azure AD application for an API that exposes OAuth2 Permissions
You can use the az ad app update command (see documentation)
You can then set an application’s property by using the optional parameter –set
Create a oauth2-permissions.json containing the permission:
[
{
"adminConsentDescription": "Access CP Debug Desc",
"adminConsentDisplayName": "Access CP Debug",
"id": "85b8f1a0-0733-47dd-9af4-cb7221dbcb73",
"isEnabled": true,
"type": "Admin",
"userConsentDescription": null,
"userConsentDisplayName": null,
"value": "Access"
}
]
Run this script, it will create the app, disable the existing scope and add the new scope:
# Create the app registration
APP_REG=$(az ad app create --display-name myapi --identifier-uris https://myapi)
# Get the app id
APP_ID=$(echo $APP_REG | jq -r '.appId')
# disable default exposed scope
DEFAULT_SCOPE=$(az ad app show --id $APP_ID | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions')
az ad app update --id $APP_ID --set oauth2Permissions="$DEFAULT_SCOPE"
# Create new scopes from file 'oath2-permissions'
az ad app update --id $APP_ID --set oauth2Permissions=#oauth2-permissions.json

With help from the thread above, and a ton of trial-n-error plus a pretty useful link, I was able to work out the CLI script to add scope using a windows environment. PowerShell is not happy with 'jq' on windows and use of the back-tick had to be removed to get things working. Now I need to solve adding preAuthorizedApplication with the CLI.
$userAccessScopeApi = '{
"lang": null,
"origin": "Application",
"adminConsentDescription": "Access CP Debug desc",
"adminConsentDisplayName": "Access CP Debug",
"id": "--- replaced in scripts ---",
"isEnabled": true,
"type": "Admin",
"userConsentDescription": null,
"userConsentDisplayName": null,
"value": "Access"
}' | ConvertTo-Json | ConvertFrom-Json
`
Write-Host " - 1 read oauth2permissions"
#(az ad app show --id $appid)
$appjson = (az ad app list --display-name $appName)
$app = $appjson | ConvertFrom-Json
$oauth2Permissions = $app.oauth2Permissions
$oauth2Permissions[0].isEnabled = 'false'
$oauth2Permissionsjson = ConvertTo-Json -InputObject #($oauth2Permissions)
Write-Host " - 2 disable oauth2Permission in Azure App Registration"
$oauth2Permissionsjson | Out-File -FilePath .\oauth2Permissionsold.json
az ad app update --id $appId --set oauth2Permissions=#oauth2Permissionsold.json
Write-Host " - 3 delete the default oauth2Permission"
az ad app update --id $appId --set oauth2Permissions='[]'
Write-Host " - 4 add the new scope required add the new oauth2Permissions values"
$oauth2PermissionsApiNew = $userAccessScopeApi | ConvertFrom-Json
$oauth2PermissionsApiNew[0].id = New-Guid
$oauth2PermissionsApiNew = ConvertTo-Json -InputObject #($oauth2PermissionsApiNew)
# Write-Host "new oauth2permissions : " + $oauth2PermissionsApiNew"
$oauth2PermissionsApiNew | Out-File -FilePath .\oauth2Permissionsnew.json
az ad app update --id $appId --set oauth2Permissions=#oauth2Permissionsnew.json
Write-Host " - Updated scopes (oauth2Permissions) for App Registration: $appId"`

As A2AdminGuy mentioned, it is not possible to update the oauth2Permissions direct anymore, but you can still use az ad app update.
Execute the command az ad app show --id $appClientId and you will see that the oauth2PermissionScopes is inside the api now:
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"oauth2PermissionScopes": [],
"preAuthorizedApplications": [],
"requestedAccessTokenVersion": null
}
You need to update the api property to be able to set the oauth2PermissionScopes:
$apiScopeId = [guid]::NewGuid().Guid
$apiScopeJson = #{
requestedAccessTokenVersion = 2
oauth2PermissionScopes = #(
#{
adminConsentDescription = "$AppName on $EnvironmentAbbrev"
adminConsentDisplayName = "$AppName on $EnvironmentAbbrev"
id = "$apiScopeId"
isEnabled = $true
type = "User"
userConsentDescription = "$AppName on $EnvironmentAbbrev"
userConsentDisplayName = "$AppName on $EnvironmentAbbrev"
value = "authenticate"
}
)
} | ConvertTo-Json -d 4 -Compress
$apiUpdateBody = $apiScopeJson | ConvertTo-Json -d 4
az ad app update --id $apiClientId --set api=$apiUpdateBody --verbose
The --verbose parameter can be removed, but interestingly, the update command is a PATH request to the graph API.
Since it is a PATH request, you don't always need to send the whole api property, you can do two requests to update different properties and the previous one will not be affected.
This is how you can update a SPA redirectUris:
$appSpaJson = #{
redirectUris = #("http://localhost:3000")
} | ConvertTo-Json -d 3 -Compress
$appUpdateBody = $appSpaJson | ConvertTo-Json -d 4
az ad app update --id $appClientId --set spa=$appUpdateBody

Here's the approach I ended up with in bash on WSL Ubuntu, in the event it's useful for anyone else:
# replace all <value> blocks with your own value
# create app registration and extract appId
clientid=$(az ad app create \
--display-name <name> \
--query appId \
--output tsv)
# generate a UUID for the scope
uuid=$(uuidgen)
# set the API object as a JSON object
api=$(echo '{
"acceptMappedClaims": null,
"knownClientApplications": [],
"oauth2PermissionScopes": [{
"adminConsentDescription": "<description>",
"adminConsentDisplayName": "<name>",
"id": "'$uuid'",
"isEnabled": true,
"type": "User",
"userConsentDescription": "<description>",
"userConsentDisplayName": "<name>",
"value": "<value>"
}],
"preAuthorizedApplications": [],
"requestedAccessTokenVersion": 2
}' | jq .)
# Update app registration with App ID URL and api object
az ad app update \
--id $clientid \
--identifier-uris api://$clientid \
--set api="$api"

Related

Adding Scopes to Azure AD Application with Powershell (Expose an API)

I'd like to add a Scope to an Azure AD App / Service Principal (UI=Expose an API) with Powershell.
$app = New-MgApplication -DisplayName $name -SignInAudience "AzureADMyOrg"
Update-MgApplication -ApplicationId $app.id -IdentifierUris #("api://$($app.AppId)")
$oauth_permission_scopes = #{
AdminConsentDescription = "admin desc"
AdminConsentDisplayName = "admin name"
Type = "Admin"
Value = "Read.all"
Id = $([guid]::NewGuid())
}
$sp = New-MgServicePrincipal -AppId $app.AppId -Notes $description -Tags #("HideApp","WindowsAzureActiveDirectoryIntegratedApp") #HideApp=VisibleToUsers
Update-MgServicePrincipal -ServicePrincipalId $sp.Id -Oauth2PermissionScopes $oauth_permission_scopes
But i get the message:
Update-MgServicePrincipal_UpdateExpanded1: Property 'oauth2PermissionScopes' is read-only and cannot be set.
Can this only be added in the UI?!
I tried to reproduce the same in my environment and got below results:
I ran the same code as you to add scopes and got same error as below:
When I checked the same in Portal, application is created but scope not added like below:
To add scope to Azure AD Application with PowerShell (Expose an API), you need to modify your script as suggested by Cpt.Whale like this:
$api = #{
oauth2PermissionScopes = #(
#{
AdminConsentDescription = "admin desc"
AdminConsentDisplayName = "admin name"
Type = "Admin"
Value = "Read.all"
Id = $([guid]::NewGuid())
}
)
}
Update-MgApplication -ApplicationId $app.id -Api $api
Response:
When I checked the same in Portal, scope added successfully in Expose an API tab of Azure AD application as below:

How do I add a scope in AD B2C App Registration using AZ CLI

I am trying to create an app registration in Azure AD B2C. I need to add a scope using Azure CLI (which can be added by going to Expose a API blade in portal)
I can retrieve my app using
az rest --method GET --uri https://graph.microsoft.com/v1.0/applications/id
But when I run the following command
az ad app update --id 'id' --set api.oauth2PermissionScopes=#scopes.json
I get this error
Couldn't find 'api' in ''. Available options: []
Here is the scopes.json file
{
"api": {
"oauth2PermissionScopes": [
{
"type": "User",
"isEnabled": true,
"adminConsentDisplayName": "deafult",
"adminConsentDescription": "deafult",
"id": "73a43c0e-9a5e-4646-9d1e-c56a43279f99",
"value": "deafult",
"userConsentDisplayName": "deafult",
"userConsentDescription": "deafult"
}
]
}
}
Any suggestions would be much appreciated
I tried in my environment and got below results:
The latest Azure CLI command "az ad app update" does not include the oauth2permissions anymore.
I tried with below scripts and added scope successfully.
$AppId ="your application id"
$scopeGUID = [guid]::NewGuid()
$permission = #{
adminConsentDescription="admin only"
adminConsentDisplayName="readwrite"
id="$scopeGUID"
isEnabled=$true
type="User"
userConsentDescription="null"
userConsentDisplayName="null"
value="readwrite"
}
$azAppObjId = (az ad app show --id $AppId | ConvertFrom-JSON).id
$accesstoken = (Get-AzAccessToken -Resource "https://graph.microsoft.com/").Token
$header = #{
'Content-Type' = 'application/json'
'Authorization' = 'Bearer ' + $accesstoken
}
$bodyaccess = #{
'api' = #{
'oauth2PermissionScopes' = #($permission)
}
}|ConvertTo-Json -d 3
Invoke-RestMethod -Method Patch -Headers $header -Uri "https://graph.microsoft.com/v1.0/applications/$azAppObjId" -Body $bodyaccess
Powershell:
Portal:
Also checked with commands:
az ad app show --id < application id >
Output:
Reference:
Please refer the similar kind of SO-Thread which is resolved by A2AdminGuy.

Add Scope (oauth2Permissions) to Azure app registration using CLI [duplicate]

Using the Azure CLI 2.x, I cannot find a way to "add a Scope" under the expose an API section in Azure AD Portal.
What I do see is if I pass the --identifier-uris when the app is created, the APP ID URI and a Scope get automatically set:
`az ad app create --display-name "$appName" --identifier-uris "https://$tenantDomain/$appName" --reply-urls "$replyUrl" --oauth2-allow-implicit-flow true`
Not what I expected nor what I want
So, I removed --identifier-urls from the create command and added the scope I wanted in manually. then I see via manifest what I'm looking for under OAuth2Permissions as shown below. Can I put this in manifest.json with a new guid and insert it somehow?
What CLI command supports the explicit support to define a Scope?
Then Adding a Client application I would need to select the defined Scope, how is this referenced?
Documentation is very sparse, IMO. This reference is very helpful but nothing in here talks about adding scopes and clients. https://learn.microsoft.com/en-us/cli/azure/ad?view=azure-cli-latest. Any help towards samples or documentation much appreciated.
As of 7/29/22 the latest Azure CLI command "az ad app update" does not include the oauth2permissions anymore. If you try the above, you will bang you head and hopefully find this post. The new location of these permissions on the app regs are located at api.oauth2PermissionScopes as an array.
In order to get around this I used a combination of a few items from this post and had to get creative as the Azure docs are also still incorrect.
It still stands true that if you have an existing API exposed, you have to disable it to modify the scopes. If you have a fresh app registration you can apply this direct without issue. Hopefully this helps someone like me that has automations that are now broken due to the changes to how apps are registered and the manifest changes. If you don't know about changes to app registrations, I recommend you review. If you got this far though, I assume you already did.
# Add API Read Scope:
$scopeGUID = [guid]::NewGuid()
$scopeJSONHash = #{
adminConsentDescription="$apiName on $svrAppRegName"
adminConsentDisplayName="$apiName on $svrAppRegName"
id="$scopeGUID"
isEnabled=$true
type="User"
userConsentDescription="$apiName on $svrAppRegName"
userConsentDisplayName="$apiName on $svrAppRegName"
value="$apiName"
}
$azAppOID = (az ad app show --id $serverApplicationId | ConvertFrom-JSON).id
$accesstoken = (Get-AzAccessToken -Resource "https://graph.microsoft.com/").Token
$header = #{
'Content-Type' = 'application/json'
'Authorization' = 'Bearer ' + $accesstoken
}
$bodyAPIAccess = #{
'api' = #{
'oauth2PermissionScopes' = #($scopeJSONHash)
}
}|ConvertTo-Json -d 3
#You can try az rest, I used Invoke-RestMethod though.
#$graphURL="https://graph.microsoft.com/v1.0/applications/$azAppOID"
#az rest --method PATCH --uri $graphurl --headers $header --body $bodyAPIAccess
Invoke-RestMethod -Method Patch -Uri "https://graph.microsoft.com/v1.0/applications/$azAppOID" -Headers $header -Body $bodyAPIAccess
From this article Azure CLI: Create an Azure AD application for an API that exposes OAuth2 Permissions
You can use the az ad app update command (see documentation)
You can then set an application’s property by using the optional parameter –set
Create a oauth2-permissions.json containing the permission:
[
{
"adminConsentDescription": "Access CP Debug Desc",
"adminConsentDisplayName": "Access CP Debug",
"id": "85b8f1a0-0733-47dd-9af4-cb7221dbcb73",
"isEnabled": true,
"type": "Admin",
"userConsentDescription": null,
"userConsentDisplayName": null,
"value": "Access"
}
]
Run this script, it will create the app, disable the existing scope and add the new scope:
# Create the app registration
APP_REG=$(az ad app create --display-name myapi --identifier-uris https://myapi)
# Get the app id
APP_ID=$(echo $APP_REG | jq -r '.appId')
# disable default exposed scope
DEFAULT_SCOPE=$(az ad app show --id $APP_ID | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions')
az ad app update --id $APP_ID --set oauth2Permissions="$DEFAULT_SCOPE"
# Create new scopes from file 'oath2-permissions'
az ad app update --id $APP_ID --set oauth2Permissions=#oauth2-permissions.json
With help from the thread above, and a ton of trial-n-error plus a pretty useful link, I was able to work out the CLI script to add scope using a windows environment. PowerShell is not happy with 'jq' on windows and use of the back-tick had to be removed to get things working. Now I need to solve adding preAuthorizedApplication with the CLI.
$userAccessScopeApi = '{
"lang": null,
"origin": "Application",
"adminConsentDescription": "Access CP Debug desc",
"adminConsentDisplayName": "Access CP Debug",
"id": "--- replaced in scripts ---",
"isEnabled": true,
"type": "Admin",
"userConsentDescription": null,
"userConsentDisplayName": null,
"value": "Access"
}' | ConvertTo-Json | ConvertFrom-Json
`
Write-Host " - 1 read oauth2permissions"
#(az ad app show --id $appid)
$appjson = (az ad app list --display-name $appName)
$app = $appjson | ConvertFrom-Json
$oauth2Permissions = $app.oauth2Permissions
$oauth2Permissions[0].isEnabled = 'false'
$oauth2Permissionsjson = ConvertTo-Json -InputObject #($oauth2Permissions)
Write-Host " - 2 disable oauth2Permission in Azure App Registration"
$oauth2Permissionsjson | Out-File -FilePath .\oauth2Permissionsold.json
az ad app update --id $appId --set oauth2Permissions=#oauth2Permissionsold.json
Write-Host " - 3 delete the default oauth2Permission"
az ad app update --id $appId --set oauth2Permissions='[]'
Write-Host " - 4 add the new scope required add the new oauth2Permissions values"
$oauth2PermissionsApiNew = $userAccessScopeApi | ConvertFrom-Json
$oauth2PermissionsApiNew[0].id = New-Guid
$oauth2PermissionsApiNew = ConvertTo-Json -InputObject #($oauth2PermissionsApiNew)
# Write-Host "new oauth2permissions : " + $oauth2PermissionsApiNew"
$oauth2PermissionsApiNew | Out-File -FilePath .\oauth2Permissionsnew.json
az ad app update --id $appId --set oauth2Permissions=#oauth2Permissionsnew.json
Write-Host " - Updated scopes (oauth2Permissions) for App Registration: $appId"`
As A2AdminGuy mentioned, it is not possible to update the oauth2Permissions direct anymore, but you can still use az ad app update.
Execute the command az ad app show --id $appClientId and you will see that the oauth2PermissionScopes is inside the api now:
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"oauth2PermissionScopes": [],
"preAuthorizedApplications": [],
"requestedAccessTokenVersion": null
}
You need to update the api property to be able to set the oauth2PermissionScopes:
$apiScopeId = [guid]::NewGuid().Guid
$apiScopeJson = #{
requestedAccessTokenVersion = 2
oauth2PermissionScopes = #(
#{
adminConsentDescription = "$AppName on $EnvironmentAbbrev"
adminConsentDisplayName = "$AppName on $EnvironmentAbbrev"
id = "$apiScopeId"
isEnabled = $true
type = "User"
userConsentDescription = "$AppName on $EnvironmentAbbrev"
userConsentDisplayName = "$AppName on $EnvironmentAbbrev"
value = "authenticate"
}
)
} | ConvertTo-Json -d 4 -Compress
$apiUpdateBody = $apiScopeJson | ConvertTo-Json -d 4
az ad app update --id $apiClientId --set api=$apiUpdateBody --verbose
The --verbose parameter can be removed, but interestingly, the update command is a PATH request to the graph API.
Since it is a PATH request, you don't always need to send the whole api property, you can do two requests to update different properties and the previous one will not be affected.
This is how you can update a SPA redirectUris:
$appSpaJson = #{
redirectUris = #("http://localhost:3000")
} | ConvertTo-Json -d 3 -Compress
$appUpdateBody = $appSpaJson | ConvertTo-Json -d 4
az ad app update --id $appClientId --set spa=$appUpdateBody
Here's the approach I ended up with in bash on WSL Ubuntu, in the event it's useful for anyone else:
# replace all <value> blocks with your own value
# create app registration and extract appId
clientid=$(az ad app create \
--display-name <name> \
--query appId \
--output tsv)
# generate a UUID for the scope
uuid=$(uuidgen)
# set the API object as a JSON object
api=$(echo '{
"acceptMappedClaims": null,
"knownClientApplications": [],
"oauth2PermissionScopes": [{
"adminConsentDescription": "<description>",
"adminConsentDisplayName": "<name>",
"id": "'$uuid'",
"isEnabled": true,
"type": "User",
"userConsentDescription": "<description>",
"userConsentDisplayName": "<name>",
"value": "<value>"
}],
"preAuthorizedApplications": [],
"requestedAccessTokenVersion": 2
}' | jq .)
# Update app registration with App ID URL and api object
az ad app update \
--id $clientid \
--identifier-uris api://$clientid \
--set api="$api"

How to List App Services ( Webapp ) Runtimes?

I have a thousand app services in different subscriptions running on Microsoft Azure. I need to pull all the runtime version for each webapp.
I used this CLI Azure command to list the runtimes actually running in my subscriptions:
az webapp list-runtimes --subscription
But, I need to have the information for each webapp.
How can I do it?
This is more difficult than it should be given that not all properties are exposed by all CLI methods (or REST API calls), and some of the ones that are aren't populated. It is made even more complex by the fact that different properties are used for Windows and Linux hosts.
However it can be done using a combination of CLI commands. This PowerShell script will generate a JSON file for all the app services in a subscription, with their relevant runtimes and versions. Like this:
Script:
# Define a collection to hold the output
$runtimes = [System.Collections.Generic.List[object]]#()
# Get subscription id
Write-Progress "Fetching subscription id"
$sub = (az account show --query id -o tsv)
# Get all resource groups in the subscription
Write-Progress "Searching for resource groups"
$groups = (az group list --query "[].name" -o tsv)
# Set counter for group progress
$groupCounter = 1;
# Loop through each resource group to find all the web apps in it
foreach($group in $groups) {
# Find web apps in the specified group
Write-Progress "Searching for web apps in resource group $group" -PercentComplete (($groupCounter / $groups.Count) * 100)
$apps =(az webapp list -g $group --query "[?kind=='app' || kind=='app,linux'].name" -o tsv)
# Iterate the web apps
foreach($app in $apps) {
# Query the web app for versions
Write-Progress "Querying web app $app"
$appConfig = (az webapp show -n $app -g $group --query "{java:siteConfig.javaversion,netFramework:siteConfig.netFrameworkVersion,php:siteConfig.phpVersion,python:siteConfig.pythonVersion,linux:siteConfig.linuxFxVersion}") | ConvertFrom-Json
# Define an output object
$output = [PSCustomObject]#{
group = $group
name = $app
host = $null
runtime = $null
version = $null
}
# Determine which type of app service it is and get the values accordingly
if($appConfig.linux -eq "") {
# Windows platform
$output.host = "windows"
# Query the app config to get the metadata for the current stack
$uri = "https://management.azure.com/subscriptions/$sub/resourceGroups/$group/providers/Microsoft.Web/sites/$app/config/metadata/list?api-version=2020-10-01"
$output.runtime = (az rest --method post --uri $uri --query "properties.CURRENT_STACK" -o tsv)
# Determine the version of the relevant stack
$output.version = switch($output.runtime) {
"dotnet" {$appConfig.netFramework}
"dotnetcore" {$null}
"python" {$appConfig.python}
"php" {$appConfig.php}
"java" {$appConfig.java}
default {$null}
}
} else {
# Linux platform
$output.host = "linux"
# Split out the stack from the version
$output.runtime = $appConfig.linux.split("|")[0]
$output.version = $appConfig.linux.split("|")[1]
}
$runtimes.Add($output)
}
$groupCounter = $groupCounter + 1
}
# Convert the collection to JSON and write it out to a file
Write-Output $runtimes | ConvertTo-Json > "webapp-runtimes-$sub.json"
Output:
[
{
"group": "sample-group",
"name": "sample-ruby-app",
"host": "linux",
"runtime": "RUBY",
"version": "2.6"
},
{
"group": "php-group",
"name": "sample-php-app",
"host": "windows",
"runtime": "php",
"version": "7.3"
},
{
"group": "linux-apps",
"name": "sample-node-app",
"host": "linux",
"runtime": "NODE",
"version": "14-lts"
},
{
"group": "linux-apps",
"name": "sample-dotnetcore-app",
"host": "linux",
"runtime": "DOTNETCORE",
"version": "3.1"
}
]
Here is an example how to get runtime versions for each app services in multiple subscriptions:
Assuming that you have all the subscriptions within same account
Assuming that you have Windows WebApps
Code:
$subscriptions = az account list | ConvertFrom-Json
foreach ($s in $subscriptions) {
az account set -s $s.name
$webapps = az resource list --resource-type 'Microsoft.Web/sites' | ConvertFrom-Json
foreach ($w in $webapps) {
$config = az webapp config show --name $w.name --resource-group $w.resourcegroup | ConvertFrom-Json
$res = $config.name + ""
$res += $config.windowsFxVersion
$res >> file.txt
}
}

Why does certain Azure CLI commands require az login

In our VSTS release pipeline we want to call a powershell script that adds a function key for one of my Azure Functions (using the Key Management rest API).
I've created a script based on this article:
https://www.markheath.net/post/managing-azure-function-keys
Param(
[string] [Parameter(Mandatory=$true)] $ResourceGroup,
[string] [Parameter(Mandatory=$true)] $AppName,
[string] [Parameter(Mandatory=$true)] $FunctionName,
[string] [Parameter(Mandatory=$true)] $KeyName,
[string] [Parameter(Mandatory=$true)] $KeyValue
)
function getAuthenticationToken([string]$appName, [string]$resourceGroup)
{
$user = az webapp deployment list-publishing-profiles -n $appName -g $resourceGroup `
--query "[?publishMethod=='MSDeploy'].userName" -o tsv
$pass = az webapp deployment list-publishing-profiles -n $appName -g $resourceGroup `
--query "[?publishMethod=='MSDeploy'].userPWD" -o tsv
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$jwt = Invoke-RestMethod -Uri "https://$appName.scm.azurewebsites.net/api/functions/admin/token" -Headers #{Authorization=("Basic {0}" -f $encodedCreds)} -Method GET
return $jwt
}
function setFunctionKey([string]$appName, [string]$functionName, [string] $keyName, [string]$keyValue, [string]$jwt)
{
$body = (#{
"name" = $keyName
"value" = $keyValue
} | ConvertTo-Json)
#Setting the SecurityProtocol is a workaround for calling Azure APIs, I think?
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
try {
Invoke-RestMethod -Uri "https://$appName.azurewebsites.net/admin/functions/$functionName/keys/$keyName/" `
-Headers #{Authorization=("Bearer $jwt")} `
-Method PUT `
-ContentType "application/json" `
-Body $body
} catch {
$_.Exception | Format-List -Force
}
}
$jwt = getAuthenticationToken $AppName $ResourceGroup
setFunctionKey $AppName $FunctionName $KeyName $KeyValue $jwt
Write-Host "Specified key '$KeyName' has been added to $FunctionName"
Works locally, but when running it VSTS it gets and error when calling
$user = az webapp deployment list-publishing-profiles -n $appName -g $resourceGroup `
--query "[?publishMethod=='MSDeploy'].userName" -o tsv
with the message:
ERROR: Please run 'az login' to setup account.
We have other azure cli calls that works, ex: az cosmosdb database, so I guess our Service Principle connections are in place. What could be the issue here?
Seems like we had an old powershell version containing a bug that keeps the old service connection authentication context when you create a new service connection authentication, which I did in this case.
So we updated powershell on our build agents and we got things going!
From the document that you posted above, there is something you could miss.
The first step is that we need to get the credentials to call the Kudu
API. If you're authenticated with the Azure CLI, you can do that by
calling the az webapp deployment list-publishing-profiles command and
extracting the userName and userPWD for MSDeploy. You need to provide
the function app name and resource group name.
It seems that you should authenticate the Azure CLI before you use them.

Resources