How to query Azure resources using the Azure CLI
Published Mar 07 2019 12:01 AM 107K Views
Microsoft

TL/DR: The Azure CLI can be used to query data from Azure. For more information on how to use the Azure CLI query functionality, see the Azure CLI Query documentation.

 

The Azure CLI can be used to not only create, configure, and delete resources from Azure but to also query data from Azure. To do so, the Azure CLI uses the --query argument to run a JMESPath query against your Azure subscriptions. Querying Azure for resource properties can be quite helpful when writing scripts using the Azure CLI. For instance, you may want to get the IP address of an Azure Virtual Machine or Container Instance in order to perform some action on that resource.

 

This article includes a quick exercise that demonstrates several concepts with a final goal being to query a single resource property and storing the value of that property in a variable. This is demonstrated using Azure Container Instances (ACI). You do not need to have experience with ACI to complete the steps in this article, the concepts transfer to any Azure resource.

 

For quick access to the Azure CLI consider using the Azure Cloud Shell.

 

Create three Container Instances

 

Before digging into query syntax and operations, create a resource group using the az group create command and three container instances using the az container create command. The following bash script can be used to complete this.

 

# Create Resource Group
az group create --name myResourceGroup --location eastus

# Create three container instances
for ((i=0; i<3; ++i)); do az container create --resource-group myResourceGroup --name mycontainer$i --image microsoft/aci-helloworld --ip-address public; done

 

Output format

 

Before talking about the query command, lets discuss output format. By default, when any command is run using the Azure CLI, the output is returned JSON formatted. For example, run the az container list command. You should see that a JSON document is returned with the details of all container instances in your subscription.

 

$ az container list

 

While the JSON output is verbose, which is great, we may want to format the output a little more elegantly. We can do so by changing the output format. This article will focus on table and tsv format. For a complete list of Azure CLI output formats and a explanation of each, see Output format for Azure CLI commands.

 

Change the output type using the --output argument. In the following example the output type of table is used. You can see that while the output is not quite as verbose, it is easier to parse.

 

$ az container list --output table

Name          ResourceGroup    Status     Image                     IP:ports           Network    CPU/Memory       OsType    Location
------------  ---------------  ---------  ------------------------  -----------------  ---------  ---------------  --------  ----------
mycontainer0  myResourceGroup  Succeeded  microsoft/aci-helloworld  20.42.27.240:80    Public     1.0 core/1.5 gb  Linux     eastus
mycontainer1  myResourceGroup  Succeeded  microsoft/aci-helloworld  104.45.170.149:80  Public     1.0 core/1.5 gb  Linux     eastus
mycontainer2  myResourceGroup  Succeeded  microsoft/aci-helloworld  52.188.216.148:80  Public     1.0 core/1.5 gb  Linux     eastus

 

You can change the default output format for the CLI with the az configure command.

 

Azure CLI query

 

To start, lets return a single property of a single container instance using the az container show command. In the following example notice that the --query argument is called and that the name property is specified.

 

$ az container show -n mycontainer0 -g myResourceGroup --query name --output table

Result
------------
mycontainer0

 

This works great when returning a single result. If however we want to pull the names of all container instances using the az container list command, we need to use the JAMESPath flatten operator  [ ]. In this example note that the az container list command is using [].name for the query value, which returns the names of all container instances.

 

$ az container list --query [].name --output table

Result
------------
mycontainer0
mycontainer1
mycontainer2

 

If you wanted to return multiple properties, each of these can be comma delimited in square brackets.

 

$ az container list --query [].[name,location] --output table

Column1       Column2
------------  ---------
mycontainer0  eastus
mycontainer1  eastus
mycontainer2  eastus

 

To customize the column name we need to return a dictionary vs. an array using a JAMESPath multiSelect hash operator{ }. Returning a dictionary allows the property key to be set as the column label.

 

To achieve this, wrap the property selection in curly braces and name each property such as KeyValue:PropertyName. In the following example the key values are Name and Location.

 

$ az container list --query "[].{Name:name,Location:location}" --output table

Name          Location
------------  ----------
mycontainer0  eastus
mycontainer1  eastus
mycontainer2  eastus

 

Return value by index


Now let's say that you want to grab a specific object from an array by its index in that array. This can be done by specifying the index number in the square brackets. This can be helpful when looping through an array and performing an action on specific objects in that array. In the following example, the object at index 2 is returned.
 
$ az container list --query [2].name --output table

Result
------------
mycontainer2
 
You can also return a slice of indexes. In this example object 0 until 2 are returned. In this case 0 and 1 are returned.
 
$ az container list --query [0:2].name --output table

Result
------------
mycontainer0
mycontainer1
 

Filter results on a value

 

In many cases we want to filter an array based on a value. This can be done using a JMESPath filter expression. In the following example only the container instances with a name containing mycontainer2 is returned.

 

$ az container list --query "[?contains(name, 'mycontainer2')]" --output table

Name          Location    ProvisioningState    RestartPolicy    OsType    ResourceGroup
------------  ----------  -------------------  ---------------  --------  ---------------
mycontainer2  eastus      Succeeded            Always           Linux     myResourceGroup

 

Store single property in a variable

 

Now let's put some of these concepts in play and find a specific container instances IP address and place that IP address into a variable.

 

We will start by returning the IP address of a container instance with the name mycontainer2.

 

$ az container list --query "[?contains(name, 'mycontainer2')].[ipAddress.ip]" --output table

Column1
--------------
52.188.216.148

 

However we only want the IP address and do not need the table formatting nor header. Instead of using table output, use tabbed separated values, or tsv. This returns only the IP address.

 

$ az container list --query "[?contains(name, 'mycontainer2')].[ipAddress.ip]" --output tsv

52.188.216.148

 

Now update the command to place the results into a variable. The following example works in bash.

 

$ ip=$(az container list --query "[?contains(name, 'mycontainer2')].[ipAddress.ip]" --output tsv)

 

If using PowerShell, the command would look similar to this.

 

PS $ip = $(az container list --query "[?contains(name, 'mycontainer2')].[ipAddress.ip]" --output tsv)

 

At this point, if we were writing a script to say perform some action against the container instance, we could reference this variable when needing the IP address of the container instance.

11 Comments
Silver Contributor

I have a question about

--query [0:2].name 

 Would it also return the same container0 and 1 if you do [1:2]? Or is it just such format to always start with 0, but it returns only 2 values if 2 is the second number? But you said that it should return values from 0 through 2 and this would mean 0, 1, 2 (3 values, not two).

Microsoft

Oleg, thanks for the question. [0:2] returns two values, 0 through 2, so 0 and 1. So [1:2] would only return one item, mycontainer1 in the case of these examples.

 

I think the word 'through' may be subjective here. I will update the blog for clarity.

Hi Neil,

 

I think there is a better way when querying resources in your subscriptions - using Resource Graph, so you don't need to read via ARM resource providers and potentially hit the throttling limit in a large environment.

Microsoft

Thanks, Tao - for sure there are multiple ways to query resources. I have not used Resource Graph myself but know that it is very powerful and plan on taking some time to dig in.

 

Do you have an example where Resource Graph is used inside of script for populating values? For example, can I do something like this with Resource Graph? This creates a container instance, queries the IP address of that resource and stores it in a variable.

 

ip=$(az container create --name test555 --resource-group myResourceGroup --image microsoft/aci-helloworld --ip-address Public --query ipAddress.ip --output tsv)

 

Thanks a bunch for the comments.

Hi Neil,

I have few sample queries here: https://github.com/tyconsulting/ExpertsLiveUSA2019/blob/master/resourceGraph/DemoQuery.ps1

 

Resource Graph uses aliases just like Azure Policy definition. so as long as there is an alias referencing the resource type, you can query it. you can retrieve the list of aliases using REST API, PowerShell or Azure CLI: https://docs.microsoft.com/en-us/azure/governance/policy/concepts/definition-structure#aliases

 

cheers,

Tao

Copper Contributor

Hi , i like to know  if that work 

PS $ip = $(az container list --query "[?contains(name, 'mycontainer2')].[ipAddress.ip]" --output tsv) 

For the command :

PS $RepositoryTags = $(az acr repository show-tags --name $AzureRegistryName --repository $RepositoryName --orderby time_desc --query "[?contains(@,'prod')]" --output tsv).

 

Because it's presente the next error :

 

Delete of repository STPC: C:\Users\OscarDíaz\Desktop> "C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\\..\python.exe" -IBm azure.cli acr repository show-tags --name testodiaz --repository recreacionyturismo/eventos/content --query [?contains(@,'prod')] --output tsv
Checking for repository: recreacionyturismo/eventos/front
] was unexpected at this time. in azure CLI 

Microsoft

Useful tips and tricks, Thank you Neil :)

Iron Contributor

How would you filter by value using a variable? 

In your example, it will take the place of 'mycontainer2'

Thank you,
Pablo

Copper Contributor

Thank you! Very useful!

Brass Contributor

Hello Neil, I came across this thread which is really usefull nad made me understand more about querying. However, I visited your repo for graph samples and ran the az command

az graph query -q "where type =~ 'microsoft.storage/storageAccounts' and aliases['Microsoft.Storage/storageAccounts/networkAcls.defaultAction'] == 'Allow'" --output table

 

I got 4 errors as follows

{
"code": "BadRequest",
"message": "Please provide below info when asking for support: timestamp = 2023-12-28T12:39:27.0323159Z, correlationId = 71ee93dc-892a-4acd-a206-ad1909806d44.",
"details": [
{
"code": "InvalidQuery",
"message": "Query is invalid. Please refer to the documentation for the Azure Resource Graph service and fix the error before retrying."
},
{
"code": "Default",
"message": "Ensure that expression: aliases.[\"Microsoft.Storage/storageAccounts/networkAcls.defaultAction\"] is indeed a simple name"
},
{
"code": "Operator_FailedToResolveEntity",
"message": "'where' operator: Failed to resolve column or scalar expression named 'aliases.[\"Microsoft.Storage/storageAccounts/networkAcls.defaultAction\"]'"
},
{
"code": "Default",
"message": "Filter expression should be Boolean"
}
]
}

 

Can you help as I am new to this graph stuff? Thanks again

Brass Contributor

Also, Neil, can you please tell me is the following statement is valid


az resource list --query "[?servicePrincipalType=='Application']" --output table

when I run I get nothing in spite of the fact I have several application SP.

Thanks in aadvance

Version history
Last update:
‎Mar 23 2019 07:01 AM
Updated by: