VMware PowerCLI: Setup and Everyday Automation
At a glance#
- Purpose: Install PowerCLI and use it for routine vSphere administration and reporting.
- Applies to: VMware PowerCLI 13+ against vCenter 7.0 and 8.0.
- Risk: Medium — scripted operations apply across many VMs at once; a wrong filter has wide effect.
- Time: 30 minutes to set up; ongoing for scripting.
Overview#
PowerCLI is VMware's PowerShell module for vSphere. Anything the vSphere client can do, PowerCLI can do — the difference is that it can do it to two hundred VMs at once, on a schedule, and produce a report at the end.
The tasks it saves the most time on are the repetitive ones: capacity reporting, snapshot cleanup, VMware Tools status, and finding VMs that are misconfigured in some consistent way.
Warning: A PowerCLI command with no filter applies to every VM in the connected vCenter. Always run destructive operations with -WhatIf first, then remove it. There is no undo.
Before you start#
- PowerShell 7 (cross-platform) or Windows PowerShell 5.1.
- Network access to vCenter on TCP 443.
- A vCenter account with the required privileges — use a read-only account for reporting.
Installation#
1. Install the module#
Install-Module -Name VMware.PowerCLI -Scope CurrentUser -ForceConfirm:
Get-Module -Name VMware.PowerCLI -ListAvailable | Select-Object Name, Version2. Configure certificate handling#
If vCenter uses the default self-signed certificate, PowerCLI refuses to connect:
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$falseNote:Ignoreis acceptable on an internal management network but disables certificate validation entirely. Where vCenter has a proper certificate installed, leave the defaultFailinstead.
3. Opt out of telemetry#
Set-PowerCLIConfiguration -ParticipateInCEIP $false -Confirm:$false4. Connect#
Connect-VIServer -Server vcenter.example.localTo avoid interactive prompts in scheduled scripts, store the credential securely:
# once, as the account that will run the script
$cred = Get-Credential
$cred | Export-Clixml -Path "$HOME\vcenter-cred.xml"
# in the script
$cred = Import-Clixml -Path "$HOME\vcenter-cred.xml"
Connect-VIServer -Server vcenter.example.local -Credential $credWarning: Export-Clixml encrypts using the Windows DPAPI, tied to that user on that machine. It cannot be read by another user or copied to another server — which is the point. Do not fall back to hard-coding passwords in the script.
Disconnect when finished:
Disconnect-VIServer -Server * -Confirm:$falseEveryday reporting#
Inventory of all VMs#
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB,
@{N='UsedGB';E={[math]::Round($_.UsedSpaceGB,1)}},
@{N='ProvisionedGB';E={[math]::Round($_.ProvisionedSpaceGB,1)}},
@{N='Host';E={$_.VMHost.Name}} |
Sort-Object Name | Format-Table -AutoSizeExport to CSV for capacity reviews:
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB, UsedSpaceGB, ProvisionedSpaceGB |
Export-Csv -Path C:\Reports\vm-inventory.csv -NoTypeInformationDatastore free space#
Get-Datastore | Select-Object Name,
@{N='CapacityGB';E={[math]::Round($_.CapacityGB,1)}},
@{N='FreeGB';E={[math]::Round($_.FreeSpaceGB,1)}},
@{N='FreePct';E={[math]::Round(($_.FreeSpaceGB/$_.CapacityGB)*100,1)}} |
Sort-Object FreePct | Format-Table -AutoSizeDatastores under 15% free:
Get-Datastore | Where-Object { ($_.FreeSpaceGB / $_.CapacityGB) -lt 0.15 } |
Select-Object Name, FreeSpaceGB, CapacityGBVMs with outdated or missing VMware Tools#
Get-VM | Where-Object { $_.PowerState -eq 'PoweredOn' } |
Select-Object Name,
@{N='ToolsStatus';E={$_.ExtensionData.Guest.ToolsStatus}},
@{N='ToolsVersion';E={$_.ExtensionData.Guest.ToolsVersionStatus}} |
Where-Object { $_.ToolsStatus -ne 'toolsOk' } |
Format-Table -AutoSizeSnapshots older than 7 days#
The most useful report on this list — old snapshots silently consume datastore space and degrade performance.
Get-VM | Get-Snapshot |
Where-Object { $_.Created -lt (Get-Date).AddDays(-7) } |
Select-Object VM, Name, Created,
@{N='SizeGB';E={[math]::Round($_.SizeGB,2)}}, Description |
Sort-Object SizeGB -Descending | Format-Table -AutoSizeHost health#
Get-VMHost | Select-Object Name, ConnectionState, PowerState,
@{N='CpuUsagePct';E={[math]::Round(($_.CpuUsageMhz/$_.CpuTotalMhz)*100,1)}},
@{N='MemUsagePct';E={[math]::Round(($_.MemoryUsageGB/$_.MemoryTotalGB)*100,1)}},
Version, Build |
Format-Table -AutoSizeVMs with mounted ISOs#
Mounted ISOs block vMotion and are usually left behind after a build:
Get-VM | Get-CDDrive |
Where-Object { $_.IsoPath -ne $null } |
Select-Object Parent, IsoPathEveryday operations#
Power operations#
Start-VM -VM 'web01'
Stop-VMGuest -VM 'web01' -Confirm:$false # graceful, needs VMware Tools
Stop-VM -VM 'web01' -Confirm:$false # hard power off
Restart-VMGuest -VM 'web01' -Confirm:$falseWarning:Stop-VMis the equivalent of pulling the power cable. UseStop-VMGuestunless the guest is unresponsive.
Adjust resources#
# Requires the VM to be powered off unless hot-add is enabled
Set-VM -VM 'web01' -NumCpu 4 -MemoryGB 8 -Confirm:$falseAdd a disk#
New-HardDisk -VM 'web01' -CapacityGB 100 -StorageFormat ThinThen extend the volume inside the guest — see Extending partition size by adding new disk LVM Linux.
Bulk operations with a safety net#
Always dry-run first:
# see what would happen
Get-VM -Name 'test-*' | Stop-VMGuest -WhatIf
# then commit
Get-VM -Name 'test-*' | Stop-VMGuest -Confirm:$falseFind VMs by attribute#
# powered off for a long time - candidates for decommissioning
Get-VM | Where-Object { $_.PowerState -eq 'PoweredOff' } |
Select-Object Name, Notes
# oversized VMs
Get-VM | Where-Object { $_.NumCpu -ge 8 -and $_.PowerState -eq 'PoweredOn' } |
Select-Object Name, NumCpu, MemoryGBA scheduled reporting script#
# C:\Scripts\vsphere-daily-report.ps1
$ErrorActionPreference = 'Stop'
$date = Get-Date -Format 'yyyy-MM-dd'
$out = "C:\Reports\$date"
New-Item -ItemType Directory -Path $out -Force | Out-Null
$cred = Import-Clixml -Path "$HOME\vcenter-cred.xml"
Connect-VIServer -Server vcenter.example.local -Credential $cred | Out-Null
try {
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB, UsedSpaceGB |
Export-Csv "$out\vm-inventory.csv" -NoTypeInformation
Get-Datastore | Select-Object Name, CapacityGB, FreeSpaceGB |
Export-Csv "$out\datastores.csv" -NoTypeInformation
Get-VM | Get-Snapshot | Where-Object { $_.Created -lt (Get-Date).AddDays(-7) } |
Select-Object VM, Name, Created, SizeGB |
Export-Csv "$out\old-snapshots.csv" -NoTypeInformation
}
finally {
Disconnect-VIServer -Server * -Confirm:$false
}Schedule it with Task Scheduler — see Windows Services and Task Scheduler.
Verification#
# connected and to what
$global:DefaultVIServers
# module version
Get-Module VMware.PowerCLI | Select-Object Name, Version
# a read-only command returns data
Get-VM | Select-Object -First 5 Name, PowerStateFor any change made through PowerCLI, confirm it in the vSphere client as well. Tasks are logged under Recent Tasks with the account that ran them.
Troubleshooting#
| Symptom | Cause and fix |
|---|---|
Invalid server certificate | Self-signed vCenter certificate. Run the Set-PowerCLIConfiguration -InvalidCertificateAction Ignore step. |
Connect-VIServer not recognised | Module not loaded. Run Import-Module VMware.PowerCLI. |
Install-Module fails | PowerShell Gallery unreachable, or NuGet provider missing. Run Install-PackageProvider -Name NuGet -Force. |
| Cmdlet returns nothing | Not connected, or the filter matched nothing. Check $global:DefaultVIServers. |
Insufficient privileges | The account lacks the vSphere permission for that operation. |
| Script prompts for credentials when scheduled | The DPAPI-encrypted credential file was created by a different user. Recreate it as the scheduled task's account. |
Set-VM fails on a running VM | CPU or memory hot-add disabled. Power off, or enable hot-add. |
| Very slow inventory commands | Get-VM on a large estate is expensive. Filter server-side: Get-VM -Name 'web*'. |