Private/Test-OCM365GraphPermission.ps1
|
function Test-OCM365GraphPermission { <# .SYNOPSIS Tests if the current Microsoft Graph connection has required permissions. .DESCRIPTION Validates that the current Microsoft Graph connection has the required permissions. Understands permission hierarchies: - Super-permissions like Directory.ReadWrite.All cover multiple specific permissions - ReadWrite permissions satisfy Read requirements - Maintains a permission hierarchy map for accurate validation .PARAMETER RequiredPermissions Array of required Microsoft Graph permissions to check for. .PARAMETER Scopes Array of current permission scopes from the Graph connection. If not provided, retrieves from current MgContext. .PARAMETER Details If specified, returns detailed object with permission analysis instead of boolean. The returned object includes: - RequiredPermissions: The permissions that were checked - GrantedPermissions: The permissions currently available - MissingPermissions: Any permissions that were not satisfied - HasAccess: Boolean indicating if all required permissions are available - Notes: Additional details about the permission check .EXAMPLE Test-OCM365GraphPermission -RequiredPermissions @('Application.Read.All', 'Directory.Read.All') Returns $true or $false. .EXAMPLE @('User.Read.All', 'Organization.Read.All') | Test-OCM365GraphPermission Returns $true or $false via pipeline. .EXAMPLE Test-OCM365GraphPermission -RequiredPermissions @('User.Read.All') -Scopes $mgContext.Scopes -Details Returns detailed object with permission analysis. .OUTPUTS System.Boolean Returns $true if all required permissions are satisfied, $false otherwise. When -Details is specified: PSCustomObject with properties: Item, ItemType, RequiredPermissions, GrantedPermissions, MissingPermissions, HasAccess, Notes .NOTES This function understands permission hierarchies: - Directory.ReadWrite.All covers Application.*, Directory.*, User.*, and Organization.Read.All - Organization.ReadWrite.All covers Organization.Read.All - ReadWrite.All covers Read.All of the same resource - TeamSettings.ReadWrite.All covers Team operations - Group permissions cover Team operations (Teams are built on Groups) - TeamMember.ReadWrite.All covers TeamMember.Read.All - All patterns are case-insensitive #> [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline)] [string[]]$RequiredPermissions, [Parameter()] [string[]]$Scopes, [Parameter()] [switch]$Details ) begin { Write-Debug "[Test-OCM365GraphPermission] Starting permission check" # Define permission hierarchy - super permissions that satisfy lower permissions $permissionHierarchy = @{ # Directory.ReadWrite.All is a super-permission covering Application and Directory operations 'Directory.ReadWrite.All' = @( 'Application.Read.All', 'Application.ReadWrite.All', 'Application.ReadWrite.OwnedBy', 'Directory.Read.All', 'Directory.ReadWrite.All', 'Organization.Read.All', 'Organization.ReadWrite.All', 'User.Read.All', 'User.ReadWrite.All' ) # Directory.Read.All covers read operations on applications and directory 'Directory.Read.All' = @( 'Application.Read.All', 'Directory.Read.All', 'Organization.Read.All' ) # Organization.ReadWrite.All covers Organization operations 'Organization.ReadWrite.All' = @( 'Organization.Read.All', 'Organization.ReadWrite.All' ) # ReadWrite covers Read of the same resource 'Application.ReadWrite.All' = @( 'Application.Read.All', 'Application.ReadWrite.All' ) 'User.ReadWrite.All' = @( 'User.Read.All', 'User.ReadWrite.All' ) # TeamSettings permissions cover Team operations 'TeamSettings.ReadWrite.All' = @( 'Team.ReadBasic.All', 'TeamSettings.Read.All', 'TeamSettings.ReadWrite.All' ) 'TeamSettings.Read.All' = @( 'Team.ReadBasic.All', 'TeamSettings.Read.All' ) # Group permissions cover Team operations (Teams are built on Groups) 'Group.ReadWrite.All' = @( 'Team.ReadBasic.All', 'Group.Read.All', 'Group.ReadWrite.All', 'TeamSettings.Read.All', 'TeamSettings.ReadWrite.All' ) 'Group.Read.All' = @( 'Team.ReadBasic.All', 'Group.Read.All' ) # TeamMember permissions 'TeamMember.ReadWrite.All' = @( 'TeamMember.Read.All', 'TeamMember.ReadWrite.All' ) } if (-not $Scopes) { $mgContext = Get-MgContext if ($mgContext) { $Scopes = $mgContext.Scopes } } if (-not $Scopes) { Write-Debug "[Test-OCM365GraphPermission] No scopes available" $Scopes = @() } Write-Debug "[Test-OCM365GraphPermission] Available scopes: $($Scopes -join ', ')" } process { Write-Debug "[Test-OCM365GraphPermission] Required permissions: $($RequiredPermissions -join ', ')" $missingPermissions = @() $allPermissionsSatisfied = $true foreach ($requiredPermission in $RequiredPermissions) { $scopeFound = $false Write-Debug "[Test-OCM365GraphPermission] Checking permission: $requiredPermission" # Check 1: Exact permission match if ($requiredPermission -in $Scopes) { Write-Debug "[Test-OCM365GraphPermission] Found exact match: $requiredPermission" $scopeFound = $true } # Check 2: Permission hierarchy - does a super-permission cover this requirement? if (-not $scopeFound) { foreach ($currentScope in $Scopes) { if ($currentScope -in $permissionHierarchy.Keys) { if ($requiredPermission -in $permissionHierarchy[$currentScope]) { Write-Debug "[Test-OCM365GraphPermission] Found hierarchical permission: $currentScope satisfies $requiredPermission" $scopeFound = $true break } } } } # Check 3: ReadWrite/Read upgrade pattern if (-not $scopeFound -and $requiredPermission -like '*.Read.All') { $upgradeScope = $requiredPermission -replace '\.Read\.All', '.ReadWrite.All' if ($upgradeScope -in $Scopes) { Write-Debug "[Test-OCM365GraphPermission] Found upgraded permission: $upgradeScope satisfies $requiredPermission" $scopeFound = $true } } # Track missing permissions if (-not $scopeFound) { Write-Debug "[Test-OCM365GraphPermission] Permission not satisfied: $requiredPermission" $missingPermissions += $requiredPermission $allPermissionsSatisfied = $false } } # Build result object $resultObject = [pscustomobject]@{ Item = "Permission Check" ItemType = "GraphPermission" RequiredPermissions = $RequiredPermissions GrantedPermissions = $Scopes MissingPermissions = $missingPermissions HasAccess = $allPermissionsSatisfied Notes = if ($missingPermissions) { "Missing required permissions: $($missingPermissions -join ', ')" } else { $null } } if ($Details) { Write-Debug "[Test-OCM365GraphPermission] Returning detailed object" $resultObject } else { Write-Debug "[Test-OCM365GraphPermission] Returning: $allPermissionsSatisfied" $allPermissionsSatisfied } } } |