Unattached managed disks in Azure
A disk that is not plugged into anything
Why it happens
Storage bills for the space it reserves, whether or not anything can reach it. These usually outlive the server they were built for.
A VM is deleted and its data disks are kept, or a disk is created for a migration that finished. Managed disks bill on provisioned capacity whether or not anything ever reads them.
Paste this into Resource Graph Explorer in the Azure portal.
resources
| where type =~ 'microsoft.compute/disks'
// Scope below matches CloudFinOpsPro policy DEFAULTS: exclusions.protectTag, environment.tagKeys,
// environment.allowedTagValues, and allowUntagged false so an untagged resource counts as production.
// If your policy.yaml differs, edit the three lines below or this will disagree with your own agent.
| where tolower(tostring(coalesce(tags['cfop:protect'], ''))) !in ('true', 'yes', '1')
| extend cfopEnv = tolower(trim(' ', tostring(coalesce(tags['Environment'], tags['environment'], tags['env'], ''))))
| where cfopEnv in ('dev', 'development', 'test', 'qa', 'sandbox', 'nonprod', 'non-prod', 'staging')
| where tostring(properties.diskState) =~ 'Unattached'
| where isempty(managedBy)
| extend ageDays = datetime_diff('day', now(), todatetime(properties.timeCreated))
| where ageDays >= 7
| project name, resourceGroup, location, ageDays,
sku = tostring(sku.name),
sizeGb = toint(properties.diskSizeGB)
| order by sizeGb descTwo filters here were missing and both change the set. The seven days is the rule's own minAgeDays default: a disk detached an hour ago is usually a migration in progress, so the agent waits a week and the previous version of this query did not, listing disks it would not touch. And managedBy sits BESIDE id rather than inside properties, which is the same mistake the detector itself once made; a disk can carry an owner while its state is not Attached, and the reference subscription has one in state Reserved whose managedBy names a live VM. Verified there: at seven days it returns the two genuinely idle disks, raising the window to thirty returns nothing, and inverting the managedBy test returns nothing, so both filters are doing work rather than sitting in the text. Snapshots are deliberately not mentioned: the rule collects them to price the saving from what the agent's own incremental snapshots really cost, which changes the figure and never the set.
Applies to microsoft.compute/disksWhat the agent does about it
A managed disk attached to nothing, billing its full provisioned size every month.
And what stops it
It has to see the same thing on three consecutive runs before it will act, it stays away from anything a person changed recently, and it will not touch a resource unless you tagged it non-production. Untagged counts as production. Every refusal is written down with the rule that caused it.
Related checks
Idle virtual machine
A running VM whose CPU and network have been near zero for the whole window.
Oversized virtual machine
A running VM whose sustained peak fits comfortably inside the next size down.
VM on an older series version
A VM running a v3 or v4 series where the same size on v5 costs the same or less.