Orchestrator/Test-GraphPermissions.ps1
|
<#
.SYNOPSIS Validates Graph API scopes after connection against required scopes. .DESCRIPTION Compares granted scopes from Get-MgContext against the scopes required by selected assessment sections. Warns about missing scopes before collectors run. #> function Test-GraphPermissions { <# .SYNOPSIS Validates Graph API scopes after connection. .DESCRIPTION Compares the scopes granted by Get-MgContext against the scopes required by the selected assessment sections (from sectionScopeMap). Warns about missing scopes before collectors run, so users know which sections may produce incomplete results. With app-only auth (certificate/managed identity), scopes are determined by app registration and Get-MgContext.Scopes may show '.default' only. In this case the check is skipped with an informational message. .PARAMETER RequiredScopes Array of Graph scope strings required for the selected sections. .PARAMETER SectionScopeMap Hashtable mapping section names to their required scope arrays. .PARAMETER ActiveSections Array of section names the user selected. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string[]]$RequiredScopes, [Parameter(Mandatory)] [hashtable]$SectionScopeMap, [Parameter(Mandatory)] [string[]]$ActiveSections ) $context = Get-MgContext -ErrorAction SilentlyContinue if (-not $context) { Write-AssessmentLog -Level WARN -Message 'Graph context not available -- skipping scope validation' -Section 'Setup' return } $grantedScopes = @($context.Scopes) # App-only auth: scopes may be empty or contain only '.default' if ($grantedScopes.Count -eq 0 -or ($grantedScopes.Count -eq 1 -and $grantedScopes[0] -eq '.default')) { Write-Host ' i App-only auth detected -- scope validation not available (permissions set in app registration)' -ForegroundColor DarkGray Write-AssessmentLog -Level INFO -Message 'App-only auth: scope validation skipped (permissions defined in Entra app registration)' -Section 'Setup' return } # Compare required vs granted (case-insensitive) $grantedLower = $grantedScopes | ForEach-Object { $_.ToLower() } $missingScopes = @($RequiredScopes | Where-Object { $_.ToLower() -notin $grantedLower }) if ($missingScopes.Count -eq 0) { Write-Host " $([char]0x2714) All $($RequiredScopes.Count) required Graph scopes granted" -ForegroundColor Green Write-AssessmentLog -Level INFO -Message "Graph scope validation passed ($($RequiredScopes.Count) scopes)" -Section 'Setup' return } # Map missing scopes back to affected sections $affectedSections = @{} foreach ($scope in $missingScopes) { foreach ($section in $ActiveSections) { if (-not $SectionScopeMap.ContainsKey($section)) { continue } $sectionScopes = $SectionScopeMap[$section] | ForEach-Object { $_.ToLower() } if ($scope.ToLower() -in $sectionScopes) { if (-not $affectedSections.ContainsKey($section)) { $affectedSections[$section] = [System.Collections.Generic.List[string]]::new() } $affectedSections[$section].Add($scope) } } } # Display warnings Write-Host '' Write-Host " $([char]0x26A0) $($missingScopes.Count) Graph scope(s) not consented -- some checks may fail:" -ForegroundColor Yellow foreach ($section in $affectedSections.Keys | Sort-Object) { $scopeList = ($affectedSections[$section] | Sort-Object) -join ', ' Write-Host " ${section}: $scopeList" -ForegroundColor Yellow } Write-Host ' Tip: re-run consent or update app registration to include these scopes' -ForegroundColor DarkGray Write-Host '' Write-AssessmentLog -Level WARN -Message "Missing Graph scopes: $($missingScopes -join ', ')" -Section 'Setup' } |