Private/Get-NSPEntraHardMatchTenantState.ps1
|
function Get-NSPEntraHardMatchTenantState { <# .SYNOPSIS Reads what hard-match checks need from the whole tenant, once. Read-only. .DESCRIPTION Any directory role counts, at any scope, not only the ones Microsoft calls privileged: a role holder is never a routine match. Group-held roles are expanded to the group's members. A failed role read throws, because an unknown role holder must not read as none. Not covered: a user who is only eligible for membership of a role-assignable group through PIM for Groups. Entra's own hard-match check still applies at sync. #> [CmdletBinding()] param([switch]$AssumeNoRoleEligibility) $roles = Get-NSPEntraPairingRoleState -AssumeNoRoleEligibility:$AssumeNoRoleEligibility $roleHolders = $roles.RoleHolders $eligible = $roles.EligibleHolders $warnings = [System.Collections.Generic.List[string]]::new() $blocks = [System.Collections.Generic.List[string]]::new() foreach ($warning in $roles.Warnings) { $warnings.Add($warning) } foreach ($block in $roles.Blocks) { $blocks.Add($block) } $deletedAnchors = @{} foreach ($user in @(Invoke-NSPGraphCollection -Uri 'directory/deletedItems/microsoft.graph.user?$select=id,onPremisesImmutableId&$top=999')) { if ($null -ne $user -and $user['onPremisesImmutableId']) { $deletedAnchors[[string]$user['onPremisesImmutableId']] = [string]$user['id'] } } # Reading this needs Global Administrator. If it is unreadable the write is safe but may achieve # nothing, because Entra then refuses the match at sync. So that is a warning, not a block. try { $settings = @((Invoke-NSPGraphRequest -Uri 'directory/onPremisesSynchronization')['value'] | Where-Object { $null -ne $_ }) if (-not $settings.Count) { $warnings.Add('The tenant has no on-premises synchronization settings yet, so its hard-match block could not be checked.') } foreach ($setting in $settings) { if ($setting['features']['blockCloudObjectTakeoverThroughHardMatchEnabled'] -eq $true) { $blocks.Add('The tenant has blockCloudObjectTakeoverThroughHardMatchEnabled on, so Entra would refuse every hard match. This module does not change that setting.') } } } catch { $warnings.Add('The tenant''s hard-match block could not be read; that needs Global Administrator. If it is on, Entra refuses the match at sync.') } [pscustomobject]@{ RoleHolders = $roleHolders EligibleHolders = $eligible DeletedAnchors = $deletedAnchors Blocks = @($blocks) Warnings = @($warnings) } } |