How to List App Services ( Webapp ) Runtimes? - azure

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
}
}

Related

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"

Azure App Configuration - Conditionally create feature flag using bicep

I plan to use the Feature Management functionality within Azure App Configuration service.
Using bicep I create the configuration store.
Template: https://learn.microsoft.com/en-us/azure/templates/microsoft.appconfiguration/2021-10-01-preview/configurationstores?tabs=bicep.
Using bicep I add a feature flag.
Template: https://learn.microsoft.com/en-us/azure/templates/microsoft.appconfiguration/2021-10-01-preview/configurationstores/keyvalues?tabs=bicep.
The value should be initially set to false and once available it's up to the business/ops to change the value to true in the Azure Portal.
So I'm looking for a way to conditionally create the feature flag in my bicep; create the feature flag if it not exists. When it already exists, the bicep should skip creation because it could otherwise overwrite/reset the flag value changed by the business/ops.
I found this issue on GitHub from which I conclude that bicep does not yet support this requirement: https://github.com/Azure/bicep/issues/4023
Any suggestions for a workaround?
You can't really do that unless you check manually if the featureFlag exists before running the deployment.
ARM templates (and Bicep) try to be idempotent so if you apply the same template multiple times it will reset any manual changes.
Here is a bicep file that creates a config store and feature flag:
// main.bicep
param location string = resourceGroup().location
param configurationStoreName string
param featureFlagExists bool
param featureFlagName string
// Create the configuration store
resource configurationStore 'Microsoft.AppConfiguration/configurationStores#2021-10-01-preview' = {
name: configurationStoreName
location: location
sku: {
name: 'free'
}
properties: {
disableLocalAuth: false
enablePurgeProtection: false
encryption: {}
softDeleteRetentionInDays: 0
}
}
// Only create the feature flag if not exists
resource featureFlag 'Microsoft.AppConfiguration/configurationStores/keyValues#2021-10-01-preview' = if (!featureFlagExists) {
name: '.appconfig.featureflag~2F${featureFlagName}'
parent: configurationStore
properties: {
contentType: 'application/vnd.microsoft.appconfig.ff+json;charset=utf-8'
tags: {}
value: '{"id": "${featureFlagName}", "description": "", "enabled": false, "conditions": {"client_filters":[]}}'
}
}
And here is a sample powershell script that invoke it:
check if the config store exists
check if the feature flag exists
run the deployment
$resourceGroupName = "<resource group name>"
$configurationStoreName = "<config store name>"
$featureFlagName = "<feature flag name>"
# Check if the app configuration exists
$appConfigExists = (az appconfig list `
--resource-group $resourceGroupName `
--query "[?name=='$configurationStoreName'].id" `
| ConvertFrom-Json).Length -gt 0
# Check if the feature flag exists
$featureFlagExists = $false
if ($appConfigExists) {
$featureFlagExists = (az appconfig kv list `
--name $configurationStoreName `
--query "[?key=='.appconfig.featureflag/$featureFlagName'].key" `
| ConvertFrom-Json).Length -gt 0
}
az deployment group create `
--resource-group $resourceGroupName `
--template-file .\main.bicep `
--parameters `
configurationStoreName=$configurationStoreName `
featureFlagExists=$featureFlagExists `
featureFlagName=$featureFlagName

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

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"

Create a StorageV2 Storage account in an Azure resource management template

I'm attempting to create an ARM Template that includes creating a Storage account.
I want to create a StorageV2 (general purpose v2) account but this seems to fail because StorageV2 does not exist in the schema.
{
"name": "[variables('xblobstorageName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2016-01-01",
"sku": {
"name": "[parameters('xblobstorageType')]"
},
"dependsOn": [],
"tags": {
"displayName": "xblobstorage"
},
"kind": "StorageV2"
}
The only allowed values for kind are Storage and BlobStorage so when attempting to deploy the above template the following error is received:
"error": {
"code": "AccountPropertyIsInvalid",
"message": "Account property kind is invalid for the request."
}
Is it possible to create a V2 storage account using ARM Templates?
You have to update the apiVersion to 2018-02-01.
I wrote a PowerShell script to determine the latest API Version for a resource provider:
<#
.Synopsis
Gets the latest API version of a resource provider
.DESCRIPTION
The following cmdlet returns the latest API version for the specified resource provider.
You can also include pre-release (preview) versions using the -IncludePreview switch
.EXAMPLE
Using the Full Parameter Set:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts
.EXAMPLE
Using the Full Parameter Set with the -IncludePreview switch:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts -IncludePreview
.EXAMPLE
Using the ProviderAndType Parameter Set:
Get-AzureRmResourceProviderLatestApiVersion -ResourceProvider Microsoft.Storage -ResourceType storageAccounts
#>
function Get-AzureRmResourceProviderLatestApiVersion
{
[CmdletBinding()]
[Alias()]
[OutputType([string])]
Param
(
[Parameter(ParameterSetName = 'Full', Mandatory = $true, Position = 0)]
[string]$Type,
[Parameter(ParameterSetName = 'ProviderAndType', Mandatory = $true, Position = 0)]
[string]$ResourceProvider,
[Parameter(ParameterSetName = 'ProviderAndType', Mandatory = $true, Position = 1)]
[string]$ResourceType,
[switch]$IncludePreview
)
# retrieving the resource providers is time consuming therefore we store
# them in a script variable to accelerate subsequent requests.
if (-not $script:resourceProvider)
{
$script:resourceProvider = Get-AzureRmResourceProvider
}
if ($PSCmdlet.ParameterSetName -eq 'Full')
{
$ResourceProvider = ($Type -replace "\/.*")
$ResourceType = ($Type -replace ".*?\/(.+)", '$1')
}
$provider = $script:resourceProvider |
Where-Object {
$_.ProviderNamespace -eq $ResourceProvider -and
$_.ResourceTypes.ResourceTypeName -eq $ResourceType
}
if ($IncludePreview)
{
$provider.ResourceTypes.ApiVersions[0]
}
else
{
$provider.ResourceTypes.ApiVersions | Where-Object {
$_ -notmatch '-preview'
} | Select-Object -First 1
}
}
Usage:
Get-AzureRmResourceProviderLatestApiVersion -Type Microsoft.Storage/storageAccounts
And wrote a blog article about it:
Determine latest API version for a resource provider

Resources