Azure Resource Graph governance loop diagram showing discover, query, triage, remediate, and monitor stages.
Azure Resource Graph governance loop diagram showing discover, query, triage, remediate, and monitor stages.

Azure Resource Graph queries are one of the fastest ways to stop guessing what is happening across Azure. When the portal feels like a cupboard full of mystery cables, Resource Graph gives admins a searchable inventory, a drift detector, and a governance flashlight in one very useful box.

This guide gives you seven practical guardrail queries you can adapt today: orphaned resources, missing tags, exposed storage settings, Key Vault protection, policy compliance, and recent changes. No heroic spreadsheet archaeology required. The monkey approves. 🐒

Admin quick take

Azure Resource Graph turns cloud inventory into repeatable governance.

Use these queries as a starter pack for weekly reviews, incident triage, cost cleanup, and Azure Policy follow-up.

  • Best first move: run the inventory, tag, public IP, and unattached disk queries against a non-production subscription first.
  • Best automation move: save approved queries and schedule them through your reporting pipeline instead of treating them as one-off portal spelunking.
  • Watch-out: query results are only useful if somebody owns the remediation queue. Dashboards do not fix clouds. People with coffee fix clouds.
Azure Resource Graph governance loop diagram showing discover, query, triage, remediate, and monitor stages.
A practical Azure Resource Graph governance loop: discover, query, triage, remediate, monitor, repeat.

Why Azure Resource Graph queries belong in your admin toolkit

Microsoft describes Azure Resource Graph as a service for efficient, performant resource exploration across subscriptions and tenants. In normal-admin language: it lets you ask questions across Azure at scale without clicking through every subscription like it is 2014 and you have made questionable life choices.

Resource Graph uses a Kusto-style query language and includes tables for Azure resources, policy resources, advisor data, authorization resources, app service resources, and more. Microsoft also notes that Resource Graph can help assess policy impact and query recent resource property changes. That combination makes it especially useful for guardrails: recurring checks that catch drift before it turns into a ticket storm.

Admin problemWhy Resource Graph helpsTypical next step
“What do we actually have?”Query resources across subscriptions, management groups, or tenants.Build a weekly inventory snapshot.
“What changed?”Use Resource Graph change data to inspect recent resource changes at scale.Correlate changes with incidents or deployment windows.
“Are policies working?”Azure Policy compliance data can be queried through Resource Graph.Prioritize non-compliant resources by assignment or resource type.
“Where is the mess?”Find missing tags, orphaned resources, weak settings, and risky exposure patterns.Create remediation work items with owners.

Before you run these Azure Resource Graph queries

You can run Resource Graph from Azure Resource Graph Explorer in the Azure portal, Azure CLI with az graph query, Azure PowerShell with Search-AzGraph, or your own automation. Microsoft’s starter samples are a good way to validate that your tooling and permissions are ready.

Safe rollout checklist

  1. Scope intentionally. Start with one subscription or management group before querying the whole estate.
  2. Validate field names. Resource provider schemas vary. If a property is missing, inspect a sample resource and adjust the query.
  3. Decide ownership. Every recurring guardrail should have a remediation owner, not just a pretty chart.
  4. Pair with Azure Policy. Resource Graph finds the mess; Azure Policy can prevent some of it from coming back.
  5. Automate carefully. Start by reporting. Only remediate automatically after you have exceptions, approvals, and rollback paths.
Checklist card for Azure Resource Graph query guardrails across tags, orphaned resources, policy, and changes.
Use Resource Graph queries as a repeatable checklist, not a one-time portal safari.

1. Count resources by type and location

This is the boring query that becomes very interesting during audits, migrations, and “why did the bill jump?” conversations.

Resources
| summarize resourceCount = count() by type, location
| order by resourceCount desc

Use it for: inventory baselines, regional drift checks, migration planning, and “we have how many public IPs?” moments.

2. Find resources missing required tags

Tags are not glamorous, but they make cost allocation, ownership, support routing, and cleanup possible. Missing tags are usually a symptom of process drift.

Resources
| extend owner = tostring(tags.Owner), costCenter = tostring(tags.CostCenter), environment = tostring(tags.Environment)
| where isempty(owner) or isempty(costCenter) or isempty(environment)
| project name, type, resourceGroup, subscriptionId, location, owner, costCenter, environment
| order by type asc, name asc

Guardrail tip: use this query to clean up existing resources, then use Azure Policy to audit or require tags for new deployments. Otherwise you are mopping while the tap is still on.

3. Find unattached managed disks

Detached disks are a classic cost leak. Sometimes they are intentionally retained for recovery. Sometimes they are the cloud equivalent of a drawer full of mystery chargers.

Resources
| where type =~ 'microsoft.compute/disks'
| where isempty(managedBy)
| project name, resourceGroup, location, sku = tostring(sku.name), diskSizeGB = tostring(properties.diskSizeGB), timeCreated = todatetime(properties.timeCreated), id
| order by timeCreated asc

Do not delete blindly. Add age, owner, backup, and change-review checks before cleanup. A disk can be unattached and still important.

4. Find unassociated public IP addresses

Unassociated public IPs can create cost noise and exposure confusion. This query looks for public IP resources without an attached IP configuration.

Resources
| where type =~ 'microsoft.network/publicipaddresses'
| extend ipConfiguration = tostring(properties.ipConfiguration.id), allocationMethod = tostring(properties.publicIPAllocationMethod), ipSku = tostring(sku.name)
| where isempty(ipConfiguration)
| project name, resourceGroup, location, allocationMethod, ipSku, id
| order by resourceGroup asc, name asc

Admin note: review before removal. Some teams intentionally stage public IPs for disaster recovery, cutovers, or allow-list coordination. The query finds candidates, not verdicts.

5. Check Storage Accounts for public access and TLS posture

Storage settings deserve routine review because they sit close to data risk. This query surfaces public blob access configuration and minimum TLS version in one list.

Resources
| where type =~ 'microsoft.storage/storageaccounts'
| extend allowBlobPublicAccess = tostring(properties.allowBlobPublicAccess), minTlsVersion = tostring(properties.minimumTlsVersion), supportsHttpsOnly = tostring(properties.supportsHttpsTrafficOnly)
| project name, resourceGroup, location, allowBlobPublicAccess, minTlsVersion, supportsHttpsOnly, id
| order by allowBlobPublicAccess desc, minTlsVersion asc

Guardrail tip: treat results as a review queue. Some workloads may need specific settings, but exceptions should be documented. “Because Bob did it in 2021” is not documentation, even if Bob is lovely.

6. Review Key Vault purge protection

Key Vaults often protect secrets, keys, and certificates that production workloads depend on. Purge protection is a useful safety control, especially where accidental or malicious deletion would be painful.

Resources
| where type =~ 'microsoft.keyvault/vaults'
| extend purgeProtection = tostring(properties.enablePurgeProtection), softDeleteRetentionDays = tostring(properties.softDeleteRetentionInDays)
| project name, resourceGroup, location, purgeProtection, softDeleteRetentionDays, tenantId = tostring(properties.tenantId), id
| order by purgeProtection asc, name asc

Admin note: validate with your security and platform standards before changing Key Vault settings. Some controls affect recovery and lifecycle behavior, so this is not a “clicky-clicky before lunch” change.

7. Summarize Azure Policy compliance and recent changes

Resource Graph becomes much more powerful when you connect inventory with compliance and change history. Microsoft documents that Azure Policy compliance information can be accessed through Resource Graph, and that Resource Graph can query resource changes at scale.

PolicyResources
| where type =~ 'microsoft.policyinsights/policystates'
| extend complianceState = tostring(properties.complianceState), assignment = tostring(properties.policyAssignmentName), resourceType = tostring(properties.resourceType)
| summarize resources = count() by complianceState, assignment, resourceType
| order by complianceState asc, resources desc
resourcechanges
| extend changeTime = todatetime(properties.changeAttributes.timestamp), changedBy = tostring(properties.changeAttributes.changedBy), clientType = tostring(properties.changeAttributes.clientType), operation = tostring(properties.changeAttributes.operation), targetResourceId = tostring(properties.targetResourceId)
| where changeTime > ago(24h)
| project changeTime, operation, changedBy, clientType, targetResourceId
| order by changeTime desc

Use it for: post-incident timelines, deployment validation, policy remediation planning, and spotting high-risk manual changes. If production broke at 10:12 and a setting changed at 10:07, you now have a useful thread to pull.

Timeline visual showing Azure cloud drift detection and triage with Resource Graph.
Resource Graph change queries help turn “something drifted” into a timeline you can investigate.

How to turn these queries into real guardrails

The difference between a clever query and an operational guardrail is repetition. Run it on a cadence, route results to owners, track exceptions, and close the loop with policy or automation where it makes sense.

🔎

Report first

Start with read-only visibility so teams trust the findings.

📋

Assign owners

Every exception should have a team, ticket, or documented reason.

🛡️

Prevent repeat drift

Convert mature checks into Azure Policy, templates, or deployment guardrails.

If you are also tightening Microsoft 365 governance, the same pattern applies: find exposure, prioritize risk, assign ownership, and automate the boring parts. For related reads, see Restricted Content Discovery for SharePoint, Microsoft 365 Copilot watermarks, and the SharePoint agents governance checklist.

Bottom line

Azure Resource Graph queries are not just for inventory nerds, although inventory nerds are welcome here. They are practical operational guardrails for Azure admins who need fast answers across subscriptions: what exists, what changed, what is non-compliant, and what is quietly costing money. Start with the seven checks above, adapt them to your naming and policy standards, then automate the review cadence. Less portal wandering, more useful governance. That is the fun kind of boring.

Sources


Discover more from SharePoint Monkey

Subscribe to get the latest posts sent to your email.