Bulk VM Operations with PowerCLI: Power States, Snapshots, Tags, and Migrations

Introduction

Managing hundreds, or thousands, of VMs requires automation that is repeatable, predictable, and safe. PowerCLI allows you to apply changes across the fleet with confidence, reducing risk and saving time.

In this article, you’ll learn how to:

  • Power VMs on/off in bulk
  • Take and remove snapshots programmatically
  • Tag or annotate multiple VMs
  • Perform mass storage migrations
  • Automate shutdown/startup in order
  • Troubleshoot common automation issues

My Personal Repository on GitHub

VMware Repository on GitHub


Bulk Power Operations

Power Off All VMs in a Folder

$folder = Get-Folder -Name "Dev"
Get-VM -Location $folder | Stop-VM -Confirm:$false

Power On All VMs on a Host

Get-VMHost -Name "esxi03.lab.local" | Get-VM | Start-VM

Power Off VMs Gracefully by OS Type

Get-VM | Where-Object {$_.Guest.OSFullName -like "*Windows*"} | Stop-VMGuest -Confirm:$false

Snapshot Automation

Take Snapshot for All Running VMs

Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"} | ForEach-Object {
New-Snapshot -VM $_ -Name "PreChange-$(Get-Date -Format yyyyMMdd-HHmm)" -Description "Snapshot before updates"
}

Remove Snapshots Older Than 7 Days

Get-VM | Get-Snapshot | Where-Object {$_.Created -lt (Get-Date).AddDays(-7)} | Remove-Snapshot -Confirm:$false

Tagging and Annotations

Assign Tag to All VMs in a Resource Pool

$pool = Get-ResourcePool -Name "Production"
$tag = Get-Tag -Name "Backup-Enabled"
Get-VM -Location $pool | New-TagAssignment -Tag $tag

Bulk Update VM Notes

Get-VM | Where-Object {$_.Name -like "*App*"} | Set-VM -Notes "Application server - reviewed 2025-07"

Storage vMotion: Moving VMs Between Datastores

Move all powered-off VMs from one datastore to another.

$source = Get-Datastore -Name "DS1"
$dest = Get-Datastore -Name "DS2"

Get-VM | Where-Object {
$_.PowerState -eq "PoweredOff" -and
($_.ExtensionData.Config.DatastoreUrl -match $source.Name)
} | Move-VM -Datastore $dest

Use with caution: Validate I/O impact and available space.


Custom Ordered Shutdown / Startup Sequences

Power off based on naming or application tier.

$orderedList = "DB-", "App-", "Web-"

foreach ($prefix in $orderedList) {
Get-VM | Where-Object {$_.Name -like "$prefix*"} | Stop-VMGuest -Confirm:$false
Start-Sleep -Seconds 10
}

Reverse the list for startup logic.


Diagram: Bulk VM Lifecycle Management


Error Handling & Common Issues

ScenarioFix
Snapshot creation fails on encrypted VMsCheck encryption policy and VM version compatibility
Stop-VMGuest hangsEnsure VMware Tools is running; fallback to Stop-VM if needed
Storage move fails due to lockVerify VM is powered off and not in backup state
Tag not found or duplicatedUse Get-Tag -Name 'TagName' and validate tag category assignment

Use Case Example: Pre-Maintenance VM Handling

Before host patching:

  • Take snapshot of critical VMs
  • Gracefully shut down based on tier
  • Migrate VMs to other hosts

PowerCLI snippet:

$criticalVMs = Get-VM | Where-Object {$_.Name -match "SQL|Exchange"}
$criticalVMs | New-Snapshot -Name "PrePatch" -Description "Pre-maintenance snapshot"
$criticalVMs | Stop-VMGuest -Confirm:$false

What’s Next

In the next article, we’ll cover:

  • Automated VM deployment using templates
  • Customizing guest OS with PowerCLI
  • Deploying VMs from JSON/CSV input

Leave a Reply

Discover more from Digital Thought Disruption

Subscribe now to keep reading and get access to the full archive.

Continue reading