FinOps Guide
How to Find Underutilized and Orphaned Azure
Resources with Azure Advisor and Cost Management
Azure Advisor will find your unattached disks and oversized VMs, and it'll stop right there. It won't find the disk snapshot whose parent disk was deleted eighteen months ago, the empty resource group still accumulating charges, or the stopped VM whose "off" compute is quietly overshadowed by a disk that never stopped billing. Advisor is the first pass, not the whole audit — and knowing exactly where it stops looking is what actually finds the rest of the waste.
Every Azure subscription accumulates waste quietly, the same way every house accumulates clutter — not through one dramatic mistake, but through a hundred small, individually-reasonable decisions that never got cleaned up. A test VM spun up for a two-day experiment eight months ago. A disk left behind when its VM was deleted, because deleting the disk was a separate click nobody made. A public IP reserved for a project that got cancelled. None of these show up as an alarming line item — each one is a few dollars a month — but industry studies consistently put the aggregate at 25-35% of total cloud spend. Azure Advisor is the right place to start finding this waste, and it's also, provably, not the whole answer: it's explicitly described in Microsoft's own positioning as point-in-time and manual, and it has documented gaps in what it actually surfaces. This guide covers what Advisor catches, precisely what it misses, and the tools that close that gap.
Before diving into specific waste categories, it's worth being precise about what each tool is actually for — using only one, and expecting it to do the job of all three, is the most common reason orphan-hunting efforts stall out after the first easy pass.
| Tool | Answers | Limitation |
|---|---|---|
| Azure Advisor | What should I fix, based on common, well-understood waste patterns? | Point-in-time, manual action required, doesn't cover every orphan category |
| Cost Management + Billing | Where is spend going, and is anything trending unexpectedly? | Shows spend by resource/service/tag, but doesn't itself identify which specific resources are orphaned |
| Azure Resource Graph | Show me every resource matching this exact pattern, across the whole tenant | Requires knowing what pattern to query for — it's a search tool, not a curated recommendation engine |
The practical workflow this implies: use Advisor as the first, automated pass for the well-known patterns, use Cost Management to confirm dollar impact and catch spend anomalies that hint at something new going wrong, and use Resource Graph queries specifically for the categories Sections 3-4 identify as commonly missed by Advisor's curated recommendations.
Advisor scans resource configuration and usage telemetry across five categories (cost, security, reliability, performance, operational excellence), and its cost recommendations specifically cover a well-defined, genuinely useful set of common patterns.
| Recommendation type | What it identifies |
|---|---|
| Right-sizing / underutilized VMs | VMs oversized relative to actual CPU, memory, and network utilization over roughly 7-14 days |
| Unattached managed disks | Disks not currently attached to any VM but still incurring charges |
| Idle public IPs | Public IP addresses not associated with any active resource |
| Idle Load Balancers / Application Gateways | Resources provisioned but handling no meaningful traffic |
| Unused ExpressRoute circuits | Circuits provisioned but never actually connected |
| Reserved Instance / Savings Plan opportunities | Steady-usage resources that would benefit from a commitment discount |
| Reservations approaching expiry | Existing commitments nearing their term end, flagged for renewal decisions |
Each recommendation includes the specific affected resource, a description of the issue, estimated savings (typically annualized), and a recommended action — genuinely actionable, not vague guidance. For the categories it covers, Advisor is free, requires no setup, and should be the very first place anyone starts.
This is the point worth stating plainly, because most cost-optimization content treats Advisor as a complete solution: it isn't, and current guidance is explicit that Advisor "does not catch everything." The gap isn't a flaw in Advisor — it's a scope limitation, and knowing the specific shape of that gap is what determines whether an orphan-hunting effort actually finds all the waste.
| Category Advisor commonly misses | Why it's missed |
|---|---|
| Orphaned disk snapshots (parent disk deleted) | Not part of Advisor's curated pattern set — requires an explicit search for snapshots without an existing parent |
| Empty resource groups still accumulating minor charges | No single "wasteful" resource configuration to flag — the waste is structural, not resource-level |
| Stopped VMs with disks still attached and billing | The VM itself shows as stopped (not actively wasteful); the disk continuing to bill isn't always surfaced as connected to that stopped state |
| Idle NAT Gateways | Not part of Advisor's default curated recommendation set |
| Log Analytics workspaces over-retaining data | A configuration choice (default 90-day retention across all tables), not a "broken" resource Advisor's pattern matching flags |
| Idle SQL databases / App Service plans with zero real traffic | Requires correlating connection counts and request telemetry over a sustained period — narrower pattern than Advisor's default VM-focused checks |
A VM that's been stopped (not deallocated) — or even a properly deallocated VM whose disk was never cleaned up — stops incurring compute charges, but its attached managed disk keeps billing regardless of the VM's power state. This is a genuinely common, expensive misconception: teams "save money" by stopping a VM and assume the resource is now cost-neutral, when in reality the disk (often the larger cost component for anything beyond a small VM) is still accruing charges every single day the VM stays stopped rather than actually deleted or the disk detached and removed.
None of this is a case against using Advisor — it remains the correct first step, free and immediately actionable for the categories it covers. The correction is narrower and more useful than "don't trust Advisor": know specifically which categories fall outside its curated pattern set, and have a second tool (Resource Graph, covered in Section 5) ready to search for exactly those categories deliberately, rather than assuming a clean Advisor dashboard means a clean environment.
Current industry guidance consistently sorts Azure waste into five categories, and treating each by its specific detection signature — rather than hunting for "waste" generically — is what makes the search systematic rather than ad hoc.
| Resource type | Detection signature |
|---|---|
| Stopped VMs | Powered off for 30+ days with no scheduled restart — flag for owner confirmation and a decommission window |
| Unattached disks | No VM association at all — the cleanest, lowest-risk deletion candidate in the entire list |
| Idle SQL databases | Connection count and CPU utilization at or near zero for 30+ consecutive days |
| Idle App Service plans | No incoming requests, no scheduled jobs, no meaningful traffic over a sustained window |
| Orphan snapshots and backups | No parent resource exists — after an appropriate grace period to rule out an in-progress migration or recovery scenario |
| Unassociated public IPs | No attachment to a load balancer, VM, or gateway — pure, unambiguous waste |
Right-sizing and missed reservations both require judgment calls — is this VM's low utilization because it's oversized, or because it's a disaster recovery standby that needs to scale instantly during failover? Idle and orphan resources don't carry that ambiguity: a disk attached to nothing, a snapshot whose parent no longer exists, a public IP bound to nothing — these require essentially no architectural judgment, only confirmation that the resource genuinely has no active use. This is why they're consistently cited as the fastest, lowest-risk savings category to act on.
Azure Resource Graph lets you run KQL (Kusto Query Language) queries across every resource in a subscription, resource group, or entire tenant — exactly the tool for finding the specific categories Section 3 identified as commonly missed by Advisor's curated recommendations.
Beyond running these queries manually during a periodic review, Resource Graph queries can be scheduled via Azure Automation, Logic Apps, or a simple runbook to run on a recurring cadence and output results to a report or alert — moving orphan detection from "something we remember to check quarterly" to a genuinely automated, continuous process. This is the natural next step once the manual query patterns for your specific environment's common orphan types are established.
Finding an orphaned resource is only half the job — deleting it safely, in a way that doesn't turn a cost-optimization exercise into an accidental data-loss incident, is the other half, and it deserves an explicit process rather than ad hoc judgment calls.
| Resource type | Recommended safe-deletion pattern |
|---|---|
| Unattached disks | Snapshot to cheap (cool/archive) storage first, then delete the original disk — preserves recoverability at a fraction of the ongoing cost |
| Stopped VMs (30+ days) | Email the owner with a defined decommission window before deletion — confirm genuine abandonment, not a legitimate long-pause scenario |
| Orphan snapshots/backups | Apply a grace period after confirming no parent resource exists — rules out an in-progress migration or recovery scenario still in motion |
| Unassociated public IPs | Generally safe to delete immediately — genuinely lower risk than compute/storage resources, since no data is at stake |
Even for the lowest-risk categories, the recommended discipline is to surface confirmed candidates, route them to a named, accountable owner (which is exactly why the tagging practices from the broader FinOps guide matter here), and delete on a fixed, predictable cadence — not to delete immediately the moment a query identifies a candidate. This protects against the specific failure mode of an automated or hasty deletion catching a resource that looks orphaned in the data but has a legitimate reason to exist that isn't visible from configuration alone.
Orphan-hunting is not a one-time cleanup project — new orphaned resources accumulate continuously as teams provision, test, and forget, at roughly the same rate old ones get identified and removed if there's no ongoing review process.
- A short, regular Advisor review. Current guidance consistently recommends a brief, scheduled review — commonly cited as roughly 20 minutes weekly — treating Advisor as a living checklist rather than a one-time setup task.
- A monthly Resource Graph sweep for the categories Advisor misses. Run the queries from Section 5 (and any others specific to your environment's common orphan patterns) on a monthly cadence, since these categories don't surface automatically.
- Fixed decommission windows, not indefinite "review later" states. A stopped VM flagged for owner confirmation should have a defined window (a specific number of days) before automatic escalation or deletion — an indefinite "pending review" state is where orphan-hunting efforts quietly die.
Organizations that treat Advisor and orphan-hunting as a recurring, scheduled habit rather than an occasional cleanup effort are consistently reported to realize meaningfully more savings over a year than those checking quarterly — the mechanism is straightforward: waste identified and removed weekly never has months to accumulate, while quarterly reviews let three months of new orphans pile up between each check. The discipline of the cadence matters as much as the tooling used to execute it.
Start with Azure Advisor's cost recommendations tab
Review every current recommendation — right-sizing, unattached disks, idle public IPs, idle Load Balancers/App Gateways, unused ExpressRoute circuits, and reservation opportunities. This is the fastest, free first pass.
Filter and triage: act on the unambiguous, flag the judgment calls
Delete or resize the clear-cut candidates (unattached disks, unassociated public IPs) quickly. Route anything requiring business context (a VM at 15% utilization that might be a DR standby) to the resource owner for confirmation before acting.
Run Resource Graph queries for the categories Advisor doesn't cover
Search specifically for orphaned snapshots without a parent disk, empty resource groups, idle NAT Gateways, and stopped VMs with disks still attached — the categories Section 3 identified as commonly missed.
Cross-reference against Cost Management to confirm dollar impact and catch anomalies
Use Cost Management's spend trends and anomaly detection to verify the actual cost of flagged resources and to surface any unexpected spend spike that Advisor's pattern matching wouldn't have caught as a discrete recommendation.
Apply the safe-deletion discipline from Section 6 to every confirmed candidate
Snapshot disks before deleting, apply grace periods to orphan snapshots, and route stopped-VM candidates to owners with a defined decommission window — don't delete-on-sight even for high-confidence candidates.
Enforce tagging on everything that survives the cleanup
Every resource that remains should carry an owner and environment tag going forward — untagged resources are exactly how the next generation of orphans accumulates undetected.
Schedule the recurring cadence: weekly Advisor, monthly Resource Graph sweep
Put both reviews on a calendar with a named owner, not as an informal "we should check on this sometime" intention — the cadence is what prevents the cleanup from needing to be redone from scratch a year later.
Automate the Resource Graph queries once the manual patterns are established
Move the queries from Section 5 into a scheduled Azure Automation runbook or Logic App once you've confirmed they reliably surface genuine candidates in your environment, reducing the review to confirming automated output rather than running queries from scratch each time.
| Anti-pattern | Why it feels right | Why it isn't |
|---|---|---|
| Treating a clean Azure Advisor dashboard as proof the environment has no waste | "Advisor didn't flag anything else" | Advisor has documented gaps — orphaned snapshots, empty resource groups, idle NAT Gateways, and more require a separate Resource Graph search |
| Assuming a stopped VM has stopped costing money | "It's stopped, so it's not billing" | The attached disk keeps billing regardless of the VM's power state — often the larger cost component |
| Deleting flagged resources immediately without a grace period or owner confirmation | "The query confirmed it's orphaned, delete it" | Configuration data doesn't always capture legitimate reasons a resource exists — route to an owner and apply a grace period first |
| Treating orphan-hunting as a one-time cleanup project | "We did a big cleanup last quarter" | New orphans accumulate continuously as teams provision and forget — without a recurring cadence, waste rebuilds at roughly the same rate it was removed |
| Running Resource Graph queries manually every time instead of automating them | "It only takes a few minutes to run" | Manual processes are the first thing skipped under time pressure — automate the queries once the pattern is validated, so detection doesn't depend on someone remembering |
| Deleting unattached disks without snapshotting first | "It's not attached to anything, it's safe to remove" | A snapshot to cheap storage first preserves recoverability at minimal cost — deleting outright removes any safety margin for a mistaken orphan classification |
Key Takeaways
Frequently Asked Questions
Related FAVRITE Articles
- Azure Cost Optimization Best Practices: Monitor, Reduce, and Control Cloud Spend with FinOps
- Azure Reserved Instances and Azure Hybrid Benefit: How to Combine Savings and Lower VM Costs
- How to Design Azure Landing Zones: The Enterprise Architecture Blueprint
- 10 Battle-Tested Azure Policy Patterns for Governance at Scale