Running individual PowerCLI commands interactively is useful for quick checks, but the real value of PowerCLI is in automation: scripts that run on a schedule, generate reports, or apply changes across dozens of VMs without manual intervention.
This guide covers the core patterns you need to write practical PowerCLI scripts: connecting and disconnecting cleanly, handling credentials, iterating over VMs, filtering results, exporting data, and structuring scripts for reuse.
Prerequisites
- PowerCLI installed — see How to install VMware PowerCLI and connect to vSphere
- A text editor or PowerShell ISE / VS Code for writing scripts
- Access to a vCenter Server or ESXi host
Script structure
A well-structured PowerCLI script follows a consistent pattern regardless of what it does:
# 1. Define parameters at the top
param(
[string]$VCenterServer = "vc01.vsphere.local",
[string]$ReportPath = "C:\Reports\vm-report.csv"
)
# 2. Connect to vCenter
Connect-VIServer -Server $VCenterServer
# 3. Do the work
# ... your logic here ...
# 4. Disconnect when done
Disconnect-VIServer -Server * -Confirm:$false
Keeping this structure consistent makes scripts easier to read, test, and hand off to other administrators.
Handling credentials safely
Avoid hardcoding passwords in scripts. Two common approaches work well in practice.
Interactive prompt — suitable for scripts run manually:
# Prompt the operator for credentials at runtime
$cred = Get-Credential
Connect-VIServer -Server vc01.vsphere.local -Credential $cred
Encrypted credential file — suitable for scheduled tasks on a trusted machine:
# Save credentials once (run this interactively, not in the script)
$cred = Get-Credential
$cred.Password | ConvertFrom-SecureString | Set-Content "C:\Scripts\vcenter-pass.txt"
# In the script, load credentials from the encrypted file
$user = "administrator@vsphere.local"
$passFile = "C:\Scripts\vcenter-pass.txt"
$pass = Get-Content $passFile | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PSCredential($user, $pass)
Connect-VIServer -Server vc01.vsphere.local -Credential $cred
Iterating over VMs
Most PowerCLI scripts loop over a set of VMs and perform an action on each. The pipeline handles this naturally:
# Get all powered-on VMs and print their name and host
Get-VM | Where-Object { $_.PowerState -eq "PoweredOn" } | ForEach-Object {
Write-Host "$($_.Name) is running on $($_.VMHost)"
}
To target a specific folder, cluster, or datacenter:
# Get VMs from a specific folder
Get-VM -Location "Production"
# Get VMs from a specific cluster
Get-Cluster "CL-PROD-01" | Get-VM
# Get VMs from a specific host
Get-VMHost "esxi01.vsphere.local" | Get-VM
Filtering and selecting properties
PowerCLI objects expose many properties. Use Select-Object to control which fields appear in output or exports:
# List VM name, power state, number of CPUs, and memory
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB | Format-Table -AutoSize
# Filter VMs with more than 8 GB of memory
Get-VM | Where-Object { $_.MemoryGB -gt 8 } | Select-Object Name, MemoryGB
Exporting results to CSV
Exporting data to CSV is useful for inventory reports, capacity planning, and change records:
# Export a VM inventory report to CSV
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB, @{N="Host"; E={$_.VMHost}} |
Export-Csv -Path "C:\Reports\vm-inventory.csv" -NoTypeInformation
Write-Host "Report saved to C:\Reports\vm-inventory.csv"
-NoTypeInformation removes the type header line that PowerShell adds by default to CSV files. Without it, the first row of the CSV contains a PowerShell object type string instead of column headers, which breaks most spreadsheet imports.
Error handling
Scripts that run unattended need to handle errors gracefully rather than stopping silently mid-run:
# Use try/catch to handle connection errors
try {
Connect-VIServer -Server vc01.vsphere.local -ErrorAction Stop
Write-Host "Connected successfully"
}
catch {
Write-Host "Failed to connect: $_"
exit 1
}
# Use -ErrorAction SilentlyContinue for non-critical operations
$snap = Get-Snapshot -VM "SRV-APP-01" -ErrorAction SilentlyContinue
if ($null -eq $snap) {
Write-Host "No snapshots found for SRV-APP-01"
}
A complete example: VM inventory report
This script connects to vCenter, collects a VM inventory, exports it to CSV, and disconnects cleanly:
# vm-inventory.ps1
# Connects to vCenter, exports VM inventory to CSV, disconnects.
# Usage: .\vm-inventory.ps1 -VCenterServer vc01.vsphere.local -ReportPath C:\Reports\vms.csv
param(
[string]$VCenterServer = "vc01.vsphere.local",
[string]$ReportPath = "C:\Reports\vm-inventory.csv"
)
# Connect - prompt for credentials at runtime
try {
Connect-VIServer -Server $VCenterServer -ErrorAction Stop
}
catch {
Write-Host "Connection failed: $_"
exit 1
}
# Collect VM data with a calculated Host column
$report = Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB,
@{Name="Host"; Expression={$_.VMHost.Name}},
@{Name="GuestOS"; Expression={$_.Guest.OSFullName}}
# Export to CSV
$report | Export-Csv -Path $ReportPath -NoTypeInformation
Write-Host "Exported $($report.Count) VMs to $ReportPath"
# Disconnect cleanly
Disconnect-VIServer -Server * -Confirm:$false
Official reference
VMware PowerCLI — Broadcom Developer Portal
