Functions/Get-RSCObject/Get-RSCObjectDetail.ps1

################################################
# Creating the Get-RSCObjectDetail function
################################################
Function Get-RSCObjectDetail {

<#
.SYNOPSIS
A Rubrik Security Cloud (RSC) Reporting Module Function that returns all the data for the objectID available on the snappableConnection API.
 
.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.
.LINK
GraphQL schema reference: https://rubrikinc.github.io/rubrik-api-documentation/schema/reference
 
.PARAMETER ObjectID
A valid ObjectID in RSC, use Get-RSCObjects to obtain.
.PARAMETER MaxSnapshots
Uses 30 by default unless specified otherwise with this param.
 
.OUTPUTS
Returns an array of all the available information on the GraphQL endpoint in a uniform and usable format.
 
.EXAMPLE
Get-RSCObjectDetail -ObectID "32ffrferf-erferf-erferfe"
This example returns all the info available on the API for the ObjectID specified.
 
.NOTES
Author: Joshua Stenhouse
Date: 08/20/2024
#>

################################################
# Paramater Config
################################################
[CmdletBinding(DefaultParameterSetName = "List")]
Param(
      [Parameter(
          ParameterSetName = "ObjectID",
          Mandatory = $true, 
          ValueFromPipelineByPropertyName = $true
      )]
      [String]$ObjectID
  )

# Example: $ObjectSnapshots= Get-RSCObjectSnapshots -ObjectID "$ObjectID"

################################################
# 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
################################################
# Running Main Function
################################################
$RSCGraphQL = @{"operationName" = "snappableConnection";

"variables" = @{
    "filter" = @{
        "objectFid" = "$ObjectID"
}
};

"query" = "query snappableConnection(`$filter: SnappableFilterInput) {
  snappableConnection(filter: `$filter) {
    edges {
      node {
        id
        fid
        name
        slaDomain {
          id
          name
        }
        awaitingFirstFull
        cluster {
          id
          name
        }
        lastSnapshot
        localSnapshots
        localStorage
        location
        logicalBytes
        logicalDataReduction
        missedSnapshots
        localSlaSnapshots
        localProtectedData
        localOnDemandSnapshots
        localMeteredData
        localEffectiveStorage
        latestReplicationSnapshot
        latestArchivalSnapshot
        lastSnapshotLogicalBytes
        dataReduction
        complianceStatus
        archivalComplianceStatus
        archivalSnapshotLag
        archiveSnapshots
        archiveStorage
        objectState
        objectType
        physicalBytes
        protectedOn
        protectionStatus
        provisionedBytes
        pullTime
        replicaSnapshots
        replicaStorage
        replicationComplianceStatus
        replicationSnapshotLag
        sourceProtocol
        totalSnapshots
        transferredBytes
        usedBytes
        orgId
        workloadOrg {
          fullName
          id
          name
        }
      }
    }
  }
}"

}
################################################
# API Call To RSC GraphQL URI
################################################
# Querying API
Try
{
$ObjectResponse = Invoke-RestMethod -Method POST -Uri $RSCGraphqlURL -Headers $RSCSessionHeader -Body $($RSCGraphQL | ConvertTo-JSON -Depth 10)
$RSCObject = $ObjectResponse.data.snappableConnection.edges.node
}
Catch
{
# If error nulling as objectID not found
$RSCObject = $null
}
# Breaking if objectID not found
IF($RSCObject -eq $null)
{
Write-Error "ERROR: ObjectID not found, check and try again.."
Start-Sleep 2
Break
}
################################################
# Getting & Converting Object Data
################################################
# Creating array
$RSCObjects = [System.Collections.ArrayList]@()
# Setting variables
$ObjectCDMID = $RSCObject.id
$ObjectID = $RSCObject.fid
$ObjectName = $RSCObject.name
$ObjectComplianceStatus = $RSCObject.complianceStatus
$ObjectLocation = $RSCObject.location
$ObjectType = $RSCObject.objectType
$ObjectSLADomainInfo = $RSCObject.slaDomain
$ObjectSLADomain = $ObjectSLADomainInfo.name
$ObjectSLADomainID = $ObjectSLADomainInfo.id
$ObjectTotalSnapshots = $RSCObject.totalSnapshots
$ObjectLocalSnapshots = $RSCObject.localSnapshots
$ObjectLastSnapshot = $RSCObject.lastSnapshot
$ObjectReplicatedSnapshots = $RSCObject.replicaSnapshots
$ObjectArchivedSnapshots = $RSCObject.archiveSnapshots
$ObjectPendingFirstFull = $RSCObject.awaitingFirstFull
$ObjectProtectionStatus = $RSCObject.protectionStatus
$ObjectProtectedOn = $RSCObject.protectedOn
$ObjectLastUpdated = $RSCObject.pulltime
$ObjectClusterInfo = $RSCObject.cluster
$ObjectClusterID = $ObjectClusterInfo.id
$ObjectClusterName = $ObjectClusterInfo.name
$ObjectLastReplicatedSnapshot = $RSCObject.latestReplicationSnapshot
$ObjectLastArhiveSnapshot = $RSCObject.latestArchivalSnapshot
# Getting current time
$UTCDateTime = [System.DateTime]::UtcNow
# Converting UNIX times if not null
IF($ObjectProtectedOn -ne $null){$ObjectProtectedOn = Convert-RSCUNIXTime $ObjectProtectedOn}
IF($ObjectLastSnapshot -ne $null){$ObjectLastSnapshot = Convert-RSCUNIXTime $ObjectLastSnapshot}
IF($ObjectLastUpdated -ne $null){$ObjectLastUpdated = Convert-RSCUNIXTime $ObjectLastUpdated}
IF($ObjectLastReplicatedSnapshot -ne $null){$ObjectLastReplicatedSnapshot = Convert-RSCUNIXTime $ObjectLastReplicatedSnapshot}
IF($ObjectLastArhiveSnapshot -ne $null){$ObjectLastArhiveSnapshot = Convert-RSCUNIXTime $ObjectLastArhiveSnapshot}
# If last snapshot not null, calculating hours since
IF($ObjectLastSnapshot -ne $null)
{
$ObjectSnapshotGap = New-Timespan -Start $ObjectLastSnapshot -End $UTCDateTime
$ObjectSnapshotGapHours = $ObjectSnapshotGap.TotalHours
$ObjectSnapshotGapHours = [Math]::Round($ObjectSnapshotGapHours, 1)
}
ELSE
{
$ObjectSnapshotGapHours = $null    
}
# Overriding Polaris in cluster name
IF($ObjectClusterName -eq "Polaris"){$ObjectClusterName = "RSC-Native"}
# Overriding location to RSC if null
IF($ObjectLocation -eq ""){
# No account info in location for cloud native EC2/AWS/GCP etc, so for now just saying the cloud
IF($ObjectType -match "Azure"){$ObjectLocation = "Azure"}
IF($ObjectType -match "Ec2Instance"){$ObjectLocation = "AWS"}
IF($ObjectType -match "Gcp"){$ObjectLocation = "GCP"}
}
# Getting object URL
$ObjectURL = Get-RSCObjectURL -ObjectType $ObjectType -ObjectID $ObjectID
# Getting SLA domain & replication info
$RSCSLADomainInfo = $RSCSLADomains | Where-Object {$_.SLADomainID -eq $ObjectSLADomainID}
IF($RSCSLADomainInfo.Replication -eq $True){$ObjectISReplicated = $TRUE}ELSE{$ObjectISReplicated = $FALSE}
$ObjectReplicationTargetClusterID = $RSCSLADomainInfo.ReplicationTargetClusterID
# If replicated, determining if source or target
IF($ObjectISReplicated -eq $TRUE)
{
# Main rule, matching cluster
IF($ObjectClusterID -eq $ObjectReplicationTargetClusterID){$ObjectReplicaType = "Target"}ELSE{$ObjectReplicaType = "Source"}
}
ELSE
{
$ObjectReplicaType = "N/A"
}
# Deciding if object should be reported on for snapshots/compliance
IF(($ObjectProtectionStatus -eq "Protected") -and ($ObjectReplicaType -ne "Target")){$ObjectReportOnCompliance = $TRUE}ELSE{$ObjectReportOnCompliance = $FALSE}
# Deciding if relic
IF($ObjectComplianceStatus -eq "NOT_APPLICABLE"){$ObjectIsRelic = $TRUE}ELSE{$ObjectIsRelic = $FALSE}
# Overridng $ObjectReportOnCompliance if relic
IF($ObjectIsRelic -eq $TRUE){$ObjectReportOnCompliance = $FALSE}
# Overriding if compliance is empty, as this means it's a replica target
IF($ObjectComplianceStatus -eq "EMPTY"){$ObjectReportOnCompliance = $FALSE}
# Data reduction stats
$DataReduction = $RSCObject.dataReduction
$LogicalDataReduction = $RSCObject.logicalDataReduction
# Getting storage stats
$physicalBytes = $RSCObject.physicalBytes
$transferredBytes = $RSCObject.transferredBytes
$logicalBytes = $RSCObject.logicalBytes
$replicaStorage = $RSCObject.replicaStorage
$archiveStorage = $RSCObject.archiveStorage
$lastSnapshotLogicalBytes = $RSCObject.lastSnapshotLogicalBytes
$localStorage = $RSCObject.localStorage
$localMeteredData = $RSCObject.localMeteredData
$usedBytes = $RSCObject.usedBytes
$provisionedBytes = $RSCObject.provisionedBytes
$localProtectedData = $RSCObject.localProtectedData
$localEffectiveStorage = $RSCObject.localEffectiveStorage
# Converting storage units
IF($physicalBytes -ne $null){$PhysicalGB = $physicalBytes / 1000 / 1000 / 1000}ELSE{$PhysicalGB = $null}
IF($transferredBytes -ne $null){$TransferredGB = $transferredBytes / 1000 / 1000 / 1000}ELSE{$TransferredGB = $null}
IF($logicalBytes -ne $null){$LogicalGB = $logicalBytes / 1000 / 1000 / 1000}ELSE{$LogicalGB = $null}
IF($replicaStorage -ne $null){$ReplicaStorageGB = $replicaStorage / 1000 / 1000 / 1000}ELSE{$ReplicaStorageGB = $null}
IF($archiveStorage -ne $null){$ArchiveStorageGB = $archiveStorage / 1000 / 1000 / 1000}ELSE{$ArchiveStorageGB = $null}
IF($lastSnapshotLogicalBytes -ne $null){$LastSnapshotLogicalGB = $lastSnapshotLogicalBytes / 1000 / 1000 / 1000}ELSE{$LastSnapshotLogicalGB = $null}
IF($localStorage -ne $null){$LocalStorageGB = $localStorage / 1000 / 1000 / 1000}ELSE{$LocalStorageGB = $null}
IF($localMeteredData -ne $null){$LocalMeteredDataGB = $localMeteredData / 1000 / 1000 / 1000}ELSE{$LocalMeteredDataGB = $null}
IF($usedBytes -ne $null){$UsedGB = $usedBytes / 1000 / 1000 / 1000}ELSE{$UsedGB = $null}
IF($provisionedBytes -ne $null){$ProvisionedGB = $provisionedBytes / 1000 / 1000 / 1000}ELSE{$ProvisionedGB = $null}
IF($localProtectedData -ne $null){$LocalProtectedGB = $localProtectedData / 1000 / 1000 / 1000}ELSE{$LocalProtectedGB = $null}
IF($localEffectiveStorage -ne $null){$LocalEffectiveStorageGB = $localEffectiveStorage / 1000 / 1000 / 1000}ELSE{$LocalEffectiveStorageGB = $null}
# Getting totals
$TotalUsedBytes = $localStorage + $archiveStorage + $replicaStorage
IF($TotalUsedBytes -ne $null){$TotalUsedGB = $TotalUsedBytes / 1000 / 1000 / 1000;$TotalUsedGB = [Math]::Round($TotalUsedGB,2)}ELSE{$TotalUsedGB = $null}
# Rounding
IF($TotalUsedGB -ne $null){$TotalUsedGB = [Math]::Round($TotalUsedGB,2)}
IF($PhysicalGB -ne $null){$PhysicalGB = [Math]::Round($PhysicalGB,2)}
IF($TransferredGB -ne $null){$TransferredGB = [Math]::Round($TransferredGB,2)}
IF($LogicalGB -ne $null){$LogicalGB = [Math]::Round($LogicalGB,2)}
IF($ReplicaStorageGB -ne $null){$ReplicaStorageGB = [Math]::Round($ReplicaStorageGB,2)}
IF($ArchiveStorageGB -ne $null){$ArchiveStorageGB = [Math]::Round($ArchiveStorageGB,2)}
IF($LastSnapshotLogicalGB -ne $null){$LastSnapshotLogicalGB = [Math]::Round($LastSnapshotLogicalGB,2)}
IF($LocalStorageGB -ne $null){$LocalStorageGB = [Math]::Round($LocalStorageGB,2)}
IF($LocalMeteredDataGB -ne $null){$LocalMeteredDataGB = [Math]::Round($LocalMeteredDataGB,2)}
IF($UsedGB -ne $null){$UsedGB = [Math]::Round($UsedGB,2)}
IF($ProvisionedGB -ne $null){$ProvisionedGB = [Math]::Round($ProvisionedGB,2)}
IF($LocalProtectedGB -ne $null){$LocalProtectedGB = [Math]::Round($LocalProtectedGB,2)}
IF($LocalProtectedGB -ne $null){$LocalProtectedGB = [Math]::Round($LocalProtectedGB,2)}
IF($LocalEffectiveStorageGB -ne $null){$LocalEffectiveStorageGB = [Math]::Round($LocalEffectiveStorageGB,2)}
# Adding To Array
$Object = New-Object PSObject
$Object | Add-Member -MemberType NoteProperty -Name "RSCInstance" -Value $RSCInstance
$Object | Add-Member -MemberType NoteProperty -Name "RubrikCluster" -Value $ObjectClusterName
$Object | Add-Member -MemberType NoteProperty -Name "RubrikClusterID" -Value $ObjectClusterID
$Object | Add-Member -MemberType NoteProperty -Name "Object" -Value $ObjectName
$Object | Add-Member -MemberType NoteProperty -Name "ObjectID" -Value $ObjectID
$Object | Add-Member -MemberType NoteProperty -Name "Type" -Value $ObjectType
$Object | Add-Member -MemberType NoteProperty -Name "Location" -Value $ObjectLocation
$Object | Add-Member -MemberType NoteProperty -Name "SLADomain" -Value $ObjectSLADomain
$Object | Add-Member -MemberType NoteProperty -Name "SLADomainID" -Value $ObjectSLADomainID
$Object | Add-Member -MemberType NoteProperty -Name "ProtectionStatus" -Value $ObjectProtectionStatus
$Object | Add-Member -MemberType NoteProperty -Name "ComplianceStatus" -Value $ObjectComplianceStatus
$Object | Add-Member -MemberType NoteProperty -Name "ReportOnCompliance" -Value $ObjectReportOnCompliance
$Object | Add-Member -MemberType NoteProperty -Name "ProtectedOn" -Value $ObjectProtectedOn
$Object | Add-Member -MemberType NoteProperty -Name "IsRelic" -Value $ObjectIsRelic
# Snapshot info
$Object | Add-Member -MemberType NoteProperty -Name "TotalSnapshots" -Value $ObjectTotalSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "LocalSnapshots" -Value $ObjectLocalSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "LastSnapshot" -Value $ObjectLastSnapshot
$Object | Add-Member -MemberType NoteProperty -Name "HoursSince" -Value $ObjectSnapshotGapHours
$Object | Add-Member -MemberType NoteProperty -Name "PendingFirstFull" -Value $ObjectPendingFirstFull
# Replication info
$Object | Add-Member -MemberType NoteProperty -Name "Replicated" -Value $ObjectISReplicated
$Object | Add-Member -MemberType NoteProperty -Name "ReplicaType" -Value $ObjectReplicaType
$Object | Add-Member -MemberType NoteProperty -Name "LastReplicatedSnapshot" -Value $ObjectLastReplicatedSnapshot
$Object | Add-Member -MemberType NoteProperty -Name "ReplicatedSnaphots" -Value $ObjectReplicatedSnapshots
# Archive info
$Object | Add-Member -MemberType NoteProperty -Name "LastArchivedSnapshot" -Value $ObjectLastArhiveSnapshot
$Object | Add-Member -MemberType NoteProperty -Name "ArchivedSnapshots" -Value $ObjectArchivedSnapshots
$Object | Add-Member -MemberType NoteProperty -Name "LastUpdated" -Value $ObjectLastUpdated
# Data reduction
$Object | Add-Member -MemberType NoteProperty -Name "DataReduction" -Value $DataReduction
$Object | Add-Member -MemberType NoteProperty -Name "LogicalDataReduction" -Value $LogicalDataReduction
# Storage stats in GB
$Object | Add-Member -MemberType NoteProperty -Name "TotalUsedGB" -Value $TotalUsedGB
$Object | Add-Member -MemberType NoteProperty -Name "ProtectedGB" -Value $PhysicalGB
$Object | Add-Member -MemberType NoteProperty -Name "LocalStorageGB" -Value $LocalStorageGB
$Object | Add-Member -MemberType NoteProperty -Name "TransferredGB" -Value $TransferredGB
$Object | Add-Member -MemberType NoteProperty -Name "LogicalGB" -Value $LogicalGB
$Object | Add-Member -MemberType NoteProperty -Name "ReplicaStorageGB" -Value $ReplicaStorageGB
$Object | Add-Member -MemberType NoteProperty -Name "ArchiveStorageGB" -Value $ArchiveStorageGB
$Object | Add-Member -MemberType NoteProperty -Name "LastSnapshotLogicalGB" -Value $LastSnapshotLogicalGB
$Object | Add-Member -MemberType NoteProperty -Name "LocalMeteredDataGB" -Value $LocalMeteredDataGB
$Object | Add-Member -MemberType NoteProperty -Name "UsedGB" -Value $UsedGB
$Object | Add-Member -MemberType NoteProperty -Name "ProvisionedGB" -Value $ProvisionedGB
$Object | Add-Member -MemberType NoteProperty -Name "LocalProtectedGB" -Value $LocalProtectedGB
$Object | Add-Member -MemberType NoteProperty -Name "LocalEffectiveStorageGB" -Value $LocalEffectiveStorageGB
# Storage stats in bytes
$Object | Add-Member -MemberType NoteProperty -Name "TotalUsedBytes" -Value $TotalUsedBytes
$Object | Add-Member -MemberType NoteProperty -Name "ProtectedBytes" -Value $physicalBytes
$Object | Add-Member -MemberType NoteProperty -Name "LocalStorageBytes" -Value $localStorage
$Object | Add-Member -MemberType NoteProperty -Name "TransferredBytes" -Value $transferredBytes
$Object | Add-Member -MemberType NoteProperty -Name "LogicalBytes" -Value $logicalBytes
$Object | Add-Member -MemberType NoteProperty -Name "ReplicaStorageBytes" -Value $replicaStorage
$Object | Add-Member -MemberType NoteProperty -Name "ArchiveStorageBytes" -Value $archiveStorage
$Object | Add-Member -MemberType NoteProperty -Name "LastSnapshotLogicalBytes" -Value $lastSnapshotLogicalBytes
$Object | Add-Member -MemberType NoteProperty -Name "LocalMeteredDataBytes" -Value $localMeteredData
$Object | Add-Member -MemberType NoteProperty -Name "UsedBytes" -Value $usedBytes
$Object | Add-Member -MemberType NoteProperty -Name "ProvisionedBytes" -Value $provisionedBytes
$Object | Add-Member -MemberType NoteProperty -Name "LocalProtectedBytes" -Value $localProtectedData
$Object | Add-Member -MemberType NoteProperty -Name "LocalEffectiveStorageBytes" -Value $localEffectiveStorage
# Misc
$Object | Add-Member -MemberType NoteProperty -Name "ObjectCDMID" -Value $ObjectCDMID
# URL
$Object | Add-Member -MemberType NoteProperty -Name "URL" -Value $ObjectURL
# Adding
$RSCObjects.Add($Object) | Out-Null

# Sample object IDs for testing
# $ObjectID = "a6dc29cb-dd15-540a-94c8-96977a943648"
# $ObjectID = "a6dc29cb-dd15-540a-94c8-96977a9436480-bb"

# Returning Result
Return $RSCObjects
}