Private/AuthContext/Processing/Resolve-AndProjectPIMPolicies.ps1
|
function Resolve-AndProjectPIMPolicies { <# .SYNOPSIS Resolves role names for PIM policies and projects directory and group policy exports. .DESCRIPTION Encapsulates the role name resolution loop and export projection previously inline in the core orchestrator. Maintains identical progress messages and object schema. Returns two arrays corresponding to directory and group exports. .PARAMETER DirectoryPolicies PIM policies scoped to Entra directory roles (already converted via Convert-PIMPoliciesToAuthContext). .PARAMETER GroupPolicies PIM policies scoped to managed groups (already converted via Convert-PIMPoliciesToAuthContext). .PARAMETER AllPolicies Union of directory + group policies used to determine unique RoleDefinitionId values. .PARAMETER GroupsById Hashtable of GroupObjectId -> DisplayName for resolving group names in projection when absent. .PARAMETER NoProgress Switch to suppress Write-Progress output identical to upstream behavior. .OUTPUTS Two arrays: [0] directory export objects, [1] group export objects. #> [CmdletBinding()] param( [Parameter(Mandatory)] [object[]] $DirectoryPolicies, [Parameter(Mandatory)] [object[]] $GroupPolicies, [Parameter(Mandatory)] [object[]] $AllPolicies, [Parameter()] [hashtable] $GroupsById, [switch] $NoProgress ) $dirExport = @(); $grpExport = @() if (-not $AllPolicies -or ($AllPolicies | Measure-Object).Count -eq 0) { return , @($dirExport, $grpExport) } $uniqueRoleIds = $AllPolicies | Where-Object { $_.RoleDefinitionId } | Select-Object -Expand RoleDefinitionId -Unique if (-not $NoProgress) { Write-Progress -Id 6 -Activity 'PIM Policies' -Status ('Role mapping for {0} unique role ids' -f ($uniqueRoleIds.Count)) -PercentComplete 85 } $roleTotal = ($uniqueRoleIds | Measure-Object).Count $roleIndex = 0 $roleMap = @{} foreach ($roleDefIdVal in $uniqueRoleIds) { $roleIndex++ $pct = if ($roleTotal -gt 0) { [int](($roleIndex / $roleTotal) * 100) } else { 100 } $friendlyDisplay = if ($roleMap.ContainsKey($roleDefIdVal)) { $roleMap[$roleDefIdVal] } else { $roleDefIdVal } if (-not $NoProgress) { Write-Progress -Id 8 -Activity 'PIM Role Mapping' -Status ('Resolving role {0}/{1}: {2}' -f $roleIndex, $roleTotal, $friendlyDisplay) -PercentComplete $pct } if ($roleDefIdVal -notmatch '^[0-9a-fA-F-]{8}-') { $lower = $roleDefIdVal.ToLower() if ($lower -eq 'member') { $roleMap[$roleDefIdVal] = 'Group Member' } elseif ($lower -eq 'owner') { $roleMap[$roleDefIdVal] = 'Group Owner' } continue } try { $roleDefinitionResponse = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/$roleDefIdVal?`$select=id,displayName" -ErrorAction Stop if ($roleDefinitionResponse.id) { $roleMap[$roleDefinitionResponse.id] = $roleDefinitionResponse.displayName; continue } } catch {} try { $roleTemplateResponse = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/directoryRoleTemplates/$roleDefIdVal?`$select=id,displayName" -ErrorAction Stop if ($roleTemplateResponse.id) { $roleMap[$roleTemplateResponse.id] = $roleTemplateResponse.displayName; continue } } catch {} try { $roleTemplateFilter = [uri]::EscapeDataString("roleTemplateId eq '$roleDefIdVal'") $directoryRolesResponse = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/directoryRoles?`$filter=$roleTemplateFilter&`$select=id,displayName" -ErrorAction Stop if ($directoryRolesResponse.value -and $directoryRolesResponse.value.Count -gt 0) { $roleMap[$roleDefIdVal] = $directoryRolesResponse.value[0].displayName; continue } } catch {} try { $resolvedRoleName = Resolve-DirectoryRoleName -RoleId $roleDefIdVal if ($resolvedRoleName) { $roleMap[$roleDefIdVal] = $resolvedRoleName; continue } } catch {} } if (-not $NoProgress) { Write-Progress -Id 8 -Activity 'PIM Role Mapping' -Completed -Status 'Role name resolution complete' } $projectPim = { param($items) $out = @() foreach ($item in $items) { # Collect potential auth context id properties (robust to upstream variations) $acCandidates = @() foreach ($propName in 'AuthContextClassRefs', 'AuthContextIds', 'AuthContextClassReferences', 'AuthContextClassReferenceIds', 'RequiredAuthContextIds', 'AuthContextId') { if ($item.PSObject.Properties.Name -contains $propName) { $val = $item.$propName if ($val) { $acCandidates += $val } } } $acIdOut = if ($acCandidates.Count -gt 0) { ($acCandidates -join ',') } else { $null } $isGroup = ($item.PSObject.Properties.Name -contains 'ScopeType' -and $item.ScopeType -eq 'Group') $grpName = $null if ($isGroup) { if ($item.PSObject.Properties.Name -contains 'GroupName' -and $item.GroupName) { $grpName = $item.GroupName } elseif ($item.PSObject.Properties.Name -contains 'ScopeId') { $groupScopeId = $item.ScopeId if ($groupScopeId -and $groupScopeId -match '^[0-9a-fA-F-]{36}$' -and $GroupsById) { $grpName = $GroupsById[$groupScopeId] } } } # Determine role identifiers list (some upstream conversions concatenate multiple role ids / names) $rawRole = $null if ($item.PSObject.Properties.Name -contains 'RoleDefinitionId') { $rawRole = $item.RoleDefinitionId } elseif ($item.PSObject.Properties.Name -contains 'RoleDefinitionIds') { $rawRole = $item.RoleDefinitionIds } elseif ($item.PSObject.Properties.Name -contains 'RoleId') { $rawRole = $item.RoleId } $roleTokens = @() if ($rawRole) { if ($rawRole -is [System.Collections.IEnumerable] -and $rawRole -isnot [string]) { $roleTokens = @($rawRole | ForEach-Object { $_ }) } else { $roleTokens = @($rawRole -split '[,\s]+' | Where-Object { $_ }) } } if ($roleTokens.Count -eq 0) { $roleTokens = @($rawRole) } foreach ($roleDefValue in $roleTokens) { if (-not $roleDefValue) { continue } $roleName = $null $lower = $roleDefValue.ToLower() if ($lower -eq 'owner') { $roleName = 'Owner' } elseif ($lower -eq 'member') { $roleName = 'Member' } elseif ($roleMap.ContainsKey($roleDefValue)) { $roleName = $roleMap[$roleDefValue] } else { $roleName = $roleDefValue } $row = if ($isGroup) { [pscustomobject]@{ 'Group Name' = $grpName 'Role Name' = $roleName 'Auth Context Id' = $acIdOut 'Auth Context Name' = $item.AuthContextNames } } else { [pscustomobject]@{ 'Role Name' = $roleName 'Auth Context Id' = $acIdOut 'Auth Context Name' = $item.AuthContextNames } } $out += $row } } $out } $dirExport = & $projectPim $DirectoryPolicies $grpExport = & $projectPim $GroupPolicies return , @($dirExport, $grpExport) } |