Removing Snapshots with PowerCLI

Snapshots for Maintenance or Maintenance for Snapshots…

During our last maintenance window for our VMware environment, my team updated VMware Tools, hardware and aligned vNUMA.  So before we started this work we tool snapshots of all of the VMs there were getting the updates.  Fast forward a few days, and now we have 600+ snapshots that need to be deleted.

Automating Snapshots Removal with PowerCLI

With having 600+ snapshots I didn’t just want to delete them all at once.  So since these were generated with a script they all have the same name, so I can use that to target them.

$AllNamedSnapshots = Get-cluster NonProductionCluster | Get-vm | Get-Snapshot | Where Name -eq "PreToolsandHardware20180310"

This will return all of the snapshots that were generated on this cluster with the give name in to an array.

$RemoveSnapshotTasks = $AllNamedSnapshots | Select -First 15 

This will select the first 15 snapshots so it can be feed into the next line of code shown below.

foreach($SnapShottobeRemoved in $RemoveSnapshotTasks){
 $Tasks[(Remove-Snapshot $SnapShottobeRemoved -RunAsync -Confirm:$false).id] = $SnapShottobeRemoved
 }

This is the line that makes the magic happen.  It will start the snapshot removal and add the task ids to a hash table.  The reason for a hash table here is that it is easier to manipulate the data later on in the script.

Zip the Snaps

Now to put these lines together and delete the snapshots, I give you the completed script.

$AllNamedSnapshots = Get-cluster NonProductionCluster | Get-Snapshot | Where Name -eq "PreToolsandHardware20180310"
$SnapshotRemaining = $AllNamedSnapshots.count
$Tasks = @{}

While ($SnapshotRemaining -gt 0){
    $RemoveSnapshotTasks = $AllNamedSnapshots | Select -First 15
    foreach($SnapShottobeRemoved in $RemoveSnapshotTasks){
        $Tasks[(Remove-Snapshot $SnapShottobeRemoved -RunAsync -Confirm:$false).id] = $SnapShottobeRemoved
    }
    
    $RunningTasks = $Tasks.count
    While ($RunningTasks -gt 0){
        Get-Task | % {
            If($tasks.containskey($_.id) -and $_.state -eq "Success"){
                $tasks.Remove($_.Id)
                $RunningTasks--
                $SnapshotRemaining--
            }
        }
        Start-Sleep -Seconds 10
        Write-host "There are still $RunningTasks task(s) running" -BackgroundColor Black -ForegroundColor Yellow
    }
    $AllNamedSnapshots = Get-cluster NonProductionCluster | Get-Snapshot | Where Name -eq "PreToolsandHardware20180310"
}

The below is what the output of the script looks like when it is running correctly.

Starting next 15 snapshots
Starting next 15 snapshots

This is a handle little script that we are going to use for many purposes.  I can easily modify the line that gathers the snapshots to instead of looking for name snapshots, but look for snapshots older the 14 days to automatically remove them and run it via a schedule tasks or setup it in vRealize Orchestrator.

The one caveat with this script is that if one of the 15 snapshots takes a long time to remove the script has to wait.  There is a way to check for these conditions and skip them, but that’s another post.

1 task still running
There are still 1 task(s) running…

-Stuart

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.