Introduction:
While working in a Nutanix-AHV environment I wanted to list all snapshots in the environment. With VMware vSphere you needed to do this with PowerCLI or use the excellent RVTools. In Nutanix Prism you can (to my knowledge) only see the snapshots when opening the virtual machine details.
Going through every VM in this environment would cost precious time that could also be spent drinking coffee, going through Twitter or catching up on some sleep. So I created the following script to list all snapshots in your environment, the virtual machine it belongs to and when it was created.
The script:
Just copy the code below to your PowerShell editor of choice (Visual Studio Code FTW) and save it as a .ps1 file or download the Zip file.
Fill in the NTNXCluster variable with the Fully Qualified Domain Name / Hostname or IP address of your Nutanix Cluster(s) (divide multiple with a semicolon (;)) and add any exceptions if needed. Also make sure you have the Nutanix Cmdlets installed on your system (which of course you have already).
After that run the .ps1 file and it will ask for credentials which it will use to connect to the Nutanix Cluster and retrieve the snapshot information.
The actual script:
# SCRIPT INFO ------------------- # --- Query all Snapshots on Nutanix --- # By Chris Jeucken # v0.9 # ------------------------------- # Run on management server with NutanixCmdlets installed # VARIABLES --------------------- # Default variables $NTNXSnapin = "NutanixCmdletsPSSnapin" # Set environment specific variables $NTNXCluster = "*** PROVIDE NUTANIX CLUSTER FQDN/HOSTNAME/IP ***" # Divide multiple clusters with semicolon (;). $NTNXException = "XDSNAP*" # Provide exceptions (if any) for specific snapshots (e.g.: XDSNAP*), divide with semicolon (;), leave empty if no exceptions. # ------------------------------- # SCRIPT ------------------------ # Convert variables to multi line $NTNXCluster = $NTNXCluster.Split(";") $NTNXException = $NTNXException.Split(";") # Get credentials from user $NTNXCredentials = Get-Credential -Message "Please provide Nutanix administrator credentials (e.g.: admin@domain.suffix):" # Importing Nutanix Cmdlets $Loaded = Get-PSSnapin -Name $NTNXSnapin -ErrorAction SilentlyContinue | ForEach-Object {$_.Name} $Registered = Get-PSSnapin -Name $NTNXSnapin -Registered -ErrorAction SilentlyContinue | ForEach-Object {$_.Name} foreach ($Snapin in $Registered) { if ($Loaded -notcontains $Snapin) { Add-PSSnapin $Snapin } } # Connect to Nutanix Clusters foreach ($Cluster in $NTNXCluster) { try { Connect-NTNXCluster -Server $Cluster -Password $NTNXCredentials.Password -UserName $NTNXCredentials.UserName -ErrorAction SilentlyContinue | Out-Null } catch { Write-Host *** Not able to connect to Nutanix Cluster $Cluster *** -ForegroundColor Red } } # Test connection to Nutanix cluster if (!(Get-NTNXCluster -ErrorAction SilentlyContinue)) { Write-Host *** No functional Nutanix connection available *** -ForegroundColor Red exit } # Create results table if ($Results) { Remove-Variable -Name Results } $Results = New-Object system.Data.DataTable "All NTNX snapshots" $Column1 = New-Object System.Data.DataColumn VM-Name,([string]) $Column2 = New-Object System.Data.DataColumn Snapshot-Name,([string]) $Column3 = New-Object System.Data.DataColumn Creation-Time,([string]) $Results.Columns.Add($Column1) $Results.Columns.Add($Column2) $Results.Columns.Add($Column3) # Get all VMs and snapshots $AllNTNXVM = Get-NTNXVM -ErrorAction SilentlyContinue $AllNTNXSnapshots = Get-NTNXSnapshot -ErrorAction SilentlyContinue # Handle exceptions (if any) if ($NTNXException) { foreach ($Exception in $NTNXException) { $AllNTNXSnapshots = $AllNTNXSnapshots | Where-Object {$_.snapshotName -notlike $Exception} } } # Find VM for each snapshot and export to table foreach ($Snapshot in $AllNTNXSnapshots) { $VMUuid = $Snapshot.vmUuid $VMname = ($AllNTNXVM | Where-Object {$_.Uuid -eq $VMUuid}).vmName $SnapshotName = $Snapshot.snapshotName $CreationTimeStamp = ($Snapshot.createdTime)/1000 $CreationTime = (Get-Date '1/1/1970').AddMilliseconds($CreationTimeStamp) $SnapshotCreationTime = $CreationTime.ToLocalTime() $Row = $Results.NewRow() $Row."VM-Name" = $VMname $Row."Snapshot-Name" = $SnapshotName $Row."Creation-Time" = $SnapshotCreationTime $Results.Rows.Add($Row) } # Disconnect from Nutanix Clusters foreach ($Cluster in $NTNXCluster) { if (Get-NTNXCluster -ErrorAction SilentlyContinue) { Disconnect-NTNXCluster -Server $Cluster } } # Present results $Results | Format-Table # -------------------------------
DISCLAIMER: Once again: I’m in no way an expert PowerShell scripter, so it might not be the most efficient code, but it gets the job done. And, of course, feel free to use it/alter it/publish it as your own.
Love this! One thing: I don’t get the VM-Name. See below.(sorry ~ format)
VM-Name Snapshot-Name Creation-Time
——- ————- ————-
nNSVPXd – Before CVE-2019-19781 12/26/2019 5:04
n10GoldStaff1809 – 10.31.19 – WEM 1906 10/31/2019 11:46
Apps – FileZille 3.36.0 9/12/2018 13:44
nNSVPXa – Backup 2 11/28/2017 20:18
nSRNPro-B4FebUpdts 2/18/2020 17:39
nSRFSB-B4FebUpdts 2/18/2020 18:02
Second thing: (see how I am? 🙂 )
How to put to file, Export-CSV instead of Format-Table?
Thanks
Deniece,
Thanks for the feedback. 🙂
That’s strange.
Maybe some things changed in the CMDlets.
Sadly I don’t have access to a Nutanix environment right now, so I am unable to test it for you.
In the following lines retrieve the VM-name.
$VMUuid = $Snapshot.vmUuid
$VMname = ($AllNTNXVM | Where-Object {$_.Uuid -eq $VMUuid}).vmName
After running the script, could you try running these lines this way? (To see if it gives output)
It should use the last snapshot in the foreach loop.
$VMUuid = $Snapshot.vmUuid
($AllNTNXVM | Where-Object {$_.Uuid -eq $VMUuid}).vmName
As for the export:
You could just change the last line from:
$Results | Format-Table
to
$Results | Export-Csv -Path *Filename*
Let me know if that works for you.
Greetings,
Chris
Sorry I missed it the first time around: timeout have something to do with it?
PS C:\Users\SU2> C:\Scripts\NTNX\Query-all-snapshots-Nutanix-AHV.ps1
Get-NTNXVM : The operation has timed out
At C:\Scripts\NTNX\Query-all-snapshots-Nutanix-AHV.ps1:63 char:18
+ $AllNTNXVM = Get-NTNXVM -ErrorAction SilentlyContinue
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (Nutanix.Prism.Common.NutanixCluster:NutanixCluster) [Get-NTNXVM], WebException
+ FullyQualifiedErrorId : Error,Nutanix.Prism.PS.Cmds.Vmmanagement.GetVM
VM-Name Snapshot-Name Creation-Time
——- ————- ————-
nNSVPXd – Before CVE-2019-19781 12/26/2019 5:04:46 AM
n10GoldStaff1809 – 10.31.19 – WEM 1906 10/31/2019 11:46:06 AM
Apps – FileZille 3.36.0 9/12/2018 1:44:17 PM
Have you tried running Get-NTNXVM by itself?
Like I said, maybe the functionality and/or parameters changed for this cmdlet.
Script works fine, thanks a lot.
By the way do you know the Nutanix recommendation for keep a VM snapshot?
Hi Chris,
I tried the script suggested by you and it works after making minor tweaks. Along with that is it possible for you to add info about the size of the Snapshot(MB or GB) in another column?
# SCRIPT INFO ——————-
# — Query all Snapshots on Nutanix —
# By Chris Jeucken
# v0.9
# ——————————-
# Run on management server with NutanixCmdlets installed
# VARIABLES ———————
# Default variables
$NTNXSnapin = “NutanixCmdletsPSSnapin”
# Set environment specific variables —-> This is not working for me
$NTNXCluster = “FQDN/IP” # Divide multiple clusters with semicolon (;).
$NTNXException = “XDSNAP*” # Provide exceptions (if any) for specific snapshots (e.g.: XDSNAP*), divide with semicolon (;), leave empty if no exceptions.
# ——————————-
# SCRIPT ————————
# Convert variables to multi line —-> I am not sure whether this is working
$NTNXCluster = $NTNXCluster.Split(“;”)
$NTNXException = $NTNXException.Split(“;”)
# Get credentials from user —- This is not working for me, hence I use “Connect-NutanixCluster -Server FQDN -UserName admin -Password pwd” before executing this script
# $NTNXCredentials = Get-Credential -Message “Please provide Nutanix administrator credentials (e.g.: admin@domain.suffix):”
# Importing Nutanix Cmdlets
$Loaded = Get-PSSnapin -Name $NTNXSnapin -ErrorAction SilentlyContinue | ForEach-Object {$_.Name}
$Registered = Get-PSSnapin -Name $NTNXSnapin -Registered -ErrorAction SilentlyContinue | ForEach-Object {$_.Name}
foreach ($Snapin in $Registered) {
if ($Loaded -notcontains $Snapin) {
Add-PSSnapin $Snapin
}
}
# Connect to Nutanix Clusters —> Everytime I get message that “Nota able to connect…..” I guess because of the above methods may be needs little modification
foreach ($Cluster in $NTNXCluster) {
try {
Connect-NTNXCluster -Server $Cluster -Password $NTNXCredentials.Password -UserName $NTNXCredentials.UserName -ErrorAction SilentlyContinue | Out-Null
} catch {
Write-Host *** Not able to connect to Nutanix Cluster $Cluster *** -ForegroundColor Red
}
}
# Test connection to Nutanix cluster —-> Even though Nutanix cluster I connected in my PS, I get this message.
if (!(Get-NTNXCluster -ErrorAction SilentlyContinue)) {
Write-Host *** No functional Nutanix connection available *** -ForegroundColor Red
exit
}
# Create results table —> This is working perfectly.
if ($Results) {
Remove-Variable -Name Results
}
$Results = New-Object system.Data.DataTable “All NTNX snapshots”
$Column1 = New-Object System.Data.DataColumn VM-Name,([string])
$Column2 = New-Object System.Data.DataColumn Snapshot-Name,([string])
$Column3 = New-Object System.Data.DataColumn Creation-Time,([string])
$Results.Columns.Add($Column1)
$Results.Columns.Add($Column2)
$Results.Columns.Add($Column3)
# Get all VMs and snapshots —> This is working perfectly I GUESS
$AllNTNXVM = Get-NTNXVM -ErrorAction SilentlyContinue
$AllNTNXSnapshots = Get-NTNXSnapshot -ErrorAction SilentlyContinue
# Handle exceptions (if any) —> Not Sure
if ($NTNXException) {
foreach ($Exception in $NTNXException) {
$AllNTNXSnapshots = $AllNTNXSnapshots | Where-Object {$_.snapshotName -notlike $Exception}
}
}
# Find VM for each snapshot and export to table —–> Working Perfectly
foreach ($Snapshot in $AllNTNXSnapshots) {
$VMUuid = $Snapshot.vmUuid
$VMname = ($AllNTNXVM | Where-Object {$_.Uuid -eq $VMUuid}).vmName
$SnapshotName = $Snapshot.snapshotName
$CreationTimeStamp = ($Snapshot.createdTime)/1000
$CreationTime = (Get-Date ‘1/1/1970’).AddMilliseconds($CreationTimeStamp)
$SnapshotCreationTime = $CreationTime.ToLocalTime()
$Row = $Results.NewRow()
$Row.”VM-Name” = $VMname
$Row.”Snapshot-Name” = $SnapshotName
$Row.”Creation-Time” = $SnapshotCreationTime
$Results.Rows.Add($Row)
}
# Disconnect from Nutanix Clusters —-> Working but I disabled it.
# foreach ($Cluster in $NTNXCluster) {
# if (Get-NTNXCluster -ErrorAction SilentlyContinue) {
# Disconnect-NTNXCluster -Server $Cluster
# }
# }
# Present results
# $Results | Format-Table
$Results | Export-Csv -Path C:\temp\snapshots.csv
# ——————————-
Nagarjun,
I think it should be possible to add the snapshot sizes, although I don’t have access to a Nutanix environment right now.
But I will look into it as soon as I get the chance.
Could you specify the minor tweaks you made to get it to work? (as to improve this blogpost ;-))
Greetings,
Chris
Hi Chris,
I´ve added param and the csv export to the script.
I plan to add a small mail report and will try to add the size of the snapshot.
Script´s on Github:
https://github.com/powerquell/nutanix/blob/main/Prism%20Element/Get-NTNXUVMSnapshots.ps1
Regards
Erik
Erik,
Great work on improving it.
And thanks for sharing.
Greetings,
Chris
Hi Eric,
I am pulling snapshots from multiple clusters, so hard to tell which cluster the snapshots are from. Are you aware of a way to add a column with the cluster name, or have the snapshots separated by cluster, to make it easier to work with?
Thanks,
Jeremy
Great script and thanks for sharing!
When connecting to more than one cluster, is it possible to have the output separated by cluster to help identify which cluster the VM/snapshot belongs to?
Thanks,
Jeremy
Jeremy,
Thanks for the feedback.
I guess that should be possible to seperate the output, but I don’t have access to a Nutanix environment right now to test it.
So I’m not able to add that functionality. Sorry for that.
Greetings,
Chris
I found another site that had a single line command to run from the Nutanix server over SSH. It will list server name and space usage for VMs with snapshots. I am working on scripting out a way to send notification emails if snapshots are discovered because they tend to build up with several administrators around here. Shouldn’t there be an API call that could be used to pull back the information? If so, a small webpart should be able to provide a checklist to select which to delete for confirmation. Just thinking through possibilities to automate my job away. 🙂
Here is the command.
ncli pd ls-snaps|egrep “Size.*\)|VM Name” |grep –no-group-separator -A1 ‘VM Name’ |grep –no-group-separator -B1 Size | tr -d ‘(,’ |awk ‘/Snapshot\ Size/{print $6}1’|grep -v Snapshot |awk ‘/.*VM\ Name.*$/{printf $0″:”;next;}1’ |awk -F : ‘{print $2 “:” $3}’ |sed -e ‘s/^\ //’ -e ‘s/\ /_/g’ |sort |awk -F : ‘BEGIN { tag = -1; sum = 0} {if (tag != $1) {if (tag > -1) {print tag, sum;}tag = $1; sum = $2} else { sum += $2 }} END {print tag, sum}’ | awk ‘{ split( “K M G T P” , v ); s=0; while( $2>1024 ){ $2/=1024; s++ } {printf $1 “: ” “%.2f %s\n”, $2, v[s] }}’