Public/Get-UTCMDrift.ps1
|
function Get-UTCMDrift { <# .SYNOPSIS Retrieves configuration drifts from the UTCM API. .DESCRIPTION Queries GET /beta/admin/configurationManagement/configurationDrifts for server-side property-level drift data. Returns granular information about which properties drifted, their current vs. desired values, and the drift status. This is far more detailed than client-side snapshot comparison — the API provides per-property currentValue/desiredValue pairs and active/fixed status tracking. .PARAMETER MonitorId Filter drifts to a specific monitor by its GUID. .PARAMETER Status Filter by drift status: active, fixed. .PARAMETER ResourceType Filter by resource type (e.g., microsoft.exchange.accepteddomain). .PARAMETER Top Limit to the N most recent drifts (client-side). .PARAMETER IncludeDetails Include driftedProperties and resourceInstanceIdentifier (returned only on $select). .PARAMETER AsJson Return results as a JSON string instead of objects. .OUTPUTS PSObject collection representing configurationDrift objects. .EXAMPLE Get-UTCMDrift .EXAMPLE Get-UTCMDrift -Status active -IncludeDetails .EXAMPLE Get-UTCMDrift -MonitorId 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' -AsJson .EXAMPLE Get-UTCMDrift -ResourceType 'microsoft.exchange.accepteddomain' -IncludeDetails #> [CmdletBinding()] param( [ValidateScript({ if (-not (Validate-Guid $_)) { throw "MonitorId '$_' is not a valid GUID." } $true })] [string] $MonitorId, [ValidateSet('active','fixed')] [string] $Status, [string] $ResourceType, [int] $Top = 0, [switch] $IncludeDetails, [switch] $AsJson ) if (Get-Command -Name Ensure-GraphConnection -ErrorAction SilentlyContinue) { Ensure-GraphConnection -ReadOnly } # Build $select $selectList = @('id','monitorId','tenantId','resourceType','baselineResourceDisplayName','firstReportedDateTime','status') if ($IncludeDetails) { $selectList += @('driftedProperties','resourceInstanceIdentifier') } # Build $filter $filters = @() if ($MonitorId) { $filters += "monitorId eq '$MonitorId'" } if ($Status) { $filters += "status eq '$Status'" } if ($ResourceType) { $filters += "resourceType eq '$ResourceType'" } # Assemble querystring $qs = @() $qs += "`$select=" + [System.Uri]::EscapeDataString(($selectList -join ',')) if ($filters.Count -gt 0) { $qs += "`$filter=" + [System.Uri]::EscapeDataString(($filters -join ' and ')) } $uri = $script:ConfigurationDriftsUri + '?' + ($qs -join '&') # Page through results $all = @() do { $page = Invoke-GraphRequestWithRetry -Method 'GET' -Uri $uri if ($page.value) { $all += $page.value } $uri = $null if ($page -is [System.Collections.IDictionary]) { if ($page.ContainsKey('@odata.nextLink')) { $uri = $page['@odata.nextLink'] } } elseif ($page.PSObject.Properties.Match('@odata.nextLink').Count) { $uri = $page.'@odata.nextLink' } } while ($uri) # Sort by firstReportedDateTime descending $sorted = $all | Sort-Object firstReportedDateTime -Descending if ($Top -gt 0) { $sorted = $sorted | Select-Object -First $Top } if ($AsJson) { return ($sorted | ConvertTo-Json -Depth 20) } if ($IncludeDetails) { return $sorted } return ($sorted | Select-Object id, monitorId, resourceType, baselineResourceDisplayName, firstReportedDateTime, status) } |