Functions/Get-RSCObject/Get-RSCObjectCompliance.ps1

################################################
# Creating the Get-RSCObjectCompliance function
################################################
Function Get-RSCObjectCompliance {
    
<#
.SYNOPSIS
A Rubrik Security Cloud (RSC) Reporting Module Function for getting compliance of backups per object.
 
.DESCRIPTION
This function checks if the object has a backup within the days to report specified and returns an array with the result.
 
.LINK
GraphQL schema reference: https://rubrikinc.github.io/rubrik-api-documentation/schema/reference
 
.PARAMETER ObjectID
A valid ObjectID of the protected object within RSC.
.PARAMETER DaysToReport
Number of days to report back, it will take a default backup window of 10am to 10sm, unless you specify differently with the param below.
.PARAMETER BackupWindowEndHour
The end hour of your backup window for consideration of a succesful backup. I.E 11am = 11
.PARAMETER BackupWindowEndminutes
The end minutes of your backup window for consideration of a succesful backup. I.E 11:30am = 30 + configuring the above.
 
.OUTPUTS
Returns an array of all the available information on the GraphQL endpoint in a uniform and usable format.
 
.EXAMPLE
Get-RSCObjectCompliance -ObjectID "dqwdqdoj-dqwdwd-wwwdwd-wdwd" -DaysToReport 5
This example checks if the object has a backup within the days to report specified.
 
.NOTES
Author: Joshua Stenhouse
Date: 05/11/2023
#>

################################################
# Paramater Config
################################################
Param ([Parameter(Mandatory=$true)]
  [String]$ObjectID,$DaysToReport,$BackupWindowStartHour,$BackupWindowEndminutes)

# Note: Backup window end hour & minutes controls when the compliance is calculated from. I.E 7 days back from 10am this morning to 10am yesterday.
# This is because checking a backup on a daily basis doesn't work, you could have a backup at 7am on Friday. Does that mean you have a backup of Friday?
# No, the only way to be sure you have a backup for Friday is to check if a backup exists between 10am Friday and 10am Saturday.

# Example: $ObjectCompliance = Get-RSCObjectCompliance -ObjectID "$ObjectID"

# Setting days to report to be 7 if null
IF($DaysToReport -eq $null){$DaysToReport = 7}

# Auto calculating $MaxSnapshots by maximum snapshots that would be allowed within window
$MaxSnapshots = $DaysToReport * 24

# Setting backup window start hour to be 8pm if null
IF($BackupWindowStartHour -eq $null){$BackupWindowStartHour = 20}

# Setting backup window start minutes to b 0 if null
IF($BackupWindowStartMinutes -eq $null){$BackupWindowStartMinutes = 0}

################################################
# 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
######################################################
# Creating Arrays & Getting Date
######################################################
# Array for storing & returning results
$ObjectCompliance = [System.Collections.ArrayList]@()
# Taking 1 day off as count starts at 0
$DaysToReportAdjusted = $DaysToReport - 1
# Creating range for days selected
$Days = 0..$DaysToReportAdjusted
# Creating array to store dates
$DateRanges = @()
# Getting date to determine compliance
$Window = Get-Date -Hour $BackupWindowStartHour -Minute $BackupWindowStartMinutes -Second 00
# Adding lag days
$Window = $Window.AddDays(-$DaysLag)
# For each Day getting date range
ForEach ($Day in $Days)
{
# Getting start date for range
$StartDate = $Window.AddDays(-$Day)
# Deciding if last day (used for SQL query)
IF ($Day -eq $DaysToReport)
{
$IsLastDay = $TRUE
}
ELSE
{
$IsLastDay = $FALSE
}
# Getting end date for range
$EndDate = $StartDate.AddDays(-1)
# Creating string for HTML report
$DateString = $StartDate.ToString("dd-MMM")
# Getting day in short format
$DateDay = $StartDate.ToString("ddd")
# Getting long format
$DateFullString = $StartDate.ToString("dd-MMM-yy")
# Adding array
$DateRange = New-Object PSObject
$DateRange | Add-Member -MemberType NoteProperty -Name "Day" -Value $Day
$DateRange | Add-Member -MemberType NoteProperty -Name "Date" -Value $DateFullString
$DateRange | Add-Member -MemberType NoteProperty -Name "DateStart" -Value $StartDate
$DateRange | Add-Member -MemberType NoteProperty -Name "DateEnd" -Value $EndDate
$DateRange | Add-Member -MemberType NoteProperty -Name "DateHTML" -Value $DateString
$DateRange | Add-Member -MemberType NoteProperty -Name "DayHTML" -Value $DateDay
$DateRange | Add-Member -MemberType NoteProperty -Name "IsLastDay" -Value $IsLastDay
$DateRanges += $DateRange
}
################################################
# Running Main Function
################################################
# Getting MSSQL DBs to override Object id with DBID as required for SnapshotOfASnappableConnection
$RSCMSSQLDBs = Get-RSCMSSQLDatabases
$RSCMSSQLDBIDs = $RSCMSSQLDBs | Select-Object DBID
# Checking if ID matches, if so, overriding
IF($RSCMSSQLDBIDs -match $ObjectID)
{
# ObjectID is an mssql DB, need to use the DAG ID instead (stupid design decision by MSSQL team)
$ObjectID = $RSCMSSQLDBs | Where-Object {$_.DBID -eq $ObjectID} | Select-Object -ExpandProperty DAGID
}
# Note: for "sortOrder" = use ASC for oldest snapshots first, DESC for newest snapshots first
$RSCGraphQL = @{"operationName" = "SnapshotOfASnappableConnection";

"variables" = @{
"workloadId" = "$ObjectID"
"sortOrder" = "DESC"
"first" = $MaxSnapshots
};

"query" = "query SnapshotOfASnappableConnection(`$workloadId: String!, `$first: Int, `$sortOrder: SortOrder) {
  snapshotOfASnappableConnection(workloadId: `$workloadId, first: `$first, sortOrder: `$sortOrder) {
    nodes {
      ... on CdmSnapshot {
        id
        date
        expirationDate
        __typename
      }
      ... on PolarisSnapshot {
        id
        date
        expirationDate
        __typename
      }
    }
  }
}"

}
################################################
# API Call To RSC GraphQL URI
################################################
# Querying API
Try
{
$ObjectSnapshotsResponse = Invoke-RestMethod -Method POST -Uri $RSCGraphqlURL -Headers $RSCSessionHeader -Body $($RSCGraphQL | ConvertTo-JSON -Depth 10)
$ObjectSnapshotsToProcess = $ObjectSnapshotsResponse.data.snapshotOfASnappableConnection.nodes
}
Catch
{
$ErrorMessage = $_.ErrorDetails; "ERROR: $ErrorMessage"
}
# Creating array
$ObjectSnapshots = [System.Collections.ArrayList]@()
# Processing snapshots
ForEach ($ObjectSnapshot in $ObjectSnapshotsToProcess)
{
# Getting snapshot data
$SnapshotDateUNIX = $ObjectSnapshot.date
$SnapshotID = $ObjectSnapshot.id
# Converting
$SnapshotDate = Convert-RSCUNIXTime $SnapshotDateUNIX
# Adding
$Object = New-Object PSObject
$Object | Add-Member -MemberType NoteProperty -Name "Date" -Value $SnapshotDate
$Object | Add-Member -MemberType NoteProperty -Name "SnapshotID" -Value $SnapshotID
$Object | Add-Member -MemberType NoteProperty -Name "ObjectID" -Value $ObjectID
$Object | Add-Member -MemberType NoteProperty -Name "MaxSnapshots" -Value $MaxSnapshots
$ObjectSnapshots.Add($Object) | Out-Null
}

##################################
# Calculating Backups For Each DateRange in DateRanges
##################################
# Getting backup compliance for each day
ForEach ($DateRange in $DateRanges)
{
# Setting variables
$Day = $DateRange.Day
$Date = $DateRange.Date
$DayHTML = $DateRange.DayHTML
$DateHTML = $DateRange.DateHTML
$DateRangeStart = $DateRange.DateStart
$DateRangeEnd = $DateRange.DateEnd
# Selecting record
$ObjectBackup = $ObjectSnapshots | Where-Object {(($_.Date -le $DateRangeStart) -and ($_.Date -ge $DateRangeEnd))} | Select-Object -First 1
$ObjectSnapshotID = $ObjectBackup.SnapshotID
$ObjectSnapshotDate = $ObjectBackup.Date
# Only calculating results if any backups exist, else setting to fails
IF ($ObjectBackup -eq $null)
{
$ObjectBackupDay = $FALSE
$ObjectBackupFoundDay = 0
$ObjectBackupNotFoundDay = 1
}
ELSE
{
# Setting backup found
$ObjectBackupFoundDay = 1
$ObjectBackupNotFoundDay = 0
$ObjectBackupDay = $TRUE
# End of bypass for no backups exist
}
# End of bypass for no backups exist
##################################
# Adding to ObjectComplianceDates array
##################################
$Object = New-Object PSObject
$Object | Add-Member -MemberType NoteProperty -Name "RSCInstance" -Value $RSCInstance
$Object | Add-Member -MemberType NoteProperty -Name "ObjectID" -Value $ObjectID
$Object | Add-Member -MemberType NoteProperty -Name "DayCounter" -Value $Day
$Object | Add-Member -MemberType NoteProperty -Name "BackupDate" -Value $Date
$Object | Add-Member -MemberType NoteProperty -Name "RangeStart" -Value $DateRangeStart
$Object | Add-Member -MemberType NoteProperty -Name "Snapshot" -Value $ObjectSnapshotDate
$Object | Add-Member -MemberType NoteProperty -Name "RangeEnd" -Value $DateRangeEnd
$Object | Add-Member -MemberType NoteProperty -Name "BackupFound" -Value $ObjectBackupFoundDay
$Object | Add-Member -MemberType NoteProperty -Name "BackupNotFound" -Value $ObjectBackupNotFoundDay
$Object | Add-Member -MemberType NoteProperty -Name "DayLabel" -Value $DayHTML
$Object | Add-Member -MemberType NoteProperty -Name "DateLabel" -Value $DateHTML
$Object | Add-Member -MemberType NoteProperty -Name "SnapshotID" -Value $ObjectSnapshotID
# Storing in array
$ObjectCompliance.Add($Object) | Out-Null
# End of for each date in dateranges below
}
# End of for each date in dateranges below

# Returning Result
Return $ObjectCompliance
}