Azure waste

VMs on the wrong SKU family for their workload

A server on the wrong type of machine
The agent reports this
Reversible
Why it happens

Some machine types cost more because they carry extra memory. If the work is not using that memory, you are paying for it anyway.

A memory-optimised E-series machine running a CPU-bound job pays a premium for RAM it never touches. A general purpose or compute optimised size at the same vCPU count is cheaper.

Paste this into Resource Graph Explorer in the Azure portal.

resources
| where type =~ 'microsoft.compute/virtualmachines'
// 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')
| extend size = tostring(properties.hardwareProfile.vmSize)
// E-series buys memory per vCPU. The check only proposes a move where it carries the
// D-series equivalent in its size ladder, so an E-series machine absent from this table
// is dropped rather than reported, however memory-heavy it looks.
| join kind=inner (
    datatable(size: string, proposedSize: string) [
    'Standard_E16s_v3', 'Standard_D16s_v3',
    'Standard_E16s_v5', 'Standard_D16s_v5',
    'Standard_E2s_v3', 'Standard_D2s_v3',
    'Standard_E2s_v5', 'Standard_D2s_v5',
    'Standard_E4s_v3', 'Standard_D4s_v3',
    'Standard_E4s_v5', 'Standard_D4s_v5',
    'Standard_E8s_v3', 'Standard_D8s_v3',
    'Standard_E8s_v5', 'Standard_D8s_v5'
    ]
  ) on size
| project name, resourceGroup, location, size, proposedSize
| order by size asc, name asc

E-series buys memory per vCPU, so a CPU-bound workload pays for memory it never uses; each row is a machine and the D-series size at the same vCPU count the agent would propose. The list is the agent's ladder rather than Azure's catalogue: an E-series machine not here, which includes everything above 16 vCPU such as Standard_E32s_v3, every non-s size such as Standard_E4_v3, and Standard_E8as_v4, is dropped by the check because it carries no D-series equivalent for that size yet. Ladder membership is the discriminator rather than AMD: Standard_E2as_v5 does resolve, to Standard_D2as_v5. Resource Graph holds no metrics, so this cannot apply the part that decides: the check additionally requires the CPU to have stayed under its threshold across the window, which is what makes a machine CPU-bound rather than merely E-series.

Applies to microsoft.compute/virtualmachines
What the agent does about it

A memory-optimised VM whose sustained CPU pressure suggests a cheaper general-purpose family at the same vCPU count would fit.

It will not fix this one

It reports this and takes no action. A check only earns the right to change something once the action behind it can re-read live state before it fires and knows the way back.