Query all snapshots from Nutanix-AHV

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.

Loading

13 thoughts on “Query all snapshots from Nutanix-AHV

  1. Deniece Greenwood

    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

    Reply
    1. Chris Jeucken Post author

      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

      Reply
      1. Deniece Greenwood

        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

        Reply
  2. Leonardo Almeida

    Script works fine, thanks a lot.

    By the way do you know the Nutanix recommendation for keep a VM snapshot?

    Reply
  3. Nagarjun

    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
    # ——————————-

    Reply
    1. Chris Jeucken Post author

      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

      Reply
    1. Jeremy

      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

      Reply
  4. 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

    Reply
    1. Chris Jeucken Post author

      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

      Reply
  5. Marty Hillman

    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] }}’

    Reply

Leave a Reply

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