PowerShell Azure Automation: Manage Cloud Resources Fast
If you're still clicking through the Azure portal to spin up VMs, check resource costs, or start and stop services on a schedule, you're leaving hours of productivity on the table every week. PowerShell Azure automation through Microsoft's Az module gives you scriptable, repeatable control over your entire cloud environment — from a single terminal window.
In this guide, I'll walk you through six practical automation scenarios using the Az module, with working code blocks you can adapt immediately. Whether you're a sysadmin managing a corporate Azure tenant or a developer juggling multiple environments, these scripts will cut your manual cloud-ops time dramatically.
Prerequisites: Getting the Az Module Ready
Before writing a single line of automation, you need the Az PowerShell module installed and connected to your Azure tenant.
Install the Az Module
Open PowerShell 7 or Windows PowerShell as Administrator and run:
1# Install the Az module from the PowerShell Gallery2Install-Module -Name Az -Repository PSGallery -Force -AllowClobber34# Verify the installation5Get-Module -Name Az -ListAvailable | Select-Object Name, Version
Tip: Always use PowerShell 7+ (cross-platform) for new Azure automation work. It supports parallel processing features that PowerShell 5.1 does not.
Connect to Your Azure Account
1# Interactive login (browser pop-up)2Connect-AzAccount34# For automation/service principals (non-interactive)5$credentials = Get-Credential # or use a stored secret6Connect-AzAccount -ServicePrincipal -Credential $credentials -TenantId "your-tenant-id"78# Confirm the active subscription9Get-AzContext | Select-Object Name, Subscription, Tenant
If you manage multiple subscriptions, switch between them like this:
1# List all subscriptions2Get-AzSubscription | Select-Object Name, Id, State34# Set the active subscription5Set-AzContext -SubscriptionId "your-subscription-id"
Scenario 1: List and Filter Azure Resources
The first thing any Azure PowerShell automation script needs to do is enumerate resources. Here's how to query and filter your environment programmatically.
1# List all resource groups2Get-AzResourceGroup | Select-Object ResourceGroupName, Location, ProvisioningState34# List all resources in a specific resource group5Get-AzResource -ResourceGroupName "prod-rg" |6 Select-Object Name, ResourceType, Location |7 Sort-Object ResourceType89# Find all VMs across the entire subscription10Get-AzVM | Select-Object Name, ResourceGroupName, Location,11 @{N="Size"; E={$_.HardwareProfile.VmSize}},12 @{N="OS"; E={$_.StorageProfile.OsDisk.OsType}}1314# Filter resources by tag15Get-AzResource -Tag @{ Environment = "Production" } |16 Select-Object Name, ResourceType, ResourceGroupName
That last example is especially useful in enterprise environments where tagging policies are enforced — you can instantly pull every production resource across all resource groups.
Scenario 2: Start and Stop VMs on a Schedule
One of the highest-ROI uses of PowerShell Azure automation is automatically starting dev/test VMs in the morning and shutting them down at night. This alone can cut your Azure compute bill by 60–70% for non-production workloads.
1# Start a single VM2Start-AzVM -ResourceGroupName "dev-rg" -Name "dev-vm-01"34# Stop (deallocate) a single VM — "Stop" alone doesn't deallocate billing5Stop-AzVM -ResourceGroupName "dev-rg" -Name "dev-vm-01" -Force67# Start ALL VMs in a resource group in parallel8$vms = Get-AzVM -ResourceGroupName "dev-rg"9$vms | ForEach-Object -Parallel {10 Start-AzVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name11} -ThrottleLimit 51213# Stop all running VMs across the subscription (use with care!)14Get-AzVM -Status |15 Where-Object { $_.PowerState -eq "VM running" } |16 ForEach-Object {17 Write-Host "Stopping $($_.Name)..."18 Stop-AzVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force -NoWait19 }
Combine this with PowerShell Task Scheduler to create a cron-style schedule on your local machine, or deploy it as an Azure Automation runbook (covered in Scenario 6).
Scenario 3: Create and Manage Resource Groups
Spinning up new environments — dev, staging, QA — manually through the portal is slow and error-prone. Automate it:
1# Create a new resource group with tags2New-AzResourceGroup -Name "staging-rg" -Location "eastus" -Tag @{3 Environment = "Staging"4 Owner = "DevTeam"5 CostCenter = "IT-001"6 CreatedDate = (Get-Date -Format "yyyy-MM-dd")7}89# Copy tags from one resource group to all its resources10$rg = Get-AzResourceGroup -Name "staging-rg"11$rgTags = $rg.Tags12Get-AzResource -ResourceGroupName "staging-rg" | ForEach-Object {13 Update-AzTag -ResourceId $_.Id -Tag $rgTags -Operation Merge14}1516# Remove a resource group (and everything in it — be careful!)17Remove-AzResourceGroup -Name "old-temp-rg" -Force -AsJob
The -AsJob flag on the remove command lets PowerShell run the deletion in the background so your terminal isn't blocked.
Scenario 4: Deploy ARM Templates via PowerShell
Deploying infrastructure-as-code through ARM (Azure Resource Manager) templates is the enterprise-standard approach. PowerShell makes this scriptable and repeatable.
1# Deploy an ARM template from a local file2New-AzResourceGroupDeployment `3 -ResourceGroupName "prod-rg" `4 -TemplateFile "./templates/storage-account.json" `5 -TemplateParameterFile "./templates/storage-account.params.json" `6 -DeploymentName "storage-deploy-$(Get-Date -Format 'yyyyMMdd-HHmm')" `7 -Verbose89# Deploy a Bicep template (Az module supports Bicep natively)10New-AzResourceGroupDeployment `11 -ResourceGroupName "prod-rg" `12 -TemplateFile "./infra/main.bicep" `13 -environment "production" `14 -location "eastus"1516# Validate a template before deploying (dry-run)17Test-AzResourceGroupDeployment `18 -ResourceGroupName "prod-rg" `19 -TemplateFile "./templates/storage-account.json" `20 -TemplateParameterFile "./templates/storage-account.params.json"
Always run Test-AzResourceGroupDeployment before production deployments — it validates template syntax and parameter values without making any changes.
Scenario 5: Automate Cost Reporting
Azure cost management is painful in the portal. Pulling cost data directly into PowerShell lets you build automated weekly reports, budget alerts, and cost-by-tag breakdowns.
1# Get current month's cost for a subscription2$context = Get-AzContext3$subId = $context.Subscription.Id4$startDate = (Get-Date -Day 1).ToString("yyyy-MM-dd")5$endDate = (Get-Date).ToString("yyyy-MM-dd")67$costData = Get-AzConsumptionUsageDetail `8 -StartDate $startDate `9 -EndDate $endDate `10 -IncludeMeterDetails1112# Summarize cost by resource group13$costData |14 Group-Object -Property ResourceGroup |15 Select-Object Name,16 @{N="TotalCostUSD"; E={ ($_.Group | Measure-Object -Property PretaxCost -Sum).Sum }} |17 Sort-Object TotalCostUSD -Descending |18 Format-Table -AutoSize1920# Export cost report to CSV21$costData |22 Select-Object InstanceName, ResourceGroup, ConsumedService,23 UsageStart, UsageEnd, PretaxCost, Currency |24 Export-Csv -Path ".\azure-cost-report-$(Get-Date -Format 'yyyy-MM').csv" -NoTypeInformation2526Write-Host "Cost report exported successfully."
Schedule this script monthly with Task Scheduler and email it to your finance team automatically — no portal access required.
Scenario 6: Setting Up Azure Automation Runbooks
For cloud-native scheduling without needing an on-premises machine, Azure Automation runbooks let you run PowerShell scripts on Microsoft's infrastructure on any schedule.
1# Create an Automation Account2New-AzAutomationAccount `3 -ResourceGroupName "automation-rg" `4 -Name "corp-automation-acct" `5 -Location "eastus" `6 -Plan "Basic"78# Import a runbook script from a local file9Import-AzAutomationRunbook `10 -ResourceGroupName "automation-rg" `11 -AutomationAccountName "corp-automation-acct" `12 -Path ".\runbooks\stop-dev-vms.ps1" `13 -Name "Stop-DevVMs" `14 -Type "PowerShell" `15 -Published1617# Create a schedule (run at 7 PM every weekday — Mon through Fri)18$scheduleParams = @{19 ResourceGroupName = "automation-rg"20 AutomationAccountName = "corp-automation-acct"21 Name = "Weekday-7PM"22 StartTime = (Get-Date "19:00:00")23 WeekInterval = 124 DaysOfWeek = @("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")25 TimeZone = "Eastern Standard Time"26}27New-AzAutomationSchedule @scheduleParams2829# Link the runbook to the schedule30Register-AzAutomationScheduledRunbook `31 -ResourceGroupName "automation-rg" `32 -AutomationAccountName "corp-automation-acct" `33 -RunbookName "Stop-DevVMs" `34 -ScheduleName "Weekday-7PM"
Once deployed, this runbook runs entirely within Azure — no local machine, no Task Scheduler, no VPN required. This is the cloud-native endpoint for everything covered in Scenarios 1–5.
Best Practices for PowerShell Azure Automation
You've probably noticed that raw scripts get messy fast. Here are the practices that separate reliable, maintainable Azure automation from one-off hacks:
Use service principals, never personal accounts. Interactive Connect-AzAccount logins expire and break pipelines. Create a dedicated service principal with the minimum RBAC permissions your script needs, store the credentials in Azure Key Vault, and retrieve them at runtime.
Tag everything at creation time. Retrofitting tags onto hundreds of resources is painful. Build tagging into every New-Az* command from day one — Environment, Owner, CostCenter at a minimum.
Test with -WhatIf and -Verbose. Most Az cmdlets support -WhatIf. Always test destructive operations in a dev subscription first. Pair with -Verbose to see exactly what API calls are being made.
Handle errors explicitly. Wrap critical operations in try/catch blocks and log failures to a file or Azure Monitor workspace. Silent failures in overnight automation are the worst kind.
Version-control your scripts. Store all runbook scripts in Git. Use parameter files for environment-specific values (subscription IDs, resource group names) so the same script runs in dev and prod without modification.
For broader PowerShell monitoring and health checking across your infrastructure, see Monitor System Health with a PowerShell Dashboard.
Conclusion
PowerShell Azure automation through the Az module transforms cloud management from a repetitive, click-heavy chore into a reproducible, auditable workflow. In this guide you covered six high-value scenarios — resource inventory, VM scheduling, resource group management, ARM/Bicep deployments, cost reporting, and Azure Automation runbooks — each with working code you can adapt today.
Start with the scenario that addresses your biggest current pain point. Get one script running reliably, commit it to source control, and build from there. Within a week you'll have an automation portfolio that handles tasks that used to take hours — automatically, overnight, while you focus on higher-value work.
Frequently Asked Questions
What's the difference between Stop-AzVM and deallocating a VM?
Stop-AzVM without the -Force flag only stops the OS; the VM is still in a "Stopped" state and Azure continues billing for compute. To stop billing, you must fully deallocate the VM by using Stop-AzVM -Force, which puts it in the "Deallocated" state.
Can I run Az module scripts on Linux or macOS?
Yes. The Az module runs on PowerShell 7+ which is fully cross-platform. Install PowerShell 7 on Linux or macOS, then install the Az module with Install-Module -Name Az, and all scripts in this guide will work without modification.
How do I avoid storing Azure credentials in my scripts?
Never hardcode credentials. Use a service principal with a certificate or client secret stored in Azure Key Vault. In your script, authenticate with Connect-AzAccount -Identity (Managed Identity) when running inside Azure, or retrieve secrets at runtime using Get-AzKeyVaultSecret.
What RBAC role does my service principal need for these scripts? It depends on the script. For read-only inventory scripts, the built-in Reader role is sufficient. For VM start/stop, assign Virtual Machine Contributor. For resource group creation and ARM deployments, Contributor at the subscription or resource group level is typically required. Always apply the principle of least privilege.
Related articles: PowerShell Active Directory User Management, PowerShell Task Scheduler: Automate Scripts, Monitor System Health with a PowerShell Dashboard
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.
