Why use Resource Graph instead Az CLI/ PowerShell?
If we want to search for resources meeting certain criteria across all our subscriptions, we can’t use Az CLI or Az PowerShell to do this type of queries since it would require a lot of overhead to filter and switch between subscription contexts.
Pesudo-Code (not so performant)
Foreach subscription in subscriptions:
set Az Context
Get the VMs, Filter based on criteria
Resource Graph queries can help here, as they can be used to fetch metadata about the resource and then after their presence is validated, maybe perform some operation on it. With PowerShell we can even group these resources together based on SubscriptionID and then iterate over each subscription (set the right context) and perform actions.
Pesudo-Code (single query and performant)
Query Azure Graph for resources based on criteria across all the subscriptions
In this post, I share some of the Resource Graph Queries I have found useful while working with Virtual Machines.
Prerequisite
Prerequisite is the Az CLI (with graph extension) or Az.ResourceGraph PowerShell module which supports this.
# Install the Resource Graph module from PowerShell Gallery
Install-Module -Name Az.ResourceGraph
For Az CLI run the below to install the extension:
# Add the Resource Graph extension to the Azure CLI environment
az extension add --name resource-graph
Virtual Machine Queries
Below are list of queries for Virtual machines.
Find Virtual Machine with Name
If you want to find out if a virtual machine is present across all the subscriptions you have access to, you can use the below Resource graph query with Az CLI.
# Using Az.ResourceGraph Module
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and name == 'testvm01'"
Now for most of the queries in this post, you can do one to one translation to Az CLI commands by extracting the query and using it, I prefer to use PowerShell and that will be used in the rest of the examples.
# Using AZ CLI
az graph query -q "where type =~ 'Microsoft.Compute/VirtualMachines' and Name == 'testvm01'"
Find Virtual machines with name regex matching
Note - This regex matching can be applied to any resource or any property defined in the Resource schema as well.
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and name matches regex 'test-[0-9].*'"
Find Virtual machines with a specific tag
Gist is Kusto allows for filtering at all the levels, so we can filter based on a specific tag or can chain multiple tags to filter.
# Filter based on a tag called the department
# Note that tags are case-sensitive
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and tags.department =~ 'ITDepartment'"
# Filter based on the groupEmail name
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' | where tags.group =~ 'SRE'"
# Combine both the department & group
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' | where tags.group =~ 'SRE' or tags.department =~ 'ITDepartment'"
Find Virtual machines deployed using MarketPlace images
This query utilizes the fact that the publisher field for a market place will not be empty.
Note - Remove the end ‘limit’ command expression at the end of query if you need the exhaustive list.
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and isnotempty(properties.storageProfile.imageReference.publisher)| limit 1"
Find Virtual machines deployed using custom Images
This query utilizes the fact that the publisher field does not exist for a VM deployed using a generalized image.
Note - Remove the end ‘limit’ command expression at the end of query if you need the exhaustive list.
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and isempty(properties.storageProfile.imageReference.publisher)| limit 1"
Find Virtual machines which do not have a Tag populated
In this example the query checks for VMs which do not have a specific tag named Department created but not populated.
Note - Remove the end ‘limit’ command expression at the end of query if you need the exhaustive list.
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and isempty(tags.group)
| project name, location, resourceGroup, subscriptionId, Group=tags.group
| limit 5"
Find Virtual machine with an IPAddress
This can simply be done by doing a reverse lookup of the IPaddress but in some cases where the machines did not have these DNS records created it was a pain.
We start by looking for network interfaces which have this IP address
$nic = Search-AzGraph -Query "where type =~ 'Microsoft.Network/networkInterfaces' |
where properties.ipConfigurations[0].properties.privateIPAddress == '10.10.10.6'"
$nic.properties.virtualMachine.id # this is the resource ID of the VM
# Now we can fire off another query to get the VM info
Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and id == `'$($nic.properties.virtualMachine.id)`'"
Gather extra Virtual Machine information
To gather the relevant information for different VM resources e.g. network, storage, subscription etc, one can use PowerShell to extend the object returned from the resource graph query.
Below I show usage of a crude way of using PowerShell to do this e.g. using a filter.
Filter GetVMInfo {
$networkQuery = "where type =~ 'Microsoft.Network/networkInterfaces' and id == `'$($PSItem.properties.networkProfile.networkInterfaces[0].id)`'"
$network = Search-AzGraph -Query $networkQuery
[pscustomObject]@{
Name = $PSItem.name
Location = $PSItem.location
Tags = $PSItem.Tags
ResourceGroup = $PSItem.resourceGroup
SubscriptionID = $PSItem.subscriptionId
SubscriptionName = (Get-AzSubscription -SubscriptionId $PSItem.subscriptionId).Name
ProvisioningState = $PSItem.properties.provisioningState
VMSize = $PSItem.properties.hardwareProfile.vmSize
BaseOSImage = $PSItem.properties.storageProfile.imageReference.id.Split('/')[-1]
OSType = $PSItem.properties.storageProfile.osDisk.osType
OSDiskSize = $PSItem.properties.storageProfile.osDisk.diskSizeGB
DataDisks = foreach ($disk in $PSItem.properties.storageProfile.dataDisks) {
"Name = {0}, Size = {1}, IsManaged = $(if ($disk.managedDisk) { $true} else {$false})" -f $disk.name, $disk.diskSizeGB
}
IPAddress = $network.properties.ipConfigurations[0].properties.privateIPAddress
SubnetName = $network.properties.ipConfigurations[0].properties.subnet.id.Split('/')[-1]
DNSservers = @($network.properties.dnsSettings.dnsServers)
}
}
Use the above filter like below:
# Search for the VM first using the Az Resurce Graph
$VM = Search-AzGraph -Query "where type =~ 'Microsoft.Compute/VirtualMachines' and name == 'testvm01'"
# Pipe the object(s) found to the filter we defined
$VM | GetVMInfo
Conclusion
Azure Resource Graph is a powerful CMDB solution for querying Azure resources, they can be used wisely to enhance existing scripts or create new robust and scalable automations.