Functions/Get-RSCAHVVMs.ps1

################################################
# Function - Get-RSCAHVVMs - Getting all AHV VMs connected to the RSC instance
################################################
Function Get-RSCAHVVMs {

<#
.SYNOPSIS
Returns a list of all Nutanix AHV VMs in RSC.
 
.DESCRIPTION
Makes the required GraphQL API calls to RSC via Invoke-RestMethod to get the data as described, then creates a usable array of the returned information, removing the need for the PowerShell user to understand GraphQL in order to interact with RSC.
 
.OUTPUTS
Returns an array of all the available information on the GraphQL endpoint in a uniform and usable format.
 
.EXAMPLE
Get-RSCAHVVMs
This example returns an array of all the information returned by the GraphQL endpoint for this object type.
 
.NOTES
Author: Joshua Stenhouse
Date: 05/11/2023
#>


################################################
# Importing Module & Running Required Functions
################################################
# Importing the module is it needs other modules
Import-Module RSCReporting
# Checking connectivity, exiting function with error if not connected
Test-RSCConnection
################################################
# Getting All AHV VMs
################################################
# Creating array for objects
$RSCVMList = @()
# Building GraphQL query
$RSCGraphQL = @{"operationName" = "NutanixVms";

"variables" = @{
"first" = 1000
};

"query" = "query NutanixVms(`$first: Int, `$after: String) {
  nutanixVms(first: `$first, after: `$after) {
    edges {
      node {
        agentStatus {
          connectionStatus
          disconnectReason
        }
        cdmId
        currentHostId
        effectiveSlaDomain {
          id
          name
        }
        excludedDisks
        hypervisorType
        id
        isAgentRegistered
        isRelic
        latestUserNote {
          userNote
          userName
          time
          objectId
        }
        name
        newestArchivedSnapshot {
          id
          date
        }
        newestReplicatedSnapshot {
          id
          date
        }
        newestSnapshot {
          id
          date
        }
        nutanixSnapshotConsistencyMandate
        objectType
        oldestSnapshot {
          id
          date
        }
        onDemandSnapshotCount
        osType
        physicalPath {
          fid
          name
          objectType
        }
        postBackupScript {
          failureHandling
          scriptPath
          timeoutMs
        }
        postSnapScript {
          failureHandling
          scriptPath
          timeoutMs
        }
        preBackupScript {
          failureHandling
          timeoutMs
          scriptPath
        }
        primaryClusterLocation {
          clusterUuid
          id
          name
        }
        vmUuid
        vmDisks {
          deviceType
          label
          isSnapshottable
          sizeInBytes
          uuid
          vmDiskUuid
        }
        slaPauseStatus
        slaAssignment
        replicatedObjectCount
        snapshotConsistencyMandate
        snapshotDistribution {
          onDemandCount
          retrievedCount
          scheduledCount
          totalCount
        }
        reportSnappable {
          archivalSnapshotLag
          archiveStorage
          archiveSnapshots
          awaitingFirstFull
          dataReduction
          lastSnapshotLogicalBytes
          localEffectiveStorage
          localMeteredData
          localOnDemandSnapshots
          localProtectedData
          localSlaSnapshots
          localSnapshots
          localStorage
          logicalBytes
          location
          logicalDataReduction
          missedSnapshots
          physicalBytes
          protectedOn
          protectionStatus
          provisionedBytes
          pullTime
          replicaSnapshots
          replicaStorage
          replicationSnapshotLag
          transferredBytes
          totalSnapshots
          usedBytes
        }
      }
    }
    pageInfo {
      endCursor
      hasNextPage
      startCursor
      hasPreviousPage
    }
  }
}"

}
################################################
# API Call To RSC GraphQL URI
################################################
# Querying API
$RSCVMListResponse = Invoke-RestMethod -Method POST -Uri $RSCGraphqlURL -Body $($RSCGraphQL | ConvertTo-JSON -Depth 20) -Headers $RSCSessionHeader
# Setting variable
$RSCVMList += $RSCVMListResponse.data.nutanixVms.edges.node
# Getting all results from paginations
While ($RSCVMListResponse.data.nutanixVms.pageInfo.hasNextPage) 
{
# Getting next set
$RSCGraphQL.variables.after = $RSCVMListResponse.data.nutanixVms.pageInfo.endCursor
$RSCVMListResponse = Invoke-RestMethod -Method POST -Uri $RSCGraphqlURL -Body $($RSCGraphQL | ConvertTo-JSON -Depth 20) -Headers $RSCSessionHeader
$RSCVMList += $RSCVMListResponse.data.nutanixVms.edges.node
}
################################################
# Processing VMs
################################################
# Creating array
$RSCVMs = [System.Collections.ArrayList]@()
# For Each Object Getting Data
ForEach ($RSCVM in $RSCVMList)
{
# Setting variables
$VMID = $RSCVM.id
$VMName = $RSCVM.name
$VMCDMID = $RSCVM.cdmId
$VMUUID = $RSCVM.vmUuid
$VMIsRelic = $RSCVM.isRelic
$VMProtectionDateUNIX = $RSCVM.reportSnappable.protectedOn
$VMGuestOSType = $RSCVM.guestOsType
$VMConsistency = $RSCVM.nutanixSnapshotConsistencyMandate
$VMAgentRegistered = $RSCVM.isAgentRegistered
$VMAgentInfo = $RSCVM.agentStatus
$VMAgentStatus = $VMAgentInfo.connectionStatus
$VMAgentDisconnectReason = $VMAgentInfo.disconnectReason
# User note info
$VMNoteInfo = $RSCVM.latestUserNote
$VMNote = $VMNoteInfo.userNote
$VMNoteCreator = $VMNoteInfo.userName
$VMNoteCreatedUNIX = $VMNoteInfo.time
# Converting dates
IF($VMProtectionDateUNIX -ne $null){$VMProtectionDateUTC = Convert-RSCUNIXTime $VMProtectionDateUNIX}ELSE{$VMProtectionDateUTC = $null}
IF($VMNoteCreatedUNIX -ne $null){$VMNoteCreatedUTC = Convert-RSCUNIXTime $VMNoteCreatedUNIX}ELSE{$VMNoteCreatedUTC = $null}
# SLA info
$VMSLADomainInfo = $RSCVM.effectiveSlaDomain
$VMSLADomain = $VMSLADomainInfo.name
$VMSLADomainID = $VMSLADomainInfo.id
$VMSLAAssignment = $RSCVM.slaAssignment
$VMSLAPaused = $RSCVM.slaPauseStatus
# VM location
$VMPhysicalPaths = $RSCVM.physicalPath
$VMClusterInfo = $VMPhysicalPaths | Where-Object {$_.objectType -eq "NutanixCluster"}
$VMClusterName = $VMClusterInfo.name
$VMClusterID = $VMClusterInfo.fid
# VMDK info
$VMVirtualDisks = $RSCVM.vmDisks.edges.node
$VMVirtualDisksCount = $VMVirtualDisks | Measure-Object | Select-Object -ExpandProperty Count
$VMVirtualDisksExcluded = $RSCVM.excludedDisks
$VMVirtualDisksExcludedCount = $VMVirtualDisksExcluded | Measure-Object | Select-Object -ExpandProperty Count
# VM scripting
$VMPreBackupScriptInfo = $RSCVM.preBackupScript
$VMPostBackupScriptInfo = $RSCVM.postBackupScript
IF($VMPreBackupScriptInfo -eq ""){$VMPreBackupScriptEnabled = $FALSE}ELSE{$VMPreBackupScriptEnabled = $TRUE}
IF($VMPostBackupScriptInfo -eq ""){$VMPostBackupScriptEnabled = $FALSE}ELSE{$VMPostBackupScriptEnabled = $TRUE}
# VM snapshot distribution
$VMSnapshotTotals = $RSCVM.snapshotDistribution
$VMOnDemandSnapshots = $VMSnapshotTotals.onDemandCount
$VMSnapshots = $VMSnapshotTotals.scheduledCount
# VM snapshot info
$VMSnapshotDateUNIX = $RSCVM.newestSnapshot.date
$VMSnapshotDateID = $RSCVM.newestSnapshot.id
$VMReplicatedSnapshotDateUNIX = $RSCVM.newestReplicatedSnapshot.date
$VMReplicatedSnapshotDateID = $RSCVM.newestReplicatedSnapshot.id
$VMArchiveSnapshotDateUNIX = $RSCVM.newestArchivedSnapshot.date
$VMArchiveSnapshotDateID = $RSCVM.newestArchivedSnapshot.id
$VMOldestSnapshotDateUNIX = $RSCVM.oldestSnapshot.date
$VMOldestSnapshotDateID = $RSCVM.oldestSnapshot.id
# Converting snapshot dates
IF($VMSnapshotDateUNIX -ne $null){$VMSnapshotDateUTC = Convert-RSCUNIXTime $VMSnapshotDateUNIX}ELSE{$VMSnapshotDateUTC = $null}
IF($VMReplicatedSnapshotDateUNIX -ne $null){$VMReplicatedSnapshotDateUTC = Convert-RSCUNIXTime $VMReplicatedSnapshotDateUNIX}ELSE{$VMSnVMReplicatedSnapshotDateUTCapshotDateUTC = $null}
IF($VMArchiveSnapshotDateUNIX -ne $null){$VMArchiveSnapshotDateUTC = Convert-RSCUNIXTime $VMArchiveSnapshotDateUNIX}ELSE{$VMArchiveSnapshotDateUTC = $null}
IF($VMOldestSnapshotDateUNIX -ne $null){$VMOldestSnapshotDateUTC = Convert-RSCUNIXTime $VMOldestSnapshotDateUNIX}ELSE{$VMOldestSnapshotDateUTC = $null}
# Calculating hours since each snapshot
$UTCDateTime = [System.DateTime]::UtcNow
IF($VMSnapshotDateUTC -ne $null){$VMSnapshotTimespan = New-TimeSpan -Start $VMSnapshotDateUTC -End $UTCDateTime;$VMSnapshotHoursSince = $VMSnapshotTimespan | Select-Object -ExpandProperty TotalHours;$VMSnapshotHoursSince = [Math]::Round($VMSnapshotHoursSince,1)}ELSE{$VMSnapshotHoursSince = $null}
IF($VMReplicatedSnapshotDateUTC -ne $null){$VMReplicatedSnapshotTimespan = New-TimeSpan -Start $VMReplicatedSnapshotDateUTC -End $UTCDateTime;$VMReplicatedSnapshotHoursSince = $VMReplicatedSnapshotTimespan | Select-Object -ExpandProperty TotalHours;$VMReplicatedSnapshotHoursSince = [Math]::Round($VMReplicatedSnapshotHoursSince,1)}ELSE{$VMReplicatedSnapshotHoursSince = $null}
IF($VMArchiveSnapshotDateUTC -ne $null){$VMArchiveSnapshotTimespan = New-TimeSpan -Start $VMArchiveSnapshotDateUTC -End $UTCDateTime;$VMArchiveSnapshotHoursSince = $VMArchiveSnapshotTimespan | Select-Object -ExpandProperty TotalHours;$VMArchiveSnapshotHoursSince = [Math]::Round($VMArchiveSnapshotHoursSince,1)}ELSE{$VMArchiveSnapshotHoursSince = $null}
IF($VMOldestSnapshotDateUTC -ne $null){$VMOldestSnapshotTimespan = New-TimeSpan -Start $VMOldestSnapshotDateUTC -End $UTCDateTime;$VMOldestSnapshotDaysSince = $VMOldestSnapshotTimespan | Select-Object -ExpandProperty TotalDays;$VMOldestSnapshotDaysSince = [Math]::Round($VMOldestSnapshotDaysSince,1)}ELSE{$VMOldestSnapshotDaysSince = $null}
# Reporting data
$VMReportInfo = $RSCVM.reportSnappable
$VMWaitingForFirstFull = $VMReportInfo.awaitingFirstFull
$VMProvisionedBytes = $VMReportInfo.localProtectedData
$VMProtectedBytes = $VMReportInfo.localProtectedData
$VMLocalUsedBytes = $VMReportInfo.localStorage
$VMReplicaUsedBytes = $VMReportInfo.replicaStorage
$VMArchiveUsedBytes = $VMReportInfo.archiveStorage
$VMLocalSnapshots = $VMReportInfo.localSnapshots
$VMReplicaSnapshots = $VMReportInfo.replicaSnapshots
$VMArchiveSnapshots = $VMReportInfo.archiveSnapshots
# Converting storage units
IF($VMProvisionedBytes -ne $null){$VMProvisionedGB = $VMProvisionedBytes / 1000 / 1000 / 1000;$VMProvisionedGB = [Math]::Round($VMProvisionedGB,2)}ELSE{$VMProvisionedGB = $null}
IF($VMProtectedBytes -ne $null){$VMProtectedGB = $VMProtectedBytes / 1000 / 1000 / 1000;$VMProtectedGB = [Math]::Round($VMProtectedGB,2)}ELSE{$VMProtectedGB = $null}
IF($VMLocalUsedBytes -ne $null){$VMLocalUsedGB = $VMLocalUsedBytes / 1000 / 1000 / 1000;$VMLocalUsedGB = [Math]::Round($VMLocalUsedGB,2)}ELSE{$VMLocalUsedGB = $null}
IF($VMReplicaUsedBytes -ne $null){$VMReplicaUsedGB = $VMReplicaUsedBytes / 1000 / 1000 / 1000;$VMReplicaUsedGB = [Math]::Round($VMReplicaUsedGB,2)}ELSE{$VMReplicaUsedGB = $null}
IF($VMArchiveUsedBytes -ne $null){$VMArchiveUsedGB = $VMArchiveUsedBytes / 1000 / 1000 / 1000;$VMArchiveUsedGB = [Math]::Round($VMArchiveUsedGB,2)}ELSE{$VMArchiveUsedGB = $null}
# Calculating dedupe for storage jockeys
IF(($VMProtectedBytes -gt 1) -and ($VMLocalSnapshots -gt 1)){$VMDedupeRatio = $VMProtectedBytes * $VMLocalSnapshots / $VMLocalUsedBytes;$VMDedupeRatio = [Math]::Round($VMDedupeRatio,2)}ELSE{$VMDedupeRatio = $null}
# Primary Rubrik cluster info
$VMRubrikCluster = $RSCVM.primaryClusterLocation.name
$VMRubrikClusterID = $RSCVM.primaryClusterLocation.id
# Creating object URL
$VMURL = Get-RSCObjectURL -ObjectType "NutanixVirtualMachine" -ObjectID $VMID
# Adding To Array
$Object = New-Object PSObject
$Object | Add-Member -MemberType NoteProperty -Name "RSCInstance" -Value $RSCInstance
# VM info
$Object | Add-Member -MemberType NoteProperty -Name "VM" -Value $VMName
$Object | Add-Member -MemberType NoteProperty -Name "VMID" -Value $VMID
$Object | Add-Member -MemberType NoteProperty -Name "VMCDMID" -Value $VMCDMID
$Object | Add-Member -MemberType NoteProperty -Name "VMUUID" -Value $VMUUID
$Object | Add-Member -MemberType NoteProperty -Name "AgentStatus" -Value $VMAgentStatus
$Object | Add-Member -MemberType NoteProperty -Name "AgentRegistered" -Value $VMAgentRegistered
# OSType - not working as of 04/19/23 - API returns nothing for every AHV VM
# $Object | Add-Member -MemberType NoteProperty -Name "OSType" -Value $VMGuestOSType
# Protection
$Object | Add-Member -MemberType NoteProperty -Name "SLADomain" -Value $VMSLADomain
$Object | Add-Member -MemberType NoteProperty -Name "SLADomainID" -Value $VMSLADomainID
$Object | Add-Member -MemberType NoteProperty -Name "SLAAssignment" -Value $VMSLAAssignment
$Object | Add-Member -MemberType NoteProperty -Name "SLAPaused" -Value $VMSLAPaused
$Object | Add-Member -MemberType NoteProperty -Name "ProtectedOn" -Value $VMProtectionDateUTC
$Object | Add-Member -MemberType NoteProperty -Name "PendingFirstFull" -Value $VMWaitingForFirstFull
$Object | Add-Member -MemberType NoteProperty -Name "IsRelic" -Value $VMIsRelic
# VM disks - not working as of 04/19/23 - API returns nothing for every AHV VM
# $Object | Add-Member -MemberType NoteProperty -Name "Disks" -Value $VMVirtualDisksCount
# $Object | Add-Member -MemberType NoteProperty -Name "DisksExcluded" -Value $VMVirtualDisksExcludedCount
# Storage usage
$Object | Add-Member -MemberType NoteProperty -Name "ProvisionedGB" -Value $VMProvisionedGB
$Object | Add-Member -MemberType NoteProperty -Name "ProtectedGB" -Value $VMProtectedGB
$Object | Add-Member -MemberType NoteProperty -Name "LocalUsedGB" -Value $VMLocalUsedGB
$Object | Add-Member -MemberType NoteProperty -Name "ReplicaUsedGB" -Value $VMReplicaUsedGB
$Object | Add-Member -MemberType NoteProperty -Name "ArchiveUsedGB" -Value $VMArchiveUsedGB
$Object | Add-Member -MemberType NoteProperty -Name "DedupeRatio" -Value $VMDedupeRatio
# VM snapshots
$Object | Add-Member -MemberType NoteProperty -Name "OnDemandSnapshots" -Value $VMOnDemandSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "LocalSnapshots" -Value $VMLocalSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "ReplicatedSnapshots" -Value $VMReplicaSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "ArchivedSnapshots" -Value $VMArchiveSnapshots
# Snapshot dates
$Object | Add-Member -MemberType NoteProperty -Name "LatestSnapshotUTC" -Value $VMSnapshotDateUTC
$Object | Add-Member -MemberType NoteProperty -Name "LatestSnapshotUTCAgeHours" -Value $VMSnapshotHoursSince
$Object | Add-Member -MemberType NoteProperty -Name "ReplicatedSnapshotUTC" -Value $VMReplicatedSnapshotDateUTC
$Object | Add-Member -MemberType NoteProperty -Name "ReplicatedSnapshotUTCAgeHours" -Value $VMReplicatedSnapshotHoursSince
$Object | Add-Member -MemberType NoteProperty -Name "ArchivedSnapshotUTC" -Value $VMArchiveSnapshotDateUTC
$Object | Add-Member -MemberType NoteProperty -Name "ArchivedSnapshotUTCAgeHours" -Value $VMArchiveSnapshotHoursSince
$Object | Add-Member -MemberType NoteProperty -Name "OldestSnapshotUTC" -Value $VMOldestSnapshotDateUTC
$Object | Add-Member -MemberType NoteProperty -Name "OldestSnapshotUTCAgeDays" -Value $VMOldestSnapshotDaysSince
# VM note info
$Object | Add-Member -MemberType NoteProperty -Name "LatestRSCNote" -Value $VMNote
$Object | Add-Member -MemberType NoteProperty -Name "LatestNoteCreator" -Value $VMNoteCreator
$Object | Add-Member -MemberType NoteProperty -Name "LatestNoteDateUTC" -Value $VMNoteCreatedUTC
# Misc info
$Object | Add-Member -MemberType NoteProperty -Name "Consistency" -Value $VMConsistency
$Object | Add-Member -MemberType NoteProperty -Name "PreBackupScript" -Value $VMPreBackupScriptEnabled
$Object | Add-Member -MemberType NoteProperty -Name "PostBackupScript" -Value $VMPostBackupScriptEnabled
# Rubrik cluster info
$Object | Add-Member -MemberType NoteProperty -Name "ObjectID" -Value $VMID
$Object | Add-Member -MemberType NoteProperty -Name "RubrikCluster" -Value $VMRubrikCluster
$Object | Add-Member -MemberType NoteProperty -Name "RubrikClusterID" -Value $VMRubrikClusterID
# VM Location information
$Object | Add-Member -MemberType NoteProperty -Name "VMCluster" -Value $VMClusterName
$Object | Add-Member -MemberType NoteProperty -Name "VMClusterID" -Value $VMClusterID
# Mgmt URL
$Object | Add-Member -MemberType NoteProperty -Name "URL" -Value $VMURL
# Adding
$RSCVMs.Add($Object) | Out-Null
# End of for each object below
}
# End of for each object above

# Returning array
Return $RSCVMs
# End of function
}