At one of my clients, it is desired to create a snapshot of a virtual machine each day and to maintain only a certain number of them. This script was developed in order to manage those snapshots using a scheduled task on the Hyper-V host.

To adjust the number of old snapshots retained, adjust the "-7" on the second line.

The script will cycle through all of the VMs and remove any snapshot older that $DOld.

It will then create a new snapshot using the name YYYY-M-D. The script checks to see if the VM encountered is part of a replication pair and if it is primary. This way, we only attempt to create snapshots against the primary VM in a replica pair and any non-replicating VMs.

$DNew=Date
$DOld=$DNew.AddDays(-7)
$DNewName = ($DNew).Year.ToString() + "-" + ($DNew).Month.ToString() + "-" + ($DNew).Day.ToString()
$DOldName = ($DOld).Year.ToString() + "-" + ($DOld).Month.ToString() + "-" + ($DOld).Day.ToString()

# Note about removing old snapshots
Write-Host -NoNewline -ForegroundColor White "Deleting snapshots older than "
Write-Host -ForegroundColor Yellow $DOld

# Add new snapshots
Write-Host -NoNewLine -ForegroundColor White "Adding snapshots labeled "
Write-Host -ForegroundColor Yellow $DNewName
foreach ($VM in (Get-VM)) {
    Write-Host -ForegroundColor Magenta $VM.Name
    # Delete snaps older than $DOld
    foreach ($VMS in ($VM | Get-VMSnapshot)) {
        Write-Host -NoNewline " "
        Write-Host -ForegroundColor Gray $VMS.Name
        if ($VMS.CreationTime -lt $DOld) {
            Write-Host -NoNewLine -ForegroundColor Cyan "Removing snap "
            Write-Host -NoNewLine -ForegroundColor Green $VMS.Name
            Write-Host -NoNewLine -ForegroundColor Cyan " from VM "
            Write-Host -NoNewLine -ForegroundColor Green $VMS.VMName
            $VMS | Remove-VMSnapshot -Passthru
            Write-Host -NoNewline -ForegroundColor Cyan " ... "
            Start-Sleep -Seconds 15
            while($VM.Status -eq 'Merging disks') { Write-Host -NoNewLine -ForeGroundColor Cyan "m"; Start-Sleep -Seconds 15 }
            Write-Host -ForegroundColor Cyan " ..."
            Start-Sleep -Seconds 15
        }
    }
    
    # See if a snapshot already exists
    $C = (($VM)|Get-VMSnapshot -Name $DNewName -ErrorAction SilentlyContinue).Count
    if ($C -eq 0) {
        # If one does not exist then...
        if ($VM.ReplicationState -eq "Replicating") {
            # if this VM is being replicated...
            if (($VM | Get-VMReplication).ReplicationMode -eq "Primary") { 
                # ...and the Vm is the source then
                Write-Host -ForegroundColor Green (" "+$DNewName)
                $VM | Checkpoint-VM -SnapshotName $DNewName
                $Length = 3
                $Tick = 300
                while($Tick -gt 0) {
                    $min = [int](([string]($Tick/60)).split('.')[0])
                    $text = " " + $min + " minutes " + ($Tick % 60) + " seconds left"
                    Write-Progress "Pausing script" -status $text -perc ($Tick/$Length)
                    Start-Sleep -Seconds 1
                    $Tick--
                } 
                Write-Progress "Pausing script" -Completed
            }
        } else {
            # No replication is happening at all...
            Write-Host -ForegroundColor Green (" Adding "+$DNewName)
            $VM | Checkpoint-VM -SnapshotName $DNewName
            $Length = 3
            $Tick = 300
            while($Tick -gt 0) {
                $min = [int](([string]($Tick/60)).split('.')[0])
                $text = " " + $min + " minutes " + ($Tick % 60) + " seconds left"
                Write-Progress "Pausing script" -status $text -perc ($Tick/$Length)
                Start-Sleep -Seconds 1
                $Tick--
            }
            Write-Progress "Pausing script" -Completed
        }
    }
}