Private/Compare-IntuneAccessSnapshotCollection.ps1
|
function Get-IntuneAccessSnapshotRecordKey { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [object] $Record, [Parameter(Mandatory)] [string] $EntityType ) switch ($EntityType) { 'Administrator' { return [string] (Get-IntuneAccessProperty (Get-IntuneAccessProperty $Record 'User') 'Id') } 'Membership' { return "$([string] (Get-IntuneAccessProperty (Get-IntuneAccessProperty $Record 'User') 'Id'))|$([string] (Get-IntuneAccessProperty $Record 'GroupId'))" } 'Permission' { return [string] (Get-IntuneAccessProperty $Record 'RawAction') } 'DeploymentOutcome' { return "$([string] (Get-IntuneAccessProperty $Record 'WorkloadId'))|$([string] (Get-IntuneAccessProperty $Record 'Id'))" } default { return [string] (Get-IntuneAccessProperty $Record 'Id') } } } function Get-IntuneAccessSnapshotRecordName { [CmdletBinding()] [OutputType([string])] param([Parameter(Mandatory)] [object] $Record) foreach ($propertyName in @('Name', 'DisplayName', 'WorkloadName', 'DeviceName', 'UserPrincipalName', 'RawAction', 'Id')) { $value = [string] (Get-IntuneAccessProperty $Record $propertyName '') if (-not [string]::IsNullOrWhiteSpace($value)) { return $value } } $user = Get-IntuneAccessProperty $Record 'User' if ($null -ne $user) { return [string] (Get-IntuneAccessProperty $user 'UserPrincipalName' (Get-IntuneAccessProperty $user 'DisplayName' 'Administrator')) } 'Unnamed record' } function Compare-IntuneAccessSnapshotCollection { [CmdletBinding()] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Before, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $After, [Parameter(Mandatory)] [string] $EntityType ) $beforeByKey = @{} $afterByKey = @{} foreach ($record in $Before) { if ($null -eq $record) { continue } $key = Get-IntuneAccessSnapshotRecordKey -Record $record -EntityType $EntityType if (-not [string]::IsNullOrWhiteSpace($key)) { $beforeByKey[$key] = $record } } foreach ($record in $After) { if ($null -eq $record) { continue } $key = Get-IntuneAccessSnapshotRecordKey -Record $record -EntityType $EntityType if (-not [string]::IsNullOrWhiteSpace($key)) { $afterByKey[$key] = $record } } $changes = [Collections.Generic.List[object]]::new() foreach ($key in @($beforeByKey.Keys + $afterByKey.Keys | Sort-Object -Unique)) { $hasBefore = $beforeByKey.ContainsKey($key) $hasAfter = $afterByKey.ContainsKey($key) $beforeRecord = if ($hasBefore) { $beforeByKey[$key] } else { $null } $afterRecord = if ($hasAfter) { $afterByKey[$key] } else { $null } $changeType = if (-not $hasBefore) { 'Added' } elseif (-not $hasAfter) { 'Removed' } else { 'Modified' } $changedProperties = @() if ($hasBefore -and $hasAfter) { $propertyNames = @($beforeRecord.PSObject.Properties.Name + $afterRecord.PSObject.Properties.Name | Sort-Object -Unique) $changedProperties = @($propertyNames | Where-Object { $beforeValue = Get-IntuneAccessProperty $beforeRecord $_ $afterValue = Get-IntuneAccessProperty $afterRecord $_ ($beforeValue | ConvertTo-Json -Depth 30 -Compress) -cne ($afterValue | ConvertTo-Json -Depth 30 -Compress) }) if ($changedProperties.Count -eq 0) { continue } } $displayRecord = if ($hasAfter) { $afterRecord } else { $beforeRecord } $changes.Add([PSCustomObject] @{ PSTypeName = 'IntuneAccess.SnapshotChange' EntityType = $EntityType ChangeType = $changeType Id = $key Name = Get-IntuneAccessSnapshotRecordName -Record $displayRecord ChangedProperties = $changedProperties Before = $beforeRecord After = $afterRecord }) } $changes.ToArray() } function Add-IntuneAccessSnapshotImpact { [CmdletBinding()] param( [Parameter(Mandatory)] [object] $Change, [Parameter(Mandatory)] [object] $SnapshotData ) $record = if ($null -ne $Change.After) { $Change.After } else { $Change.Before } $impactState = 'NotEvaluated' $impactSummary = 'The potentially affected population cannot be proved from the snapshot.' $potentialUsers = $null $potentialDevices = $null if ($Change.EntityType -eq 'WorkloadAssignment') { $targetType = [string] (Get-IntuneAccessProperty $record 'TargetType') switch ($targetType) { { $_ -in @('All users', 'All licensed users', 'AllUsers') } { $impactState = 'BroadTarget' $potentialUsers = @(Get-IntuneAccessProperty $SnapshotData 'ManagedUsers' @()).Count $impactSummary = "All users target; $potentialUsers managed user records were present in the newer snapshot." } { $_ -in @('All devices', 'AllDevices') } { $impactState = 'BroadTarget' $potentialDevices = @(Get-IntuneAccessProperty $SnapshotData 'ManagedDevices' @()).Count $impactSummary = "All devices target; $potentialDevices managed device records were present in the newer snapshot." } default { $targetId = [string] (Get-IntuneAccessProperty $record 'TargetId') $impactSummary = "Target $targetType $targetId changed; group membership and filter evaluation are not asserted by this snapshot." } } } elseif ($Change.EntityType -eq 'RoleAssignment') { $impactSummary = 'Administrative access may have changed for members of the connected Admin Groups.' } elseif ($Change.EntityType -eq 'ScopeTag') { $scopeTagId = [string] (Get-IntuneAccessProperty $record 'Id') $workloads = @(Get-IntuneAccessProperty $SnapshotData 'WorkloadObjects' @() | Where-Object { $scopeTagId -in @(Get-IntuneAccessProperty $_ 'ScopeTagIds' @()) }) $impactState = if ($workloads.Count -gt 0) { 'ObservedRelationship' } else { 'NotEvaluated' } $impactSummary = "$($workloads.Count) collected workloads reference this Scope Tag." } $Change | Add-Member -NotePropertyName ImpactState -NotePropertyValue $impactState -Force $Change | Add-Member -NotePropertyName ImpactSummary -NotePropertyValue $impactSummary -Force $Change | Add-Member -NotePropertyName PotentialUserCount -NotePropertyValue $potentialUsers -Force $Change | Add-Member -NotePropertyName PotentialDeviceCount -NotePropertyValue $potentialDevices -Force $Change } |