Private/Authentication/Connect-GraphEntitlementSafe.ps1
|
function Connect-GraphEntitlementSafe { <#! .SYNOPSIS Connects to Microsoft Graph with read-only Entitlement Management scopes for Access Package reporting. .DESCRIPTION Ensures the Graph context includes the minimum read permissions needed to enumerate access packages, assignment policies, resources, approvals, and custom extensions. Reuses an existing context when the required scopes are already granted to avoid extra prompts. .PARAMETER QuietMode Suppress console output. .OUTPUTS Boolean indicating success. #> [CmdletBinding()] param( [switch]$QuietMode, [string]$TenantId, [string]$ClientId, [string[]]$AdditionalScopes ) $script:graphConnected = $false $script:graphDisconnectOnExit = $false $baseScopes = @( 'EntitlementManagement.Read.All', 'Directory.Read.All', 'Group.Read.All', 'User.Read.All', 'Policy.Read.All', 'Application.Read.All' # for app role/resource enrichment (service principals/apps) ) $neededScopes = ($baseScopes + ($AdditionalScopes | Where-Object { $_ })) | Select-Object -Unique try { $context = Get-MgContext -ErrorAction SilentlyContinue if ($context -and $context.Account -and (-not $TenantId -or $context.TenantId -eq $TenantId)) { $currentScopes = @() try { if ($context.Scopes) { $currentScopes = $context.Scopes } } catch { Write-Verbose 'Unable to read scopes from existing Graph context.' } $missingScopes = @(); foreach ($scope in $neededScopes) { if ($currentScopes -notcontains $scope) { $missingScopes += $scope } } if ($missingScopes.Count -gt 0) { if (-not $QuietMode) { Write-Host ('[Graph] Re-auth required to add missing scopes: {0}' -f ($missingScopes -join ',')) -ForegroundColor Yellow } Connect-MgGraph -Scopes ($currentScopes + $missingScopes | Select-Object -Unique) -ErrorAction Stop | Out-Null $script:graphDisconnectOnExit = $true $context = Get-MgContext -ErrorAction SilentlyContinue $currentScopes = @(); try { if ($context.Scopes) { $currentScopes = $context.Scopes } } catch { Write-Verbose 'Unable to read scopes after re-auth.' } $missingScopes = @(); foreach ($scope in $neededScopes) { if ($currentScopes -notcontains $scope) { $missingScopes += $scope } } if ($missingScopes.Count -gt 0) { Write-ModuleLog -Message ('Microsoft Graph still missing scopes after re-auth: {0}' -f ($missingScopes -join ',')) -Level Error throw "Graph connection missing required scopes: $($missingScopes -join ', ')" } } else { if (-not $QuietMode) { Write-Host " ✓ Using existing Microsoft Graph connection (Account: $($context.Account))" -ForegroundColor DarkGreen } } $script:graphConnected = $true $script:graphDisconnectOnExit = $true return $true } if (-not $QuietMode) { Write-Host ' → Connecting to Microsoft Graph (Entitlement Mgmt scopes)...' -ForegroundColor DarkCyan } $connectParams = @{ Scopes = $neededScopes; NoWelcome = $true; ErrorAction = 'Stop' } if ($TenantId) { $connectParams['TenantId'] = $TenantId } if ($ClientId) { $connectParams['ClientId'] = $ClientId } Connect-MgGraph @connectParams | Out-Null $script:graphDisconnectOnExit = $true # Validate scopes $context = Get-MgContext -ErrorAction SilentlyContinue $currentScopes = @(); try { if ($context.Scopes) { $currentScopes = $context.Scopes } } catch { Write-Verbose 'Unable to read scopes after initial connect.' } $missingScopes = @(); foreach ($scope in $neededScopes) { if ($currentScopes -notcontains $scope) { $missingScopes += $scope } } if ($missingScopes.Count -gt 0) { Write-ModuleLog -Message ('Microsoft Graph connection established but missing scopes: {0}' -f ($missingScopes -join ',')) -Level Error throw "Graph connection missing required scopes: $($missingScopes -join ', ')" } $script:graphConnected = $true if (-not $QuietMode) { Write-Host ' ✓ Microsoft Graph connection established' -ForegroundColor DarkGreen } return $true } catch { # One retry with force refresh to trigger an auth prompt if cache/session is bad if (-not $QuietMode) { Write-Host ' ✗ Microsoft Graph connection failed, retrying with ForceRefresh...' -ForegroundColor Yellow } try { $connectParams = @{ Scopes = $neededScopes; NoWelcome = $true; ForceRefresh = $true; ErrorAction = 'Stop' } if ($TenantId) { $connectParams['TenantId'] = $TenantId } if ($ClientId) { $connectParams['ClientId'] = $ClientId } Connect-MgGraph @connectParams | Out-Null $script:graphDisconnectOnExit = $true $script:graphConnected = $true if (-not $QuietMode) { Write-Host ' ✓ Microsoft Graph connection established (after refresh)' -ForegroundColor DarkGreen } return $true } catch { if (-not $QuietMode) { Write-Host ' ✗ Microsoft Graph connection failed' -ForegroundColor Red } Write-Warning "Graph connection failed: $($_.Exception.Message)" $script:graphConnected = $false return $false } } } |