{"id":954,"date":"2020-04-30T19:47:47","date_gmt":"2020-05-01T02:47:47","guid":{"rendered":"http:\/\/blog.nillsf.com\/?p=954"},"modified":"2020-04-30T19:47:55","modified_gmt":"2020-05-01T02:47:55","slug":"using-azure-resource-graph-to-optimize-your-scripts","status":"publish","type":"post","link":"https:\/\/blog.nillsf.com\/index.php\/2020\/04\/30\/using-azure-resource-graph-to-optimize-your-scripts\/","title":{"rendered":"Using Azure Resource Graph to optimize your scripts"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Azure Resource Graph<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">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&#8217;t incur additional ARM throttles (the graph has it&#8217;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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"497\" height=\"153\" src=\"\/wp-content\/uploads\/2020\/04\/image-22.png\" alt=\"\" class=\"wp-image-955\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-22.png 497w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-22-300x92.png 300w\" sizes=\"auto, (max-width: 497px) 100vw, 497px\" \/><figcaption>Looking for resource graph shows you the resource graph explorer.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This will open the graph explorer. Here, you can write your queries and see the results.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"994\" height=\"389\" src=\"\/wp-content\/uploads\/2020\/04\/image-23.png\" alt=\"\" class=\"wp-image-956\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-23.png 994w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-23-300x117.png 300w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-23-768x301.png 768w\" sizes=\"auto, (max-width: 994px) 100vw, 994px\" \/><figcaption>The graph explorer in the portal<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">As a first query, we can get all resources and take just 10 out of them:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resources\n| take 10<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"638\" src=\"\/wp-content\/uploads\/2020\/04\/image-24-1024x638.png\" alt=\"\" class=\"wp-image-957\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-24-1024x638.png 1024w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-24-300x187.png 300w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-24-768x478.png 768w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-24.png 1333w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Taking top 10 out of the resources<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We can then make more interesting queries. Like counting the total amount of disks in a subscription:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resources\n| where type =~ 'Microsoft.Compute\/disks'\n| count<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"533\" height=\"400\" src=\"\/wp-content\/uploads\/2020\/04\/image-25.png\" alt=\"\" class=\"wp-image-958\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-25.png 533w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-25-300x225.png 300w\" sizes=\"auto, (max-width: 533px) 100vw, 533px\" \/><figcaption>Counting the amount of disks in my subscription<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">What interests me most, are the disks that aren&#8217;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. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resources\n| where type =~ 'Microsoft.Compute\/disks'\n| where isnull(parse_json(managedBy))<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Which will return unattached disks:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"792\" height=\"380\" src=\"\/wp-content\/uploads\/2020\/04\/image-26.png\" alt=\"\" class=\"wp-image-959\" srcset=\"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-26.png 792w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-26-300x144.png 300w, https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-26-768x368.png 768w\" sizes=\"auto, (max-width: 792px) 100vw, 792px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Which we can then use in a PowerShell script:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Editing PowerShell scripts to leverage Azure Resource Graph<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let me show you one of the scripts I run daily (using Azure Automation) to delete any unattached disks and NICs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#Get all ARM resources from all resource groups\n$rgs = Get-AzureRmResourceGroup \nforeach ($rg in $rgs){\n    $disks = get-azurermdisk -ResourceGroupName $rg.ResourceGroupName \n    foreach($disk in $disks){\n        if($null -eq $disk.ManagedBy){\n            Remove-AzureRmDisk -ResourceGroupName $rg.ResourceGroupName -DiskName $disk.name -asjob -Force\n            Start-Sleep -s 1\n        }\n    }\n    $nics = Get-AzureRmNetworkInterface -ResourceGroupName $rg.ResourceGroupName\n    foreach($nic in $nics){\n        Remove-AzureRmNetworkInterface -ResourceGroupName $rg.ResourceGroupName -Name $nic.name -force -AsJob\n        $nic.name\n        Start-Sleep -s 1\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see, this script loops over every resource group, and for every resource group loops over all disks and NICs. Another <em>sort of issue<\/em> 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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s first loop over the disks, which we can do using this way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$subid = \"d19dddf3-9520-4226-a313-ae8ee08675e5\"\n$query = \"resources | where type =~ 'Microsoft.Compute\/disks' | where isnull(parse_json(managedBy))\"\n$disks =  Search-AzGraph -Subscription $subid -Query $query\nforeach ($disk in $disks){\n    Remove-AzResource -ResourceId $disk.id -force\n    start-sleep 1\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We can do something very similar for the NICs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$query = \"resources | where type =~ 'Microsoft.Network\/networkInterfaces' | where isnull(parse_json(properties.virtualMachine ))\"\n$subid = \"d19dddf3-9520-4226-a313-ae8ee08675e5\"\n$nics=  Search-AzGraph -Subscription $subid -Query $query\nforeach ($nic in $nics){\n    Remove-AzResource -ResourceId $nic.id -force \n    start-sleep 1\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This will delete all NICs that are not attached to a VM. NICs don&#8217;t carry a cost, but since I tend to create\/delete VMs regularly, I prefer to have some automation clean up after me.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see, both parts of the script don&#8217;t query all resource groups and don&#8217;t loop over all resources. This has the benefit that the script will run faster, and I won&#8217;t trigger any throttles on the ARM API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">And that is the Azure Resource Graph. It&#8217;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.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What use cases do you have to use the Azure Resource Graph?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":958,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[2,4,41],"tags":[112,110,111],"class_list":["post-954","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-management","category-windows","tag-powershell","tag-resource-graph","tag-scripting"],"jetpack_featured_media_url":"https:\/\/nillsfblog.blob.core.windows.net\/media\/2020\/04\/image-25.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/954","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/comments?post=954"}],"version-history":[{"count":2,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/954\/revisions"}],"predecessor-version":[{"id":961,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/954\/revisions\/961"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/media\/958"}],"wp:attachment":[{"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/media?parent=954"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/categories?post=954"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.nillsf.com\/index.php\/wp-json\/wp\/v2\/tags?post=954"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}