Private/Entra/Core/Get-EntraPIMData.ps1
|
# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0 # https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/ # AI/LLM use: see AI-USAGE.md for required attribution function Get-EntraPIMData { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AccessToken, [switch]$Quiet ) $data = @{ DirectoryRoles = @() RoleAssignments = @() RoleEligibilitySchedules = @() RoleAssignmentSchedules = @() RoleDefinitions = @() PrivilegedUsers = @() GlobalAdmins = @() Errors = @{} } # ── Directory Role Definitions ──────────────────────────────────────── if (-not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message 'Collecting directory role definitions' } try { $data.RoleDefinitions = @(Invoke-GraphApi -AccessToken $AccessToken ` -Uri '/roleManagement/directory/roleDefinitions' ` -Paginate -Quiet:$Quiet) } catch { $data.Errors['RoleDefinitions'] = $_.Exception.Message } # ── Active Role Assignments ─────────────────────────────────────────── if (-not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message 'Collecting active role assignments' } try { $data.RoleAssignments = @(Invoke-GraphApi -AccessToken $AccessToken ` -Uri '/roleManagement/directory/roleAssignments' ` -QueryParameters @{ '$expand' = 'principal' } ` -Paginate -Quiet:$Quiet) } catch { $data.Errors['RoleAssignments'] = $_.Exception.Message } # ── Eligible Role Assignments (PIM) ─────────────────────────────────── if (-not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message 'Collecting PIM eligible role assignments' } try { $data.RoleEligibilitySchedules = @(Invoke-GraphApi -AccessToken $AccessToken ` -Uri '/roleManagement/directory/roleEligibilityScheduleInstances' ` -Paginate -Quiet:$Quiet) } catch { $data.Errors['RoleEligibilitySchedules'] = $_.Exception.Message } # ── Role Assignment Schedule Instances (active PIM activations) ─────── try { $data.RoleAssignmentSchedules = @(Invoke-GraphApi -AccessToken $AccessToken ` -Uri '/roleManagement/directory/roleAssignmentScheduleInstances' ` -Paginate -Quiet:$Quiet) } catch { $data.Errors['RoleAssignmentSchedules'] = $_.Exception.Message } # ── Global Administrator members ────────────────────────────────────── if (-not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message 'Enumerating Global Administrators' } $globalAdminTemplateId = '62e90394-69f5-4237-9190-012177145e10' try { $data.GlobalAdmins = @(Invoke-GraphApi -AccessToken $AccessToken ` -Uri "/directoryRoles(roleTemplateId='$globalAdminTemplateId')/members" ` -Paginate -Quiet:$Quiet) } catch { # Try alternate approach via role assignments try { $gaAssignments = @($data.RoleAssignments | Where-Object { $_.roleDefinitionId -eq $globalAdminTemplateId }) $data.GlobalAdmins = @($gaAssignments | ForEach-Object { $_.principal }) } catch { $data.Errors['GlobalAdmins'] = $_.Exception.Message } } # ── Collect privileged user details ──────────────────────────────────── # Identify all unique principals with privileged roles $privilegedPrincipalIds = [System.Collections.Generic.HashSet[string]]::new( [StringComparer]::OrdinalIgnoreCase ) # Define privileged role template IDs $privilegedRoleIds = @( '62e90394-69f5-4237-9190-012177145e10' # Global Administrator 'e8611ab8-c189-46e8-94e1-60213ab1f814' # Privileged Role Administrator '194ae4cb-b126-40b2-bd5b-6091b380977d' # Security Administrator 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c' # SharePoint Administrator '29232cdf-9323-42fd-ade2-1d097af3e4de' # Exchange Administrator 'fe930be7-5e62-47db-91af-98c3a49a38b1' # User Administrator '9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3' # Application Administrator '158c047a-c907-4556-b7ef-446551a6b5f7' # Cloud Application Administrator '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' # Privileged Authentication Administrator 'b0f54661-2d74-4c50-afa3-1ec803f12efe' # Billing Administrator '966707d0-3269-4727-9be2-8c3a10f19b9d' # Global Reader 'fdd7a751-b60b-444a-984c-02652fe8fa1c' # Groups Administrator '729827e3-9c14-49f7-bb1b-9608f156bbb8' # Helpdesk Administrator 'b1be1c3e-b65d-4f19-8427-f6fa0d97feb9' # Conditional Access Administrator 'c4e39bd9-1100-46d3-8c65-fb160da0071f' # Authentication Administrator '7698a772-787b-4ac8-901f-60d6b08affd2' # Cloud Device Administrator '3a2c62db-5318-420d-8d74-23affee5d9d5' # Intune Administrator '44367163-eba1-44c3-98af-f5787879f96a' # Dynamics 365 Administrator '11648597-926c-4cf3-9c36-bcebb0ba8dcc' # Power Platform Administrator '0526716b-113d-4c15-b2c8-68e3c22b9f80' # Authentication Policy Administrator ) foreach ($assignment in $data.RoleAssignments) { if ($assignment.roleDefinitionId -in $privilegedRoleIds) { if ($assignment.principalId) { [void]$privilegedPrincipalIds.Add($assignment.principalId) } } } # Fetch user details for privileged principals (batch) if ($privilegedPrincipalIds.Count -gt 0 -and -not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message "Collecting details for $($privilegedPrincipalIds.Count) privileged principals" } $privilegedUsers = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($principalId in $privilegedPrincipalIds) { try { $user = Invoke-GraphApi -AccessToken $AccessToken ` -Uri "/users/$principalId" ` -QueryParameters @{ '$select' = 'id,displayName,userPrincipalName,userType,accountEnabled,onPremisesSyncEnabled,signInActivity,createdDateTime' } if ($user) { $privilegedUsers.Add($user) } } catch { # Principal might be a service principal or group, not a user Write-Verbose "Could not fetch user details for principal $principalId" } } $data.PrivilegedUsers = @($privilegedUsers) if (-not $Quiet) { Write-ProgressLine -Phase INFILTRATE -Message "Found $($data.GlobalAdmins.Count) Global Admins, $($data.RoleAssignments.Count) role assignments" } return $data } |