Finds every snapshot across all VMs older than the configured age and removes it asynchronously, logging the VM, age and size of each. It starts in what-if mode, printing exactly what it would delete and how much space that frees — flip one variable to make it real. Old snapshots are the most common cause of a full datastore.
powershell
$server = "esxi.example.local"
$maxAgeDays = 30
$whatIf = $true # Set to $false to actually delete
Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $true -Confirm:$false
$username = "SE-CredentialsStore.Username.(esxi.example.local)"
$password = "SE-CredentialsStore.Password.(esxi.example.local)"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $securePassword)
Connect-VIServer -Server $server -Credential $credential
Write-Host "<WRITE-LOG = ""*================== Delete Snapshots Older Than $maxAgeDays Days ==================*"">"
$cutoffDate = (Get-Date).AddDays(-$maxAgeDays)
$snapshots = Get-VM | Get-Snapshot | Where-Object { $_.Created -lt $cutoffDate }
if ($snapshots) {
foreach ($snap in $snapshots) {
$ageDays = ((Get-Date) - $snap.Created).Days
if ($whatIf) {
Write-Host "<WRITE-LOG = ""*[WHATIF] Would delete snapshot: $($snap.Name) on VM: $($snap.VM.Name) | Age: $ageDays days | Size: $([math]::Round($snap.SizeGB,2)) GB*"">"
} else {
Write-Host "<WRITE-LOG = ""*Deleting snapshot: $($snap.Name) on VM: $($snap.VM.Name) | Age: $ageDays days*"">"
Remove-Snapshot -Snapshot $snap -Confirm:$false -RunAsync
}
}
} else {
Write-Host "<WRITE-LOG = ""*No snapshots older than $maxAgeDays days found.*"">"
}
Disconnect-VIServer -Server $server -Confirm:$falseRun it across your fleet
This script runs as-is on a single host. Paste it into ServerEngine to schedule it, run it on a whole server group in parallel, and keep the credentials out of the file — see the scripts documentation and the credential store.
More in VMware & vSphere
Ready when you are.
Try ServerEngine free for 7 days.