Simon Vedder

Cloud Engineer · Zürich

Invoke-AzureVMPowerManagementRunbook.ps1

Run AzureVMPowerManagement from an Azure Automation runbook

Required permissionsManaged identity with Reader for discovery, plus the custom role from deploy/main.bicep for the power actions, on the target scope.

Thin wrapper around the AzureVMPowerManagement module: signs in with the Automation Account’s managed identity, plans the work through the module and either reports it or performs it. The runbook knows the operation; the module knows the rules. Keep this file free of rules.

It ships disarmed. -Armed defaults to false, so a deployed schedule discovers, decides and prints everything while changing nothing. Read a week of that before arming it - see docs/decisions/0004-eager-to-start-reluctant-to-stop.md.

Disarmed is the same code path with -WhatIf on it, not a second one. Every guard is evaluated, so a blast radius set too low fails the job in week one rather than at the moment somebody arms it. A disarmed job that fails on “more than the N allowed” is the tool telling you the number is wrong while nothing is at stake.

Discovery reaches every subscription the managed identity can read in one Resource Graph call, so -SubscriptionId is a narrowing option rather than a requirement. All optional flags are [bool] instead of [switch] because the Automation “Start runbook” dialog cannot populate switch parameters.

Syntax

./Invoke-AzureVMPowerManagementRunbook.ps1 [[-SubscriptionId] <string[]>] [[-Armed] <bool>] [[-MaximumActions] <int>] [[-MinimumDwellMinutes] <int>] [[-IncludeUntagged] <bool>] [[-ScheduleCatalog] <string>] [[-ScheduleTag] <string>] [[-ExclusionTag] <string>] [[-ManagedIdentityClientId] <string>] [<CommonParameters>]

Requirements

PrerequisitesAzure Automation PowerShell 7.2+ runtime; modules AzureVMPowerManagement, Az.Accounts and Az.Compute.

Parameters

NameTypeRequiredPipelineDefaultDescription
-SubscriptionIdString[]nonoNarrow discovery to these subscriptions. Leave empty to plan across everything the identity reads.
-ArmedBooleannonoFalse, the default, plans and reports without touching a machine. True performs the plan.
-MaximumActionsInt32nono0Refuse the whole run if it would act on more machines than this. There is no safe default for somebody else’s estate: without this and without the Automation variable PM_MaximumActions, the run refuses rather than picking one.
-MinimumDwellMinutesInt32nono30Leave a machine alone if this runbook acted on it more recently than this. The memory lives in the Automation variable PM_LastActionAt, which this runbook writes at the end of an armed run - without it there is nothing to compare against and the guard cannot fire. Zero switches the check off. A schedule carrying its own minimumDwellMinutes can ask for longer, never shorter.
-IncludeUntaggedBooleannonoAlso act on machines carrying no schedule tag. Off by default: opt-in is the rule. Untagged machines that are powered off and still billed are reported either way.
-ScheduleCatalogStringnonoThe schedule catalogue as JSON. Empty reads PM_ScheduleCatalog and PM_ScheduleCatalogCustom from the Automation Account and merges them, custom winning on a name collision. No catalogue at all means only the stranded-machine rule applies, which is a complete and useful run on its own.
-ScheduleTagStringnonoTag key that opts a machine in. Empty uses the module’s default, PowerSchedule.
-ExclusionTagStringnonoTag key that protects a machine from every rule. Empty uses the module’s default.
-ManagedIdentityClientIdStringnonoClient ID of a user-assigned managed identity. Leave empty for the system-assigned identity.

Examples

Example 1

# What a deployed schedule does on day one: plan the whole estate, change nothing.
.\Invoke-AzureVMPowerManagementRunbook.ps1 -MaximumActions 50

Example 2

# Armed, limited to one subscription, refusing any run that would touch more than twenty machines.
.\Invoke-AzureVMPowerManagementRunbook.ps1 -SubscriptionId '00000000-0000-0000-0000-000000000000' -Armed $true -MaximumActions 20

Output

  • AzureVMPowerManagement.VmPowerPlan when disarmed, AzureVMPowerManagement.VmPowerPlanResult when armed, one per machine, plus a summary string.

Generated from the comment-based help in the module. Same text as Get-Help Invoke-AzureVMPowerManagementRunbook.ps1 -Full, and as the copy on GitHub.