Using Azure Resource Graph to optimize your scripts

I had to get some data out of a large Azure environment yesterday. What I needed was a quick way to get all machines of a certain size. Typically, I would have used Azure Powershell or Azure CLI to get this done. Create a loop over all resource groups, get all the resources in the resource group, and then just increment a counter.

There is a better to do this. Using the Azure Resource Graph, you can write queries to your Azure resources and get very quick results without the need to loop over resources. Using the Azure Resource Graph, you write queries in KQL, the same language as you use for Log Analytics and Azure Data Explorer.

Let me quickly introduce the Azure Resource Graph, and then also show you how you can use it from Azure PowerShell to optimize your scripts. The benefit of doing this would be that you do less Azure ARM queries, meaning you have less risk of being throttled.

What is Azure Resource Graph

The Azure Resource Graph is an Azure service that allows you to query resources using the KQL language cross-subscription. The graph lives outside of the ARM API, hence querying this graph doesn’t incur additional ARM throttles (the graph has it’s own throttles). The biggest benefit of using the resource graph is that you have the ability to query resources by all of their attributes, meaning for example machine sizes, disk types, status etc. and build complex queries.

The graph is available in the Azure portal, as well as through the Azure CLI and Azure PowerShell. Let me show you a quick demo of the resource graph in the portal. To see the graph explorer, you can look for resource graph in the Azure search bar.

Looking for resource graph shows you the resource graph explorer.

This will open the graph explorer. Here, you can write your queries and see the results.

The graph explorer in the portal

As a first query, we can get all resources and take just 10 out of them:

| take 10
Taking top 10 out of the resources

We can then make more interesting queries. Like counting the total amount of disks in a subscription:

| where type =~ 'Microsoft.Compute/disks'
| count
Counting the amount of disks in my subscription

What interests me most, are the disks that aren’t attached to a VM. The reason this is interesting, is that I have scripts that delete all these disks. Getting all those disks as a single query, will optimize my daily clean up scripts.

| where type =~ 'Microsoft.Compute/disks'
| where isnull(parse_json(managedBy))

Which will return unattached disks:

Which we can then use in a PowerShell script:

Editing PowerShell scripts to leverage Azure Resource Graph

Let me show you one of the scripts I run daily (using Azure Automation) to delete any unattached disks and NICs:

#Get all ARM resources from all resource groups
$rgs = Get-AzureRmResourceGroup 
foreach ($rg in $rgs){
    $disks = get-azurermdisk -ResourceGroupName $rg.ResourceGroupName 
    foreach($disk in $disks){
        if($null -eq $disk.ManagedBy){
            Remove-AzureRmDisk -ResourceGroupName $rg.ResourceGroupName -DiskName $ -asjob -Force
            Start-Sleep -s 1
    $nics = Get-AzureRmNetworkInterface -ResourceGroupName $rg.ResourceGroupName
    foreach($nic in $nics){
        Remove-AzureRmNetworkInterface -ResourceGroupName $rg.ResourceGroupName -Name $ -force -AsJob
        Start-Sleep -s 1

As you can see, this script loops over every resource group, and for every resource group loops over all disks and NICs. Another sort of issue with this script is that it is using the older AzureRM PowerShell, and this might be a good opportunity to update this to AZ PowerShell.

Let’s first loop over the disks, which we can do using this way:

$subid = "d19dddf3-9520-4226-a313-ae8ee08675e5"
$query = "resources | where type =~ 'Microsoft.Compute/disks' | where isnull(parse_json(managedBy))"
$disks =  Search-AzGraph -Subscription $subid -Query $query
foreach ($disk in $disks){
    Remove-AzResource -ResourceId $ -force
    start-sleep 1

As you can see in the script above, we are no longer looping over all resource groups and getting all the disks. We simply query for all disks that are not attached to a VM, and then loop over that small amount of disks and delete them. I do put a sleep in there, because I noticed in the past that sending too many deletes simultaneously can cause some errors.

We can do something very similar for the NICs:

$query = "resources | where type =~ 'Microsoft.Network/networkInterfaces' | where isnull(parse_json(properties.virtualMachine ))"
$subid = "d19dddf3-9520-4226-a313-ae8ee08675e5"
$nics=  Search-AzGraph -Subscription $subid -Query $query
foreach ($nic in $nics){
    Remove-AzResource -ResourceId $ -force 
    start-sleep 1

This will delete all NICs that are not attached to a VM. NICs don’t carry a cost, but since I tend to create/delete VMs regularly, I prefer to have some automation clean up after me.

As you can see, both parts of the script don’t query all resource groups and don’t loop over all resources. This has the benefit that the script will run faster, and I won’t trigger any throttles on the ARM API.


And that is the Azure Resource Graph. It’s useful to query all your resources and get a view on your environment. You can additionally use the resource graph to optimize some of your scripts to run faster and more optimally.

What use cases do you have to use the Azure Resource Graph?

Leave a Reply