Functions/Get-RSC/Get-RSCSnapshotAnalytics.ps1
|
################################################ # Creating the Get-RSCSnapshotAnalytics function ################################################ Function Get-RSCSnapshotAnalytics { <# .SYNOPSIS A Rubrik Security Cloud (RSC) Reporting Module Function that returns the data threat analytics for the snapshot ID specified. .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. .OUTPUTS Returns an array of all the available information on the GraphQL endpoint in a uniform and usable format. .EXAMPLE Get-RSCSnapshotAnalytics -SnapshotID "48987e0e-cb80-56f0-ba03-df0aa75ec023" This example returns the data threat analytics for the snapshot ID specified. .NOTES Author: Joshua Stenhouse Date: 11/04/2025 #> ################################################ # Paramater Config ################################################ Param ( [Parameter(Mandatory=$true)]$SnapshotID ) ################################################ # 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" = "RadarInvestigationBrowseListQuery"; "variables" = @{ "snapshotId" = "$SnapshotID" "path" = "" "filter" = @{ "deltaType" = "NODES_CREATED","NODES_MODIFIED","NODES_DELETED" } "first" = 100 }; "query" = "query RadarInvestigationBrowseListQuery(`$after: String, `$filter: SnapshotDeltaFilterInput, `$first: Int, `$path: String!, `$searchPrefix: String, `$snapshotId: UUID!, `$quarantineFilters: [QuarantineFilter!], `$workloadFieldsArg: WorkloadFieldsInput) { snapshotFilesDeltaV2( after: `$after filter: `$filter first: `$first path: `$path searchPrefix: `$searchPrefix snapshotFid: `$snapshotId quarantineFilters: `$quarantineFilters workloadFieldsArg: `$workloadFieldsArg ) { edges { cursor node { file { absolutePath displayPath filename fileMode size path lastModified ...WorkloadFieldsFragment __typename } previousSnapshotQuarantineInfo { isQuarantined containsQuarantinedFiles __typename } childrenDeltas { deltaType deltaAmount __typename } selfDeltas { deltaType deltaAmount __typename } __typename } __typename } pageInfo { endCursor hasNextPage hasPreviousPage __typename } __typename } } fragment WorkloadFieldsFragment on SnapshotFile { workloadFields { o365Item { id metadata { objectType snapshotNum snappableId snappableType __typename } __typename } __typename } __typename }" } ################################################ # API Call To RSC GraphQL URI ################################################ # Querying API Try { $RSCGraphQLResponse = Invoke-RestMethod -Method POST -Uri $RSCGraphqlURL -Headers $RSCSessionHeader -Body $($RSCGraphQL | ConvertTo-JSON -Depth 10) $RSCGraphQLData = $RSCGraphQLResponse.data.snapshotFilesDeltaV2.edges.node } Catch { $ErrorMessage = $_.ErrorDetails; "ERROR: $ErrorMessage" } ################################################ # Processing GraphQL Data ################################################ # Creating array $ObjectSnapshotPaths = [System.Collections.ArrayList]@() # Processing paths ForEach ($SnapshotPath in $RSCGraphQLData) { # Setting variables $Path = $SnapshotPath.file.displayPath $PathType = $SnapshotPath.file.fileMode $LastModifiedUNIX = $SnapshotPath.file.lastModified $PathSizeBytes = $SnapshotPath.file.size # Converting date time object IF($LastModifiedUNIX -ne $null){$LastModified = Convert-RSCUNIXTime $LastModifiedUNIX}ELSE{$LastModified = $null} # Getting file analytics $FilesCreated = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "NODES_CREATED"} | Select-Object -ExpandProperty deltaAmount $FilesDeleted = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "NODES_DELETED"} | Select-Object -ExpandProperty deltaAmount $FilesModified = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "NODES_MODIFIED"} | Select-Object -ExpandProperty deltaAmount # Getting size analytics $CreatedBytes = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "BYTES_CREATED"} | Select-Object -ExpandProperty deltaAmount $DeletedBytes = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "BYTES_DELETED"} | Select-Object -ExpandProperty deltaAmount $ModifiedBytes = $SnapshotPath.childrenDeltas | Where-Object {$_.deltaType -eq "BYTES_MODIFIED"} | Select-Object -ExpandProperty deltaAmount # Converting sizes IF($PathSizeBytes -ne $null){$PathSizeGB = $PathSizeBytes / 1000 / 1000 / 1000}ELSE{$PathSizeGB = $null} IF($CreatedBytes -ne $null){$CreatedGB = $CreatedBytes / 1000 / 1000 / 1000}ELSE{$CreatedGB = $null} IF($DeletedBytes -ne $null){$DeletedGB = $DeletedBytes / 1000 / 1000 / 1000}ELSE{$DeletedGB = $null} IF($ModifiedBytes -ne $null){$ModifiedGB = $ModifiedBytes / 1000 / 1000 / 1000}ELSE{$ModifiedGB = $null} # Rounding IF($PathSizeGB -ne $null){$PathSizeGB = [Math]::Round($PathSizeGB,2)} IF($CreatedGB -ne $null){$CreatedGB = [Math]::Round($CreatedGB,2)} IF($DeletedGB -ne $null){$DeletedGB = [Math]::Round($DeletedGB,2)} IF($ModifiedGB -ne $null){$ModifiedGB = [Math]::Round($ModifiedGB,2)} # Calculating change rate percentage $TotalChangedBytes = $CreatedBytes + $ModifiedBytes $ChangeRate = $TotalChangedBytes / $PathSizeBytes * 100 IF($ChangeRate -ne $null){$ChangeRate = [Math]::Round($ChangeRate,2)} # Creating object $Object = New-Object PSObject $Object | Add-Member -MemberType NoteProperty -Name "RSCInstance" -Value $RSCInstance $Object | Add-Member -MemberType NoteProperty -Name "SnapshotID" -Value $SnapshotID $Object | Add-Member -MemberType NoteProperty -Name "Path" -Value $Path $Object | Add-Member -MemberType NoteProperty -Name "PathType" -Value $PathType $Object | Add-Member -MemberType NoteProperty -Name "LastModified" -Value $LastModified $Object | Add-Member -MemberType NoteProperty -Name "FilesCreated" -Value $FilesCreated $Object | Add-Member -MemberType NoteProperty -Name "FilesDeleted" -Value $FilesDeleted $Object | Add-Member -MemberType NoteProperty -Name "FilesModified" -Value $FilesModified $Object | Add-Member -MemberType NoteProperty -Name "PathSizeGB" -Value $PathSizeGB $Object | Add-Member -MemberType NoteProperty -Name "CreatedGB" -Value $CreatedGB $Object | Add-Member -MemberType NoteProperty -Name "DeletedGB" -Value $DeletedGB $Object | Add-Member -MemberType NoteProperty -Name "ModifiedGB" -Value $ModifiedGB $Object | Add-Member -MemberType NoteProperty -Name "PathSizeBytes" -Value $PathSizeBytes $Object | Add-Member -MemberType NoteProperty -Name "CreatedBytes" -Value $CreatedBytes $Object | Add-Member -MemberType NoteProperty -Name "DeletedBytes" -Value $DeletedBytes $Object | Add-Member -MemberType NoteProperty -Name "ModifiedBytes" -Value $ModifiedBytes $Object | Add-Member -MemberType NoteProperty -Name "TotalChangedBytes" -Value $TotalChangedBytes $Object | Add-Member -MemberType NoteProperty -Name "ChangeRatePC" -Value $ChangeRate # Adding to the array $ObjectSnapshotPaths.Add($Object) | Out-Null # End of for each path below } # End of for each path above # Creating array for snapshot result $ObjectSnapshotAnalytics = [System.Collections.ArrayList]@() # Summarizing data across all paths $TotalSnapshotPaths = $ObjectSnapshotPaths | Measure-Object | Select-Object -ExpandProperty Count # If not paths, snapshot has not been succesfully indexed IF($TotalSnapshotPaths -gt 0) { $TotalFilesCreated = $ObjectSnapshotPaths | Measure-Object -Sum FilesCreated | Select-Object -ExpandProperty Sum $TotalFilesDeleted = $ObjectSnapshotPaths | Measure-Object -Sum FilesDeleted | Select-Object -ExpandProperty Sum $TotalFilesModified = $ObjectSnapshotPaths | Measure-Object -Sum FilesModified | Select-Object -ExpandProperty Sum $TotalSizeBytes = $ObjectSnapshotPaths | Measure-Object -Sum PathSizeBytes | Select-Object -ExpandProperty Sum $TotalCreatedBytes = $ObjectSnapshotPaths | Measure-Object -Sum CreatedBytes | Select-Object -ExpandProperty Sum $TotalDeletedBytes = $ObjectSnapshotPaths | Measure-Object -Sum DeletedBytes | Select-Object -ExpandProperty Sum $TotalModifiedBytes = $ObjectSnapshotPaths | Measure-Object -Sum ModifiedBytes | Select-Object -ExpandProperty Sum $TotalChangedBytes = $ObjectSnapshotPaths | Measure-Object -Sum TotalChangedBytes | Select-Object -ExpandProperty Sum # Converting sizes IF($TotalSizeBytes -ne $null){$TotalSizeGB = $TotalSizeBytes / 1000 / 1000 / 1000}ELSE{$TotalSizeGB = $null} IF($TotalCreatedBytes -ne $null){$TotalCreatedGB = $TotalCreatedBytes / 1000 / 1000 / 1000}ELSE{$TotalCreatedGB = $null} IF($TotalDeletedBytes -ne $null){$TotalDeletedGB = $TotalDeletedBytes / 1000 / 1000 / 1000}ELSE{$TotalDeletedGB = $null} IF($TotalModifiedBytes -ne $null){$TotalModifiedGB = $TotalModifiedBytes / 1000 / 1000 / 1000}ELSE{$TotalModifiedGB = $null} # Rounding IF($TotalSizeGB -ne $null){$TotalSizeGB = [Math]::Round($TotalSizeGB,2)} IF($TotalCreatedGB -ne $null){$TotalCreatedGB = [Math]::Round($TotalCreatedGB,2)} IF($TotalDeletedGB -ne $null){$TotalDeletedGB = [Math]::Round($TotalDeletedGB,2)} IF($TotalModifiedGB -ne $null){$TotalModifiedGB = [Math]::Round($TotalModifiedGB,2)} # Calculating change rate percentage $TotalChangedBytes = $TotalCreatedBytes + $TotalModifiedBytes $ChangeRate = $TotalChangedBytes / $TotalSizeBytes * 100 IF($ChangeRate -ne $null){$ChangeRate = [Math]::Round($ChangeRate,2)} } ELSE { # Snapshot has not been indexed, nulling all values $TotalFilesCreated = $null $TotalFilesDeleted = $null $TotalFilesModified = $null $TotalSizeGB = $null $TotalCreatedGB = $null $TotalDeletedGB = $null $ModifiedGB = $null $ChangeRate = $null $TotalSizeBytes = $null $TotalCreatedBytes = $null $TotalDeletedBytes = $null $TotalModifiedBytes = $null $TotalChangedBytes = $null } # Creating object $Object = New-Object PSObject $Object | Add-Member -MemberType NoteProperty -Name "RSCInstance" -Value $RSCInstance $Object | Add-Member -MemberType NoteProperty -Name "SnapshotID" -Value $SnapshotID $Object | Add-Member -MemberType NoteProperty -Name "Paths" -Value $TotalSnapshotPaths $Object | Add-Member -MemberType NoteProperty -Name "FilesCreated" -Value $TotalFilesCreated $Object | Add-Member -MemberType NoteProperty -Name "FilesDeleted" -Value $TotalFilesDeleted $Object | Add-Member -MemberType NoteProperty -Name "FilesModified" -Value $TotalFilesModified $Object | Add-Member -MemberType NoteProperty -Name "SizeGB" -Value $TotalSizeGB $Object | Add-Member -MemberType NoteProperty -Name "CreatedGB" -Value $TotalCreatedGB $Object | Add-Member -MemberType NoteProperty -Name "DeletedGB" -Value $TotalDeletedGB $Object | Add-Member -MemberType NoteProperty -Name "ModifiedGB" -Value $ModifiedGB $Object | Add-Member -MemberType NoteProperty -Name "ChangeRatePC" -Value $ChangeRate $Object | Add-Member -MemberType NoteProperty -Name "SizeBytes" -Value $TotalSizeBytes $Object | Add-Member -MemberType NoteProperty -Name "CreatedBytes" -Value $TotalCreatedBytes $Object | Add-Member -MemberType NoteProperty -Name "DeletedBytes" -Value $TotalDeletedBytes $Object | Add-Member -MemberType NoteProperty -Name "ModifiedBytes" -Value $TotalModifiedBytes $Object | Add-Member -MemberType NoteProperty -Name "TotalChangedBytes" -Value $TotalChangedBytes # Adding to the array $ObjectSnapshotAnalytics.Add($Object) | Out-Null # Returning Result Return $ObjectSnapshotAnalytics } |