Private/Graph/Get-DeviceSettingStatusData.ps1
|
# Copyright (c) 2026 Sandy Zeng. All rights reserved. # Source-available. All rights reserved. See LICENSE file. <# Get-DeviceSettingStatusData.ps1 — Retrieves per-setting status for a policy on a device. Author: Sandy Zeng Project: IntuneDiff Version History: 1.0.0 Initial release. #> function Get-DeviceSettingStatusData { <# .SYNOPSIS Returns per-setting status for a single policy applied to a device. .DESCRIPTION For a policy whose overall status on a device is Conflict or Error, the policy-level status does not tell which individual settings actually failed. This function calls reports/getConfigurationSettingsReport (paginated via skip/top) to obtain the status of every setting for the given policy/device/user. Returns an ordered hashtable keyed by a normalized setting name whose values are hashtables: @{ StatusText; SettingStatus; ErrorCode; SettingId; SettingInstanceId }. .PARAMETER PolicyId The configuration policy id to query. .PARAMETER DeviceId The Intune device id (GUID). .PARAMETER UserId The user id (GUID) from step-1 policy assignment data. For system-account rows, pass 00000000-0000-0000-0000-000000000000. #> [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param( [Parameter(Mandatory)] [string]$PolicyId, [Parameter(Mandatory)] [string]$DeviceId, [Parameter(Mandatory)] [string]$UserId ) if ($DeviceId -notmatch '^[0-9a-fA-F\-]{36}$') { throw "Invalid DeviceId format: '$DeviceId'. Expected a GUID." } $statusMap = @{ 0 = 'Succeeded'; 1 = 'Not applicable'; 2 = 'Succeeded'; 5 = 'Error'; 6 = 'Conflict' } if ([string]::IsNullOrWhiteSpace($UserId)) { throw "UserId is required for getConfigurationSettingsReport filtering." } $filter = "(PolicyId eq '$PolicyId') and (DeviceId eq '$DeviceId') and (UserId eq '$UserId')" $result = [ordered]@{} $pageSize = 50 $skip = 0 $totalRowCount = 0 $schema = @() $allValues = New-Object System.Collections.Generic.List[object] while ($true) { $body = @{ select = @('SettingName', 'SettingStatus', 'ErrorCode', 'SettingId', 'SettingInstanceId') filter = $filter skip = $skip search = '' top = $pageSize } $response = Invoke-IntuneDiffRequest -Method POST -Uri '/beta/deviceManagement/reports/getConfigurationSettingsReport' -Body $body if ($response -is [string]) { $response = $response | ConvertFrom-Json } if ($schema.Count -eq 0 -and $response.Schema) { $schema = $response.Schema } $pageValues = $response.Values if (-not $pageValues) { $pageValues = @() } if ($response.TotalRowCount) { $totalRowCount = [int]$response.TotalRowCount } if ($pageValues.Count -eq 0) { break } foreach ($row in $pageValues) { $allValues.Add($row) } $skip += $pageSize if ($totalRowCount -gt 0 -and $allValues.Count -ge $totalRowCount) { break } if ($pageValues.Count -lt $pageSize) { break } } foreach ($valueArray in $allValues) { $row = @($valueArray) $obj = @{} for ($i = 0; $i -lt $schema.Count; $i++) { $columnName = $schema[$i].Column $obj[$columnName] = $row[$i] } $settingName = [string]$obj['SettingName'] if (-not $settingName) { continue } $statusInt = if ($null -ne $obj['SettingStatus']) { [int]$obj['SettingStatus'] } else { 2 } $statusText = if ($statusMap.ContainsKey($statusInt)) { $statusMap[$statusInt] } else { "Status $statusInt" } $key = ConvertTo-NormalizedSettingName -Name $settingName $result[$key] = @{ StatusText = $statusText SettingStatus = $statusInt ErrorCode = $obj['ErrorCode'] SettingId = [string]$obj['SettingId'] SettingInstanceId = [string]$obj['SettingInstanceId'] } } return $result } function ConvertTo-NormalizedSettingName { <# .SYNOPSIS Normalizes a setting display name for matching report data against extracted settings. .DESCRIPTION The per-setting reports return the leaf setting name, while extracted settings use a full category > setting path. This helper reduces both to a comparable form: the leaf segment (text after the last ' > '), with a trailing '(Device)'/'(User)' scope suffix removed, trimmed and lower-cased. .PARAMETER Name The setting display name (leaf or full path). #> [CmdletBinding()] [OutputType([string])] param( [string]$Name ) if (-not $Name) { return '' } $leaf = $Name $sepIndex = $leaf.LastIndexOf(' > ') if ($sepIndex -ge 0) { $leaf = $leaf.Substring($sepIndex + 3) } $leaf = $leaf -replace '\s*\((Device|User)\)\s*$', '' return $leaf.Trim().ToLowerInvariant() } |