Skip to content

Azure CLI Commands

References

JMES Query Syntax

By default, Azure CLI queries return JSON output. You can change the output format using the --output switch. Typical values are either 'table' or 'tsv'.

The query option can be used to filter the fields returned. Where a command returns a single row in table output, you can query by field name

az account show --query id

For commands returning more than one row or object, you need to use the 'flatten' operator in the query

az account list --query [].id -o table

To return multiple values in the output, specify these in a comma separated list:

az account list --query [].[id,name] -o table

You can rename the columns by specifying a dictionary instead of an array: note that the query is now in double-quotes:

az account list \
    --query "[].{Subscription:id,Name:name}" \
    -o table

You can also specify an index value to return a specific row: indexes begin at 0 for the first element:

az account list \
    --query "[1].{Subscription:id,Name:name}" \
    -o table

An array slice can also be used:

az account list \
    --query "[1:4].{Subscription:id,Name:name}" \
    -o table

The slice specification equates to: "return the element at index 1 and all elements up to, but not including, the element at index 4". Three elements (4 - 1) are returned

In addition to using array indexing, you can filter the results using filter expressions:

az account list \
    --query "[?name == 'mySubscription'].{Subscription:id,Name:name}" \
    -o table`

az account list \
    --query "[?contains(name, 'sub')].{Subscription:id,Name:name}" \
    -o table`

So far we've been selecting fields that return a scalar value. However some fields will be dictionaries: use the dot operator to select a single element from each dictionary:

az account list --query "[].[user.type]" -o table`

If the query returns a single row, you can use the tsv output format to assign the value to a variable or to directly use the value in a command:

SUB=$(az account list --query "[?contains(name, 'research')].[id]" -o tsv)
az account set --subscription $SUB

az account set --subscription $(az account list --query "[?contains(name, 'research')].[id]" -o tsv)

For multiple rows of single values, you can pipe the output to xargs, to perform the same command multiple times:

az group list --query "[?starts_with(name,'az104-03')].[name]" --output tsv | \
xargs -L1 bash -c 'az group delete --name $0 --no-wait --yes'

You can capture multiple values in an ENV variable and use a foreach loop to iterate:

VM_NAMES=$(az vm list --query [].[name] -o tsv)
for n in $VM_NAMES; do echo "on $n now"; done

Or you can capture the output in an array, by enclosing the rvalue in round brackets:

SUB=($(az account show --query [id, name] -o tsv))
echo "ID: ${SUB[0]}"
echo "Name: ${SUB[1]}"

Replace placeholder data in an environment variable:

JSON_DATA=$(cat somejsonfile.json)

# replace <name> with 'Example Text'
JSON_DATA=${JSON_DATA//<name>/Example Text}

REST API

The az rest command can be used to send queries directly to ARM:

CONF=$(az rest --method GET --url https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/xx-xxxxxxxxxx/providers/Microsoft.Network/virtualNetworks/xxx-xxxxxxxxxxx?api-version=2020-07-01)
echo $CONF
az rest --method PUT --body $CONF --url https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xx-xxxxxxxxxx/providers/Microsoft.Network/virtualNetworks/xxxx-xxxxxxxxxx?api-version=2020-07-01

Whilst the value for the url parameter should be possible to construct manually, you can also find the value in the 'Overview' pane for the resource in the Azure Portal, and switching to 'JSON View'. You can also find the value by logging-in to resources.azure.com and browsing to the resource.

Login

The az login command can be used to authenticate to Azure. Without any additional parameters, the command will attempt to launch a browser to complete an interactive logon. If no browser is available, then the command defaults back to the old-style device-code logon. Use the --use-device-code logon switch to force old-style device-code logon.

The --allow-no-subscriptions parameter can be used for tenant-level access. The --tenant option allows you to specify the tenant to logon to.

Compute

The --admin-username parameter of az vm create is used to specify a username for the VM: if not provided, then the username on your local machine is used. The --generate-ssh-keys will create id_rsa key pairs on the local and remote machines. If these already exist on the local machine they will be copied to the remote instead being created.

az vm image list can be used to get a list of VM images available. By default this will display the most popular images. Use the --all flag to get a complete list. You can also filter the results using --publisher, --sku, --offer flags. Use the --location filter to view offers that are available in the region you wish to deploy to.

Use az vm list-sizes --location $LOCATION -o table to list the available machine sizes for your region. If you don't specify the --size parameter in your az vm create command, Azure will select a default general-purpose size for you. If you wish to resize an existing VM, you can use the following command to check available sizes for cluster the VM is deployed to:

az vm list-vm-resize-options \
    --resource-group learn-6e62a4e5-3f38-4461-aa16-2a0149360363 \
    --name SampleVM \
    --output table

Once you have identified the desired VM size, run az vm resize to resize the VM.

Use az vm list-ip-addresses to list the IP Addresses associated to a VM.

az vm list will return information about all VMs in the current subscription. Use az vm show to get more detailed information about a specific VM.

az vm open-port --port $port_number to open a port on a running VM.

Check the power status of a VM:

az vm get-instance-view \
    --name $VM_NAME\
    --resource-group $RG_NAME \
    --query "instanceView.statuses[?starts_with(code, 'PowerState/')].displayStatus" -o tsv

Storage

Create a storage account and container

RESOURCE_GROUP_NAME={{ page.resgroup }}
LOCATION=uksouth
STORAGE_ACCOUNT_NAME={{ page.stgname }}
CONTAINER_NAME={{ page.containername }}

az group create --name $RESOURCE_GROUP_NAME --location $LOCATION

az storage account create \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS \
    --encryption-services blob

az storage container create \
    --name $CONTAINER_NAME \
    --account-name $STORAGE_ACCOUNT_NAME

Upload a file to blob storage:

az storage blob upload \
    --account-name $STORAGE_ACCOUNT_NAME \
    --container-name $CONTAINER_NAME \
    --file $FILE_NAME --name $CONTAINER_FILE

Upload a folder to blob storage:

az storage blob upload-batch \
    --destination $CONTAINER_NAME \
    --account-name $STORAGE_ACCOUNT_NAME \
    --destination-path $CONTAINER_FOLDER \
    --source $LOCAL_FOLDER

List Storage Account keys:

az storage account keys list --account-name $STORAGE_ACCOUNT_NAME`

Generate and capture SAS keys to access a storage container:

ACCOUNT_KEY=$(az storage account keys list \
    --resource-group $RESOURCE_GROUP_NAME \
    --account-name $STORAGE_ACCOUNT_NAME 
    --query '[0].value' -o tsv)

END_DATE=date -u -d "1 year" '+%Y-%m-%dT%H:%MZ'

SAS_KEY=$(az storage container generate-sas \
    -n $CONTAINER_NAME \
    --account-key $ACCOUNT_KEY \
    --account-name $STORAGE_ACCOUNT_NAME \
    --https-only \
    --permissions dlrw \
    --expiry $END_DATE -o tsv)

The 'azcopy' command can also be used to move data quickly into and out of Azure Storage Accounts. Logon to Azure:

azcopy login

Create a container:

azcopy make 'https://${STORAGE_ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}'

Copy a folder to the container (creates the data_folder folder in the target container):

azcopy copy '/data/data_folder' \
    'https://${STORAGE_ACCOUNT_NAME}.blob.core.windows.net/${CONTAINER_NAME}'

Deploying ARM Templates

Deploy infrastructure from an ARM Template:

RESOURCE_GROUP=$RESOURCE_GROUP_NAME
TEMPLATE_FILE=/path/to/template.json

az group deployment create \
    --name blanktemplate \
    --resource-group $RESOURCE_GROUP \
    --template-file $TEMPLATE_FILE

Sample Templates are available from the Azure Quickstart Repo

You can start with a blank template:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "functions": [],
    "variables": {},
    "resources": [],
    "outputs": {}
}

You can then add resources as you expand the deployment. For instance to add a storage account, add a storage account resource to the template:

"resources": [{
    "name": "learn132uksstorage",
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-04-01",
    "tags": {
        "displayName": "learn132uksstorage"
    },
    "location": "[resourceGroup().location]",
    "kind": "StorageV2",
    "sku": {
        "name": "Standard_LRS",
        "tier": "Standard"
    }
    "properties": {
        "supportsHttpsTrafficOnly": true
    }
}],

Then you can create a new deployment using:

templateFile="azuredeploy.json"
today=$(date +"%d-%b-%Y")
DeploymentName="addstorage-"$today

az deployment group create \
    --name $DeploymentName \
    --resource-group $RESOURCE_GROUP \
    --template-file $templateFile

You can make your template re-useable by using parameters instead of hard-coded values. For instance, to use a parameter to specify the Storage Account type, add the following parameter to the parameters section:

"parameters":{
    "storageAccountType": {
        "type": "string",
        "defaultValue": "Standard_LRS",
        "allowedValues": [
            "Standard_LRS",
            "Standard_GRS",
            "Standard_ZRS",
            "Premium_LRS"
        ],
        "metadata": {
            "description": "Storage Account type"
        }
    },
},

Then replace the hard-coded value for the Storage Account type:

"resources": [{
    "name": "learn132uksstorage",
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-04-01",
    "tags": {
        "displayName": "learn132uksstorage"
    },
    "location": "[resourceGroup().location]",
    "kind": "StorageV2",
    "sku": {
        "name": "[parameters('storageAccountType')]"
    }
    "properties": {
        "supportsHttpsTrafficOnly": true
    }
}],

When you deploy the template, you can give a value for the parameter, otherwise the default value is used:

templateFile="azuredeploy.json"
today=$(date +"%d-%b-%Y")
DeploymentName="use-stg-parameter-"$today

az deployment group create \
    --name $DeploymentName \
    --resource-group $RESOURCE_GROUP \
    --template-file $templateFile
    --parameters storageAccountType=Standard_LRS

Template deployments also allow you to specify outputs that will be returned after a successful deployment. The reference() function can be used to retrieve the runtime state of the resource:

"outputs": {
    "storageEndpoint": {
    "type": "object",
    "value": "[reference('learntemplatestorage123').primaryEndpoints]"
    }
}

We can also add a parameter for the Storage Account Name, and additionally specify allowed values for any of our parameters. A completed ARM template could now look something like this:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "storageName": {
            "type": "string",
            "minLength": 3,
            "maxLength": 24,
            "metadata": {
            "description": "The name of the Azure storage resource"
            }
        },
        // This is the allowed values for an Azure Storage account
        "storageSKU": {
            "type": "string",
            "defaultValue": "Standard_LRS",
            "allowedValues": [
                "Standard_LRS",
                "Standard_GRS",
                "Standard_RAGRS",
                "Standard_ZRS",
                "Premium_LRS",
                "Standard_GZRS",
                "Standard_RAGZRS"
            ],
            "metadata": {
                "description": "Allowed SKUs for Storage Accounts"
            }
        }
    },
    "functions": [],
    "variables": {},
    "resources": [{
        "name": "[parameters('storageName')]",
        "type": "Microsoft.Storage/storageAccounts",
        "apiVersion": "2021-04-01",
        "tags": {
            "displayName": "[parameters('storageName')]"
        },
        "location": "[resourceGroup().location]",
        "kind": "StorageV2",
        "sku": {
            "name": "[parameters('storageSKU')]",
            "tier": "Standard"
        }
    }],
    "outputs": {
        "storageEndpoint": {
            "type": "object",
            "value": "[reference(parameters('storageName')).primaryEndpoints]"
        }
    }
}

AAD

Get a list of users by Job Title:

az ad user list \
    --query "[?jobTitle=='Manager'].{ department: department, name: displayName, jobTitle: jobTitle, pname: userPrincipalName }" \
    --output table

List AD Groups by displayName:

az ad group list \
    --query "[?contains(displayName,'Education')].{ name: displayName }" \
    --output tsv

List members of the Education Department AD Group:

az ad group member list \
    --group "Education Department" \
    --query "[].{ name: displayName }" \
    --output tsv

Create a service principal with Contributor role on the specified subscription:

az ad sp create-for-rbac \
--scopes /subscriptions/$SUBSCRIPTION_ID \
--role Contributor --name $SP_NAME

Grant keyvault permissions to a service principal:

SP_OBJECT_ID=$(az ad sp list --display-name $SERVICE_PRINCIPAL --query [].objectId -o tsv)
az keyvault set-policy --name $KEYVAULT_NAME \
--secret-permissions get list --object-id $SP_OBJECT_ID

Key Vaults

Create a Key Vault and add a secret:

az keyvault create --name $KEYVAULT_NAME \
    --resource-group $RESOURCE_GROUP_NAME \
    --location $LOCATION --tags $TAG_VALUE

az keyvault secret set \
    --vault-name $KEYVAULT_NAME \
    --name client-id --value $SECRET_VALUE

Azure Load Balancer

Create a Load Balancer with a static front-end IP:

RG=my_resource_group
Public_IP=pip-lb-uksouth

az network public-ip create --resource-group $RG \
    --allocation-method Static --name $Public_IP

az network lb create --resource-group $RG \
    --name myLoadBalancer \
    --public-ip-address $Public_IP \
    --frontend-ip-name myFrontEndPool \
    --backend-pool-name myBackEndPool

Add a health probe and a distribution rule for http traffic:

az network lb probe create \
    --resource-group $RG \
    --lb-name myLoadBalancer \
    --name myHealthProbe \
    --protocol tcp \
    --port 80

az network lb rule create \
    --resource-group $RG \
    --lb-name myLoadBalancer \
    --name myHTTPRule \
    --protocol tcp \
    --frontend-port 80 \
    --backend-port 80 \
    --frontend-ip-name myFrontEndPool \
    --backend-pool-name myBackEndPool \
    --probe-name myHealthProbe

Connect two VMs to the Back-End pool:

az network nic ip-config update \
    --resource-group $RG \
    --nic-name webNic1 \
    --name ipconfig1 \
    --lb-name myLoadBalancer \
    --lb-address-pools myBackEndPool

az network nic ip-config update \
    --resource-group $RG \
    --nic-name webNic2 \
    --name ipconfig1 \
    --lb-name myLoadBalancer \
    --lb-address-pools myBackEndPool

Azure Monitor

Configure an alert for a VM when the CPU usage exceeds 80%:

RG=my_resource_group
VM=my_vm

VMID=$(az vm show \
        --resource-group $RG \
        --name $VM \
        --query id \
        --output tsv)

az monitor metrics alert create -n "Cpu80PercentAlert" \
    --resource-group $RG \
    --scopes $VMID \
    --condition "max percentage CPU > 80" \
    --description "Virtual machine is running at or greater than 80% CPU utilization" \
    --evaluation-frequency 1m \
    --window-size 10m \
    --severity 3

Configure Defaults

The az configure command can be used to set and unset default parameter values. To set a default resource group for each az command use:

az configure --defaults group=$RESOURCE_GROUP

To unset the default use:

az configure --defaults group=''

To list current defaults use:

az configure --list-defaults