We have a cluster with a bunch of VMs. Let’s say around 300 .
Some actions require us to take a snapshot of certain VMs and then remove them after we’re sure everything is ok.
We are using VeeamOne to track this, but it’s goot do have good old PowerShell take care of the task itself.
There are 3 snippets here I’m using very often:
This code also can be used to target single Hyper-V instances and use different Credentials. Also some Hyper-V nodes may be in maintenance mode so first let’s check which of those are available.
$HyperVHost = 'ClusterName' #clustername 'ClusterName' or hostname 'HyperVHost'
$Cluster = $true #true if cluster is targeted
#$Credential = Get-Credential #Optional
$connProperties = @{
ComputerName = $HyperVHost
}
if ($Credential) {
$connProperties.Credential = $Credential
}
if ($Cluster) {
$Nodes = Invoke-Command @connProperties -ScriptBlock {
Get-ClusterNode | where-object { $_.State -eq 'Up' } | select-object -ExpandProperty Name
}
$connProperties.ComputerName = $Nodes
}
Once I have all active
nodes I can query them for VMs and process only specific ones to create snapshot SystemUpdate
:
$SnapshotName = 'SystemUpdate'
$VMsToProcess = @(
'VMName1',
'VMName2'
)
Invoke-Command @connProperties -ScriptBlock {
$VMs = Get-VM
foreach ($VM in $VMs) {
if($VM.VMName -in $USING:VMsToProcess) {
Write-Host "Processing VM {$($VM.Name)} on Host {$($ENV:COMPUTERNAME)}"
Checkpoint-VM -VM $VM -SnapshotName $USING:SnapshotName
}
}
}
If I need to find all VMs with a snapshot of a name ‘SystemUpdate’ here’s the code:
$SnapshotName = 'SystemUpdate'
$VMs = Invoke-Command @connProperties -ScriptBlock {
Get-VM | Get-VMSnapshot -Name $USING:SnapshotName -ErrorAction SilentlyContinue
}
$VMsToProcess = $VMs | Out-GridView -passThru
I’ll get a window where I can select specific VMs to process. Also I’ll see whether there is a parent snapshot present:
Now let’s merge those snapshots:
foreach ($process in $VMsToProcess) {
$connProperties.ComputerName = $process.PSComputerName
Invoke-Command @connProperties -ScriptBlock {
Write-Host "Processing $($USING:process.VMName) on host $($env:COMPUTERNAME)"
Get-VM $USING:process.VMName | Get-VMSnapshot -Name $USING:SnapshotName | Remove-VMSnapshot -Verbose
}
}
Here are full snippets for given tasks
$HyperVHost = 'ClusterName' #clustername 'ClusterName' or hostname 'HyperVHost'
$Cluster = $true #true if cluster is targeted
#$Credential = Get-Credential #Optional
$connProperties = @{
ComputerName = $HyperVHost
}
if ($Credential) {
$connProperties.Credential = $Credential
}
if ($Cluster) {
$Nodes = Invoke-Command @connProperties -ScriptBlock {
Get-ClusterNode | where-object { $_.State -eq 'Up' } | select-object -ExpandProperty Name
}
$connProperties.ComputerName = $Nodes
}
$SnapshotName = 'SystemUpdate'
$VMsToProcess = @(
'VMName1',
'VMName2'
)
Invoke-Command @connProperties -ScriptBlock {
$VMs = Get-VM
foreach ($VM in $VMs) {
if($VM.VMName -in $USING:VMsToProcess) {
Write-Host "Processing VM {$($VM.Name)} on Host {$($ENV:COMPUTERNAME)}"
Checkpoint-VM -VM $vM -SnapshotName $USING:SnapshotName
}
}
}
$HyperVHost = 'ClusterName' #clustername 'ClusterName' or hostname 'HyperVHost'
$Cluster = $true #true if cluster is targeted
#$Credential = Get-Credential #Optional
$connProperties = @{
ComputerName = $HyperVHost
}
if ($Credential) {
$connProperties.Credential = $Credential
}
if ($Cluster) {
$Nodes = Invoke-Command @connProperties -ScriptBlock {
Get-ClusterNode | where-object { $_.State -eq 'Up' } | select-object -ExpandProperty Name
}
$connProperties.ComputerName = $Nodes
}
$SnapshotName = 'SystemUpdate'
$VMs = Invoke-Command @connProperties -ScriptBlock {
Get-VM | Get-VMSnapshot -Name $USING:SnapshotName -ErrorAction SilentlyContinue
}
$VMsToProcess = $VMs | Out-GridView -passThru
$HyperVHost = 'ClusterName' #clustername 'ClusterName' or hostname 'HyperVHost'
$Cluster = $true #true if cluster is targeted
#$Credential = Get-Credential #Optional
$connProperties = @{
ComputerName = $HyperVHost
}
if ($Credential) {
$connProperties.Credential = $Credential
}
if ($Cluster) {
$Nodes = Invoke-Command @connProperties -ScriptBlock {
Get-ClusterNode | where-object { $_.State -eq 'Up' } | select-object -ExpandProperty Name
}
$connProperties.ComputerName = $Nodes
}
$SnapshotName = 'SystemUpdate'
$VMs = Invoke-Command @connProperties -ScriptBlock {
Get-VM | Get-VMSnapshot -Name $USING:SnapshotName -ErrorAction SilentlyContinue
}
$VMsToProcess = $VMs | Out-GridView -passThru
foreach ($process in $VMsToProcess) {
$connProperties.ComputerName = $process.PSComputerName
Invoke-Command @connProperties -ScriptBlock {
Write-Host "Processing $($USING:process.VMName) on host $($env:COMPUTERNAME)"
Get-VM $USING:process.VMName | Get-VMSnapshot -Name $USING:SnapshotName | Remove-VMSnapshot -Verbose
}
}
These three little snippets saves me time whether I’m running a demo lab on my private host, test hosts or production ones.