Subchapter 4.4
references/resource-graph.mdMarkdown3 KBView on GitHub
Azure Resource Graph (ARG) enables fast, cross-subscription resource querying through Azure Resource Manager MCP (ARM MCP). Use it to retrieve Azure Advisor recommendations and factual resource inventory for optimization analysis.
Use generate_query, validate_query, then execute_query. Never execute an
unvalidated query. Follow any skipToken returned by execute_query.
| Table | Contains |
|---|---|
Resources | All ARM resources (name, type, location, properties, tags) |
ResourceContainers | Subscriptions, resource groups, management groups |
AdvisorResources | Cost and performance recommendations |
Find orphaned (unattached) managed disks:
Resources
| where type =~ 'microsoft.compute/disks'
| where isempty(managedBy)
| project name, resourceGroup, location, diskSizeGb=properties.diskSizeGB, sku=sku.nameFind unattached public IP addresses:
Resources
| where type =~ 'microsoft.network/publicipaddresses'
| where isempty(properties.ipConfiguration)
| project name, resourceGroup, location, sku=sku.nameFind orphaned network interfaces:
Resources
| where type =~ 'microsoft.network/networkinterfaces'
| where isempty(properties.virtualMachine)
| project name, resourceGroup, locationResource count by SKU/tier (spot oversized resources):
Resources
| where isnotempty(sku.name)
| summarize count() by type, tostring(sku.name)
| order by count_ descTag coverage for cost allocation:
Resources
| extend hasCostCenter = isnotnull(tags['CostCenter'])
| summarize total=count(), tagged=countif(hasCostCenter) by type
| extend coverage=round(100.0 * tagged / total, 1)
| order by total descFind load balancers with no backend pools:
Resources
| where type =~ 'microsoft.network/loadbalancers'
| where array_length(properties.backendAddressPools) == 0
| project name, resourceGroup, location, sku=sku.nameAn empty backend-pool configuration is an investigation signal, not proof that the load balancer is unused or safe to remove.
Get Advisor cost recommendations:
AdvisorResources
| where subscriptionId =~ '{subscription-id}'
| where properties.category == 'Cost'
| extend resourceId=tostring(properties.resourceMetadata.resourceId)
| project subscriptionId,
name,
resourceId,
impact=properties.impact,
description=properties.shortDescription.solution,
savingsDetails=tostring(properties.extendedProperties)Replace the placeholder with the exact target subscription returned by Azure. Apply both the MCP subscription scope and the KQL subscription predicate before execution. Project only fields needed for the report. If duplicate or cross-scope rows remain, narrow or page the validated query; do not save and parse the response with a local tool.
Report savings, currency, and period only when those fields are present in
savingsDetails; otherwise label the recommendation qualitative.
=~ for case-insensitive type matching (resource types are lowercase)properties.fieldNamelimit clause to bound result count.query_costs results.