As a Cloud Solutions Engineer, optimizing costs and automating operations is a daily priority. One of the common challenges in Azure is managing the runtime of virtual machines—especially those used for testing, development, or training purposes. While Microsoft offers tools like StopStartV2, they can feel heavy, brittle, or overly complex for certain environments.
In this post, I’ll walk you through my lightweight, tag-driven alternative: a two-part solution that combines an Azure Automation Runbook with a PowerShell-based GUI (PowerMate) to empower both administrators and end-users to control VM runtime efficiently and intuitively.
Contents
🚀 The Problem: Unused VMs = Wasted Costs
Many teams spin up VMs for specific use cases—but forget to shut them down. Running 24/7, these instances quietly incur unnecessary costs.
While Microsoft’s StopStartV2 attempts to solve this problem, it comes with a complex configuration and sometimes unpredictable behavior in large environments.
💡 The Solution: PowerManagement & PowerMate
I’ve built a two-part system:
- PowerManagement: An Azure Automation Runbook that auto-starts or deallocates VMs based on custom tags.
- PowerMate: A user-friendly PowerShell WPF GUI that allows users to skip shutdowns or manually deallocate their VM—without admin rights.
Let’s break them down.
🧠 Part 1: PowerManagement (Azure Runbook)
The core logic lives in an Azure Automation Account and is executed on a schedule using two time-based triggers:
- Morning (action=Start) → Starts all VMs
- Evening (action=Stop) → Deallocates them to reduce cost
It evaluates the following custom tags:
Tag | Description |
AutoShutdown-Exclude | If true, the VM is excluded from automation entirely |
AutoShutdown-SkipUntil | Temporarily excludes the VM until a future date |
AutoShutdown-ExcludeOn | Skips the shutdown for a specific date (e.g., today) |
AutoShutdown-Weekdays | Restricts shutdown/start only to specific weekdays |
🛠️ Execution of the script will automatically add all relevant tags with default values if they’re missing on the VM.
🔐 The runbook uses System-Assigned Managed Identity with a custom role granting only these permissions:
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/write",
"Microsoft.Network/networkInterfaces/join/action",
"Microsoft.Compute/disks/write",
"Microsoft.ManagedIdentity/userAssignedIdentities/assign/action",
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/deallocate/action"
This is a least privilege alternative to the broader RBAC scopes used in Microsoft’s tooling.
💻 Runbook Setup with Terraform or ARM
You can deploy the entire setup using one of two options:
1. Terraform
Full environment:
- Automation Account with Managed Identity
- Custom role & role assignment
- Runbook Upload
- Schedules (Start & Stop)
- additional: User Assigned Managed Identity for VMs with an custom role
- additional: VM example
2. ARM Template (minimal: Automation Account + Runbook + Schedules)
Minimal:
- Automation Account
- Custom role & role assignment
- Runbook Upload
- Schedules (Start & Stop)
🧑💻 Part 2: PowerMate (WPF GUI for Users)
For end users (e.g., developers, testers), I built PowerMate—a lightweight GUI written in PowerShell using WPF and optionally packaged via ps2exe.
🔍 Main features:
- Tag Status Overview: Displays current tag values set on the VM.
- Skip Today: Adds today’s date to AutoShutdown-ExcludeOn (to avoid auto-deallocation).
- Deallocate Now: Manually deallocates the VM to save cost instantly.
- Refresh: Reloads tag data.
- Clear Skip: Clears the ExcludeOn tag value.
Tag-based overview


Deallocation process


PowerMate uses Azure PowerShell module to authenticate with Managed Identity and query or update VM metadata. It can be:
- Copied to VMs via Azure Image/Custom Script,
- Executed as .ps1 or compiled .exe,
- Used by non-admins as long as permissions are properly scoped.
I compiled it for you with PS2EXE ready to use for you:

🔧 Architecture Overview
+---------------------+
| Azure Automation |
| Runbook Engine |
+----------+----------+
|
+-------------------------------+
| Checks tags, filters VMs, |
| executes Start/Stop actions |
+-------------------------------+
|
+--------------------+------------------+
| |
+------------+ +---------------+
| VM1 with Tags| ←←←←←←←←←←←←←←←←←←←←←| PowerMate |
+------------+ +---------------+
| AutoShutdown-... | Read/Write Tags
| | Manual Dealloc
+------------+ +---------------+
✅ Summary: Why This Is a Better Fit
Feature | StartStopV2 | PowerManagement + PowerMate |
Tag-Based Control | ✅ (complex) | ✅ (simple & extendable) |
Managed Identity | ✅ | ✅ (with custom RBAC) |
GUI for End Users | ❌ | ✅ (PowerMate WPF) |
Extensible Tags | ❌ (hardcoded) | ✅ (e.g., weekdays, skipUntil) |
Ease of Deployment | ✅ (ARM) | ✅ (ARM / Terraform) |
Open Source Customization | 🔒 | ✅ |
📦 Resources
- 🧠 PowerManagement Script: Link
- 🛠 Terraform Deployment: Folder
- 🧰 ARM Template: Link
- 🖥 PowerMate Source (PowerShell + WPF): Source & Folder
- 💬 Questions or Feedback? Reach out via LinkedIn or leave a comment!
✍️ Final Thoughts
This solution was born from necessity—balancing automation with user flexibility and clean cloud governance. With tags as the core control mechanism and a GUI for human override, this setup is simple to maintain, secure to run, and intuitive to use.
Let me know what you think or if you’d like to contribute or improve this project together!
📷 Screenshots





