KB
Virtualization

VMware PowerCLI: Setup and Everyday Automation

6 min read1100 words22 code blocks

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#

powershell
Install-Module -Name VMware.PowerCLI -Scope CurrentUser -Force

Confirm:

powershell
Get-Module -Name VMware.PowerCLI -ListAvailable | Select-Object Name, Version

2. Configure certificate handling#

If vCenter uses the default self-signed certificate, PowerCLI refuses to connect:

powershell
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
Note: Ignore is acceptable on an internal management network but disables certificate validation entirely. Where vCenter has a proper certificate installed, leave the default Fail instead.

3. Opt out of telemetry#

powershell
Set-PowerCLIConfiguration -ParticipateInCEIP $false -Confirm:$false

4. Connect#

powershell
Connect-VIServer -Server vcenter.example.local

To avoid interactive prompts in scheduled scripts, store the credential securely:

powershell
# 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 $cred
Warning: 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:

powershell
Disconnect-VIServer -Server * -Confirm:$false

Everyday reporting#

Inventory of all VMs#

powershell
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 -AutoSize

Export to CSV for capacity reviews:

powershell
Get-VM | Select-Object Name, PowerState, NumCpu, MemoryGB, UsedSpaceGB, ProvisionedSpaceGB |
  Export-Csv -Path C:\Reports\vm-inventory.csv -NoTypeInformation

Datastore free space#

powershell
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 -AutoSize

Datastores under 15% free:

powershell
Get-Datastore | Where-Object { ($_.FreeSpaceGB / $_.CapacityGB) -lt 0.15 } |
  Select-Object Name, FreeSpaceGB, CapacityGB

VMs with outdated or missing VMware Tools#

powershell
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 -AutoSize

Snapshots older than 7 days#

The most useful report on this list — old snapshots silently consume datastore space and degrade performance.

powershell
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 -AutoSize

Host health#

powershell
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 -AutoSize

VMs with mounted ISOs#

Mounted ISOs block vMotion and are usually left behind after a build:

powershell
Get-VM | Get-CDDrive |
  Where-Object { $_.IsoPath -ne $null } |
  Select-Object Parent, IsoPath

Everyday operations#

Power operations#

powershell
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:$false
Warning: Stop-VM is the equivalent of pulling the power cable. Use Stop-VMGuest unless the guest is unresponsive.

Adjust resources#

powershell
# Requires the VM to be powered off unless hot-add is enabled
Set-VM -VM 'web01' -NumCpu 4 -MemoryGB 8 -Confirm:$false

Add a disk#

powershell
New-HardDisk -VM 'web01' -CapacityGB 100 -StorageFormat Thin

Then 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:

powershell
# see what would happen
Get-VM -Name 'test-*' | Stop-VMGuest -WhatIf

# then commit
Get-VM -Name 'test-*' | Stop-VMGuest -Confirm:$false

Find VMs by attribute#

powershell
# 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, MemoryGB

A scheduled reporting script#

powershell
# 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#

powershell
# 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, PowerState

For 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#

SymptomCause and fix
Invalid server certificateSelf-signed vCenter certificate. Run the Set-PowerCLIConfiguration -InvalidCertificateAction Ignore step.
Connect-VIServer not recognisedModule not loaded. Run Import-Module VMware.PowerCLI.
Install-Module failsPowerShell Gallery unreachable, or NuGet provider missing. Run Install-PackageProvider -Name NuGet -Force.
Cmdlet returns nothingNot connected, or the filter matched nothing. Check $global:DefaultVIServers.
Insufficient privilegesThe account lacks the vSphere permission for that operation.
Script prompts for credentials when scheduledThe DPAPI-encrypted credential file was created by a different user. Recreate it as the scheduled task's account.
Set-VM fails on a running VMCPU or memory hot-add disabled. Power off, or enable hot-add.
Very slow inventory commandsGet-VM on a large estate is expensive. Filter server-side: Get-VM -Name 'web*'.