Azure waste

Capacity reservations with unused units

Reserved machine capacity with nothing running on it
The agent tells you how to fix 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 desc

Microsoft 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/capacityreservations
What 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.