VM Power Management
Commands
The runbook Azure Automation executes every hour, and the module commands behind it, with their syntax, parameters, permissions and examples. Generated from the module's own help, so this page and Get-Help cannot disagree.
The runbook
What Azure Automation runs every hour. It reads its settings from the automation variables, merges the schedule catalogue, asks the module for a plan and either reports it or performs it.
Schedules
Writing a schedule down, looking at what it will do, and storing it in the automation account. No redeployment involved.
New-VmPowerScheduleBuild a schedule from parameters instead of writing the JSON by handNeeds no permissionsShow-VmPowerScheduleCalendarPrint the next few days of a schedule, so a mistake is something you read rather than surviveNeeds no permissionsTest-VmPowerScheduleCheck a schedule or a whole catalogue, and report what is wrong rather than throwingNeeds no permissionsSet-VmPowerScheduleStore a schedule in the catalogue, without a redeploymentNeeds Microsoft.Automation/automationAccounts/variables/write and /read on the Automation AccountGet-VmPowerScheduleRead the schedule catalogue out of an Automation AccountNeeds Microsoft.Automation/automationAccounts/variables/read on the Automation AccountRemove-VmPowerScheduleTake a schedule out of the custom catalogueNeeds Microsoft.Automation/automationAccounts/variables/write and /read on the Automation Account
Deciding and acting
The plan is computed once and consumed once, so a dry run and an armed run cannot disagree about what would happen.
Get-VmPowerPlanWork out what should happen to the virtual machines in scope, and change nothingNeeds Reader on every subscription in scope, or at a management group above themInvoke-VmPowerPlanCarry out a plan, after the guards agree to itNeeds Microsoft.Compute/virtualMachines/deallocate/action and Microsoft.Compute/virtualMachines/read on every machine in scope, or their resource groups
What the output means
Every command returns one row per machine. Action is what the controller would do to it, Reason is the short name for why, and Explanation is that reason as a sentence. The names below are this module's own, not Azure's: Azure reports a power state and nothing about intent. The two tag names are defaults you can change.
Action
What would happen to the machine on an armed run. On a disarmed run the same decision is computed and nothing is performed.
| Value | What it means |
|---|---|
None | Nothing. Either no rule applies, or a guard held the machine back. |
Start | The machine would be started. |
Deallocate | The machine would be deallocated, which is what stops the compute charge. |
Reason
Twelve values, one per branch of the decision. The first four are about the expensive state that has nothing to do with schedules.
| Value | What it means |
|---|---|
StrandedButNotOnboarded | Switched off but still on a host, so still billed. It carries no PowerSchedule tag, so it is reported and not touched. These are the machines the read path is for. |
StoppedNotDeallocated | The same state, on a machine that does carry a tag. This one is deallocated. |
InTransition | Azure is already starting, stopping or deallocating it. Nothing acts on a machine mid-move. |
PowerStateUnknown | Resource Graph returned no power state. Not knowing is not a reason to act. |
Excluded | The machine carries the exclusion tag, so no rule applies to it. |
MatchesSchedule | It is already in the state its schedule wants at this time. |
ShouldBeStopped | Its schedule has it down at this time and it is running. |
ShouldBeRunning | Its schedule has wanted it up for a while and it is still deallocated, inside the schedule's start grace. |
DownSinceTheStartWindow | Its schedule wants it up, but the start was long enough ago that somebody turned this machine off on purpose. It is left alone. |
ScheduleStateUnknown | The schedule has no action in the lookback window, so there is nothing to compare against. |
ScheduleNotInCatalogue | The tag names a schedule that does not exist. A machine is not acted on by a rule nobody can read. |
NoRuleMatched | It carries no schedule and nothing else applies. |
The tags
Two tag names, both defaults. The module takes -ScheduleTag and -ExclusionTag, the deployment takes scheduleTag and exclusionTag, and the runbook reads whatever the deployment stored. Rename them if your estate already uses something else; the names below are what you get if you do not.
| Tag | What it means |
|---|---|
PowerSchedule | The value is the name of a schedule in the catalogue, for example office-hours-ch. A machine without this tag is never acted on by a schedule. A value naming a schedule that does not exist is reported as ScheduleNotInCatalogue, not guessed at. |
PowerSchedule-Exclude | Present on a machine, whatever the value, and nothing touches it. Reported as Excluded. This is the emergency brake for one machine, and it wins over every schedule. |
Armed and disarmed
The controller's one switch, stored as the Automation variable PM_Armed and false when the deployment lands.
| Value | What it means |
|---|---|
disarmed | The runbook discovers, decides, applies every guard and performs nothing. The job log and the workbook show what an armed run would have done. A blast radius set too low fails the job in week one rather than on the day you arm it. |
armed | The same code path without the dry run. Set PM_Armed to true in the Automation Account; no redeployment. |