šŸš€ Practical PowerShell for Azure: Automating Cloud Tasks with Confidence

CharanCharan
7 min read

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.

0
Subscribe to my newsletter

Read articles from Charan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Charan
Charan