Capacity reservations with unused units
Reserved machine capacity with nothing running on it
Why it happens
You asked Azure to hold capacity for a number of machines and are billed for all of them, whether or not you run them. The ones with no machine attached are paid for and idle.
A capacity reservation bills at the full pay-as-you-go rate of its VM size from the moment you create it, used or not. Reserve ten and attach six machines and you pay for ten.
Paste this into Resource Graph Explorer in the Azure portal.
resources
| where type =~ 'microsoft.compute/capacityreservationgroups/capacityreservations'
// 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')
// The agent REFUSES when virtualMachinesAssociated is absent, because a field that did not
// arrive and a reservation nobody uses look identical, and guessing reports every reservation
// as entirely wasted. This query does the same rather than defaulting the count to nothing.
| where isnotnull(properties.virtualMachinesAssociated)
| extend reservedUnits = toint(sku.capacity)
| extend machinesAttached = array_length(properties.virtualMachinesAssociated)
| where reservedUnits > 0
| extend unusedUnits = reservedUnits - machinesAttached
| where unusedUnits > 0
| project name, resourceGroup, location,
vmSize = tostring(sku.name),
reservedUnits,
machinesAttached,
unusedUnits
| order by unusedUnits descMicrosoft states the billing directly: reserve ten D2s_v3 and you are billed for ten even if the reservation is not used, and if you then attach six machines you see a bill for six VMs and four unused reservations, all at the same rate. The figure the agent quotes is a floor in two ways. A machine that is attached but deallocated is credited as consuming its unit, and the rate quoted is pay-as-you-go, so a savings plan or reserved instance covering these units makes the real cost lower.
Applies to microsoft.compute/capacityreservationgroups/capacityreservationsWhat the agent does about it
Reserved compute capacity that no virtual machine is using.
It will not fix this one
It finds it and tells you what to change. The change itself is yours to make, because it is not one the agent should make on your behalf.
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.
Unattached managed disk
A managed disk attached to nothing, billing its full provisioned size every month.