Dev test resources left running

28 Sept 2026

Dev/test resources that run all weekend

Nobody provisions a test VM intending to pay for Saturday. It happens because Azure has no opinion about your working week: the meter runs on wall clock time, and the only thing that stops it is something you configured. A dev box that three people touch between 09:00 and 18:00, Monday to Friday, is useful for 40 hours and billed for 168.

168
Hours a week it bills
40
Hours a week anyone uses it
67%
Cut by one 08:00–19:00 schedule
0
Azure defaults that do it for you

An eleven-hour weekday window is 55 billed hours instead of 168 — a third of the bill, for a machine that is available every minute anyone was going to use it. That is the whole prize, and it takes an afternoon. Here is the order to do it in.

Before you start

"Off" is two different states in Azure and only one of them stops the compute charge. A developer who types shutdown -h now inside the guest gets the expensive one. Fix that first, or your schedule will produce a beautiful graph of machines that are switched off and still billing.

The state that keeps charging

Azure's power state table is blunt about it. Stopped — also written Stopped (Allocated), and reached "by invoking the PowerOff API operation or invoking shutdown from within the guest OS" — is billed. The VM is powered off and still holding its lease on a host, so you are still paying for the host. Only Deallocated releases that lease, and only Deallocated is free of the compute charge.

WHAT "OFF" MEANS TO THE METER Running Billed shutdown from inside the VM or the PowerOff API portal Stop, az vm deallocate, a shutdown schedule Stopped (Allocated) Lease still held — compute still billed Deallocated Lease released — compute not billed Disks and networking keep charging in both states.

This is why "we told everyone to shut down their test boxes" almost never shows up on the invoice. The instruction was followed and the state was wrong.

The five steps

1
Compare a Tuesday with a Saturday.

Don't start from a resource list, start from the shape of the spend. The Cost Management query API takes "granularity": "Daily" with a grouping by dimension, so one call per subscription gives you cost per resource per day. Anything whose weekend cost matches its weekday cost is running on a clock nobody set. Done when you have that list — not a list of dev resources, a list of dev resources with a flat seven-day line.

2
Audit the power states before you change anything.

The Virtual Machines List All API with statusOnly=true returns the power state of every VM in a subscription in one request. Every PowerState/stopped you find is a machine someone believes is off and is paying for. Done when that count is zero overnight — and it is worth re-running after the first scheduled shutdown, because a schedule that leaves machines in the wrong state is a schedule that saves nothing.

3
Set the schedule — and set the time zone.

Every Azure VM has an Auto-shutdown blade under Operations; from a script it is one line, az vm auto-shutdown -g rg -n vm --time 18:00, loopable over az vm list. The documented trap is in the note at the bottom of that page: UTC is the default time zone. Set it to 18:00 and forget the zone and half of Europe gets its machines back at 19:00 or 20:00 local. Done when every non-production VM has a schedule with an explicit zone.

4
Decide the opt-out before someone loses work.

A shutdown that kills a long build at 18:00 gets disabled by Friday. Both the VM blade and Azure DevTest Labs can notify 30 minutes ahead, by email or webhook, with links to skip this shutdown or delay it by one or two hours — the escape hatch that makes the policy survive. DevTest Labs adds a lab-wide policy with three settings: users can opt out, users can shift the time but not opt out, or users control nothing. Done when one of the three is chosen deliberately. Note that policy changes apply only to VMs created afterwards, so existing machines need the sweep anyway.

5
Sweep what a schedule can't reach.

Auto-shutdown is a VM feature. The rest of a dev environment has no off switch at all, and that is where the residue sits after the VMs go quiet. Done when the Cost tab in Advisor has no High-impact item you haven't triaged.

The half with no off switch

Azure Advisor already names most of it. These are all live entries in the cost recommendation reference, and each one describes a resource that survives every shutdown schedule you write:

Resource What Advisor flags Why it outlives the VM
Managed disk Disks not attached to a VM Deleting the VM leaves the disk behind; it bills the same deallocated or not
App Service plan Unused or empty plan The plan is the billable unit — it charges with zero apps on it
Virtual network gateway Gateways with no connections Hourly gateway charge plus the public IP, connected or not
ExpressRoute circuit Circuits stuck not-provisioned Created but never finished with the provider; carries no traffic, bills monthly
Data Explorer cluster Stopped for 60 days or more Stopped is not deleted — Advisor's cue that nobody is coming back
Virtual machine Right-size or shut down underutilised VMs High impact, and the one a schedule actually closes

Note what the first row implies for the honest version of the 67% figure: a deallocated VM still pays for its disks. The compute line goes to zero, the storage line does not. On a small dev box with a P10 disk that can be a meaningful slice of what's left — which is an argument for deleting the ones nobody has logged into since spring, not just scheduling them. The orphaned resource sweep is the same afternoon's work.

Why this comes before any discount

It is tempting to skip straight to a commitment, because the marketing number is bigger. It's the wrong order, and Microsoft's own guidance says so: right-size first, commit second. A reservation reduces the rate; a schedule reduces the hours. Buy a three-year reservation for a dev environment that idles 76% of the week and you have locked in a discount on waste for three years — the point where the reservation arithmetic stops helping you.

The weekday-versus-weekend comparison in step 1 is also the check that tells you it worked. Run it again a fortnight after the schedules go on: the flat lines should have grown a weekend notch, and the ones that didn't are the resources that were never VMs in the first place.

Sources
GraphPaaS

See which Azure resources bill exactly the same on Saturday as they do on Tuesday — across every tenant, not one portal tab at a time.

See your Azure spend →

Newsletter

Get the next article by email

Practical M365 & Azure cost pieces like this one. No spam, unsubscribe anytime.