š Practical PowerShell for Azure: Automating Cloud Tasks with Confidence


PowerShell has become an essential tool for managing and automating tasks in Azure. With the Az module, it's possible to work directly with Azure resources in a way thatās both scriptable and scalable.
This post covers practical PowerShell examples for automating common cloud tasksālike starting or stopping virtual machines, filtering resources by location or status, using loops to repeat actions across multiple resources, and handling errors cleanly in scripts.
Each example is designed to highlight real-world patterns that can simplify cloud operations and help make automation scripts more reliable and flexible.
āļø Getting Started with Basic PowerShell Commands for Azure
Before diving into automation, itās helpful to get familiar with a few core commands used to interact with Azure resources. These examples use the Az module, which can be installed with:
powershellCopyEditInstall-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
After installation, log in to your Azure account:
powershellCopyEditConnect-AzAccount
Once connected, here are some commonly used commands:
š Create a Resource Group
A resource group is a container for your Azure resources. Here's how to create one using PowerShell:
powershellCopyEditNew-AzResourceGroup -Name "MyResourceGroup" -Location "EastUS"
š» Get a List of Virtual Machines
To list all virtual machines in your subscription:
powershellCopyEditGet-AzVM
If you only want to see the VM names:
powershellCopyEditGet-AzVM | Select-Object Name
š¢ Start a VM
powershellCopyEditStart-AzVM -Name "vm-name" -ResourceGroupName "MyResourceGroup"
š“ Stop a VM
powershellCopyEditStop-AzVM -Name "vm-name" -ResourceGroupName "MyResourceGroup"
These commands form the foundation of most PowerShell automation tasks. Once you're comfortable running them manually, it becomes easier to scale things up using loops, filtering, and error handling.
š Filtering and Logic in PowerShell
One of the most useful parts of working with PowerShell is its ability to handle objects, not just plain text. This means you can filter Azure resources based on properties like location, status, or nameācleanly and efficiently.
Here are a few ways to apply logic when working with Azure virtual machines:
š Filter VMs by Location
This returns only the virtual machines that are in a specific region:
powershellCopyEditGet-AzVM | Where-Object { $_.Location -eq "EastUS" }
The $_
refers to āthe current objectā being passed through the pipeline. This line says:
āGet all the VMs, and keep only the ones where the Location equals EastUS.ā
ā” Filter VMs That Are Running
To check the status of a VM (e.g. running, stopped), add the -Status
flag:
powershellCopyEditGet-AzVM -Status | Where-Object { $_.Statuses[1].Code -eq "PowerState/running" }
The status is returned as an array, and the power state is typically found at index [1]
.
š§ Combine Filters (e.g. Location + Status)
You can combine multiple conditions inside the same filter:
powershellCopyEditGet-AzVM -Status | Where-Object {
$_.Location -eq "EastUS" -and $_.Statuses[1].Code -eq "PowerState/running"
}
This returns only the VMs that are both in EastUS and currently running. From here, you could pass that into other commands like Stop-AzVM
.
š Loops and Automation with PowerShell
Once you know how to get and filter Azure resources, the next step is automating actions across multiple resources. Thatās where loopsāespecially foreach
ācome in.
Hereās how to repeat actions for a list of virtual machines:
ā¶ļø Loop Through a List of VM Names
You can loop through a simple array of VM names like this:
powershellCopyEdit$vms = @("vm1", "vm2", "vm3")
foreach ($vm in $vms) {
Start-AzVM -Name $vm -ResourceGroupName "MyResourceGroup"
}
This will attempt to start each VM in the list, one at a time.
š§± Loop Through VMs with Different Resource Groups
If each VM is in a different resource group, you can store both values using an array of hashtables:
powershellCopyEdit$vms = @(
@{ Name = "vm1"; RG = "GroupA" },
@{ Name = "vm2"; RG = "GroupB" }
)
foreach ($vm in $vms) {
Start-AzVM -Name $vm.Name -ResourceGroupName $vm.RG
}
This approach makes your script more dynamic and flexibleāespecially in real-world environments where naming and grouping arenāt always consistent.
š§Æ Add Error Handling with Try/Catch
To prevent your loop from crashing if one VM fails (for example, if itās already running or doesn't exist), wrap the command in a try { } catch { }
block:
powershellCopyEditforeach ($vm in $vms) {
try {
Start-AzVM -Name $vm.Name -ResourceGroupName $vm.RG
}
catch {
Write-Output "Failed to start VM: $($vm.Name)"
}
}
You can also log these failures to a file:
powershellCopyEdit"Failed to start VM: $($vm.Name)" | Out-File -FilePath "errors.txt" -Append
With these patterns, you can automate common cloud operations in a way thatās reliable and easy to maintain.
š“ Stopping VMs Based on Region and Power State
Sometimes, you only want to stop virtual machines that are currently runningāand maybe only in a specific region. This avoids unnecessary API calls and helps keep your scripts efficient and safe.
š Stop All Running VMs in EastUS
This command filters for VMs that are:
Located in EastUS
Currently in the running state
Then it pipes them directly into Stop-AzVM
:
powershellCopyEditGet-AzVM -Status | Where-Object {
$_.Location -eq "EastUS" -and $_.Statuses[1].Code -eq "PowerState/running"
} | Stop-AzVM
PowerShell automatically handles parameter binding hereāit passes the VM Name
and ResourceGroupName
to Stop-AzVM
behind the scenes, as long as those properties exist on the object.
š§Æ Optional: Add Error Handling
To safely stop VMs in a loop with error logging:
powershellCopyEdit$vms = Get-AzVM -Status | Where-Object {
$_.Location -eq "EastUS" -and $_.Statuses[1].Code -eq "PowerState/running"
}
foreach ($vm in $vms) {
try {
Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Force
}
catch {
"Failed to stop VM: $($vm.Name)" | Out-File -FilePath "stop-errors.txt" -Append
}
}
š¹
-Force
is used to avoid confirmation prompts
š¹ Errors are logged, but the loop continues
With these patterns, it's easy to scale out operations across multiple VMs without writing complex logic. Filtering + looping + error handling = the core of smart PowerShell automation.
š Logging and Output in PowerShell Scripts
Logging is an underrated part of automation. Whether you're running a script manually or inside a CI/CD pipeline, it's important to know what happened, what failed, and what succeededāwithout staring at the terminal the whole time.
š¬ Output to the Console
During development or testing, simple console messages help trace what's happening:
powershellCopyEditWrite-Output "Starting VM: $($vm.Name)"
Or the shorter alias:
powershellCopyEdit"Starting VM: $($vm.Name)"
š Writing to a Log File
For longer-running scripts, especially those in production or being used by others, it's better to log to a file:
powershellCopyEdit"Successfully started VM: $($vm.Name)" | Out-File -FilePath "log.txt" -Append
You can also write errors:
powershellCopyEdit"Failed to stop VM: $($vm.Name)" | Out-File -FilePath "error-log.txt" -Append
The -Append
flag ensures each new line is added to the end of the file, not overwriting the previous ones.
š§ Pro Tip: Timestamp Your Logs
Adding a timestamp to each log entry can make troubleshooting easier:
powershellCopyEdit"$((Get-Date).ToString('u')) - Started VM: $($vm.Name)" | Out-File -FilePath "log.txt" -Append
This adds something like:
yamlCopyEdit2025-04-10 12:43:00Z - Started VM: myVM01
Logging is especially useful when combining multiple operations in a scriptālike stopping some VMs, starting others, tagging resources, or setting configurations.
ā Wrapping Up
PowerShell, when paired with the Az module, becomes a reliable tool for managing Azure resources through automation. Whether it's starting or stopping virtual machines, filtering resources by region or status, or handling errors and logsāthese patterns are foundational for scaling out cloud operations.
What makes PowerShell especially effective is its combination of:
Object-based filtering (using
Where-Object
)Looping through multiple resources (
foreach
)Built-in error handling (
try/catch
)Readable output and logs (
Out-File
, timestamps, etc.)
These arenāt just helpful for simplifying repetitive tasksāthey also build the confidence needed to run scripts safely in production environments or as part of deployment pipelines.
š§© Whatās Next?
Here are a few great next steps you could explore from here:
Turn these script patterns into functions for reuse
Accept input parameters to make scripts more flexible
Use PowerShell in Azure DevOps pipelines
Combine with Terraform or ARM templates for hybrid deployments
PowerShell is not just about command-line controlāit's a foundation for reliable cloud automation.
⨠Thanks for reading! If you're exploring cloud automation, DevOps, or scripting in generalāthis post is part of a growing collection of hands-on guides. Follow along for more real-world tips and tools.
Subscribe to my newsletter
Read articles from Charan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
