Introduction
Virtual machines that are powered off, inactive, or forgotten still consume storage, licenses, and management resources. Identifying these VMs across a large vSphere environment can be challenging. PowerCLI allows you to audit and report idle or unused VMs, making cleanup and cost optimization easier.
In this article, you will learn how to:
- Detect VMs that are powered off
- Identify VMs with low or no CPU/memory activity
- Tag, annotate, or export these VMs for review
- Build an audit-friendly CSV report
- Prepare for cleanup actions with safe scripts
Step 1: List Powered-Off VMs
Get-VM | Where-Object {$_.PowerState -eq "PoweredOff"} | Select Name, VMHost, @{N="DaysSincePoweredOff";E={(Get-Date) - $_.ExtensionData.Runtime.BootTime}}
Export to CSV:
Get-VM | Where-Object {$_.PowerState -eq "PoweredOff"} | Export-Csv "C:\Reports\PoweredOffVMs.csv" -NoTypeInformation
Step 2: Detect Low CPU and Memory Usage VMs
Query recent performance stats:
$lowUsageVMs = Get-VM | Where-Object {
$_.PowerState -eq "PoweredOn" -and
$_.ExtensionData.Summary.QuickStats.OverallCpuUsage -lt 100 -and
$_.ExtensionData.Summary.QuickStats.GuestMemoryUsage -lt 100
}
Export for audit:
$lowUsageVMs | Select Name, VMHost, PowerState | Export-Csv "C:\Reports\IdleVMs.csv" -NoTypeInformation
Step 3: Annotate Candidates for Cleanup
$lowUsageVMs | ForEach-Object {
Set-VM -VM $_ -Notes "Marked for review: low CPU/memory usage"
}
Tag if using vSphere tags:
$tag = Get-Tag -Name "ReviewForCleanup"
$lowUsageVMs | New-TagAssignment -Tag $tag
Step 4: Combine Idle and Powered-Off Report
$combined = Get-VM | Where-Object {
$_.PowerState -eq "PoweredOff" -or
($_.ExtensionData.Summary.QuickStats.OverallCpuUsage -lt 50 -and $_.ExtensionData.Summary.QuickStats.GuestMemoryUsage -lt 50)
}
$combined | Select Name, PowerState, VMHost | Export-Csv "C:\Reports\Combined_IdleVMs.csv" -NoTypeInformation
Diagram: Idle VM Audit Process

Use Case: Quarterly Cleanup Review
- Export list of all idle and off VMs
- Send to application owners for review
- Apply tags to VMs approved for deletion
- Schedule removal script with snapshot fallback
Bonus: Schedule Audit with Logging
$log = "C:\Logs\IdleVMScan_$(Get-Date -Format yyyyMMdd).log"
$combined | Export-Csv "C:\Reports\IdleVMs_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
"$($combined.Count) idle VMs detected on $(Get-Date)" | Out-File $log
Troubleshooting
| Problem | Fix |
|---|---|
| GuestMemoryUsage returns null | Ensure VMware Tools is installed and running |
| CPU usage shows zero but VM is active | Extend performance query range with Get-Stat |
| Notes field not saving | Ensure Set-VM command is used with correct parameters |
| No idle VMs found | Adjust thresholds or widen time window for CPU/memory averages |
Introduction VM tags in vSphere are a powerful way to organize, classify, and apply policies to virtual machines. But without regular audits,...