Public/Connect-PurviewPostureSession.ps1
|
# Connect-PurviewPostureSession.ps1 - opens the two read-only sessions the analyzer uses: # Security & Compliance PowerShell (Connect-IPPSSession) - labels, DLP, retention, IRM, # comms compliance, eDiscovery, DSPM-for-AI (Copilot-location) policies # Exchange Online (Connect-ExchangeOnline) - audit config, organization config # # No Microsoft Graph: the tool never reads licensing or directory data, so there is no # Graph module requirement and no admin-consent prompt (PLAN.md decision D9). License # context in the report is a static annotation from Data/license-requirements.json. # # These are interactive sign-ins. This module never mutates the tenant; the Connect-* # cmdlets only establish sessions. ASCII-only source (Windows PowerShell 5.1). Set-StrictMode -Off function Connect-PurviewPostureSession { [CmdletBinding()] param( [string]$UserPrincipalName, # Cross-tenant guest / B2B support (pre-publish Part 6): connect to a CLIENT # tenant as an invited guest. -DelegatedOrganization names the client tenant # (e.g. client.onmicrosoft.com). The Security & Compliance endpoint ALSO # requires -AzureADAuthorizationEndpointUri (module 3.0.0+); when not # supplied it is derived as https://login.microsoftonline.com/<org>, matching # the MS Learn guest example. Commercial cloud only - sovereign clouds are # out of scope. Exchange Online takes the organization ALONE. [string]$DelegatedOrganization, [string]$AzureADAuthorizationEndpointUri ) # F-014 presence guard: without the ExchangeOnlineManagement module NOTHING can # connect, so stop cleanly BEFORE any connection work - a terminating error with # the locked, operator-approved message. Availability check only (never an import, # never a command probe). All three connect paths (manual run, -Connect switch, # guest/B2B) funnel through this function, so this single guard covers them all. # (Guard-scan note: the install hint is composed at runtime so no mutating-verb # cmdlet literal appears in source - message text for the operator, never an # invocation. Same convention as the -Connect both-failed hint in the invoker.) if (-not (Test-PpaExoModuleAvailable)) { throw (@( 'ExchangeOnlineManagement module not found.' 'PurviewPostureAnalyzer needs it to connect to Microsoft Purview. PPA stopped before connecting.' '' 'To install it, run:' (' ' + 'Install' + '-Module ExchangeOnlineManagement -Scope CurrentUser') '' 'Then run PurviewPostureAnalyzer again.' ) -join [Environment]::NewLine) } $results = [ordered]@{ SecurityCompliance = 'not attempted'; ExchangeOnline = 'not attempted' } # Param hygiene: the endpoint is a guest-call refinement - without the guest # organization it has no meaning, so it is ignored loudly, never applied. if ($AzureADAuthorizationEndpointUri -and -not $DelegatedOrganization) { Write-Warning '-AzureADAuthorizationEndpointUri is only used with -DelegatedOrganization (guest/B2B connect); ignoring it.' } # Security & Compliance PowerShell try { if (Get-Command -Name 'Connect-IPPSSession' -ErrorAction SilentlyContinue) { $ippsArgs = @{ ShowBanner = $false; ErrorAction = 'Stop' } if ($UserPrincipalName) { $ippsArgs.UserPrincipalName = $UserPrincipalName } if ($DelegatedOrganization) { # Guest call: IPPS needs BOTH the organization and the auth endpoint # (verified against MS Learn, module 3.0.0+). $ippsArgs.DelegatedOrganization = $DelegatedOrganization $ep = if ($AzureADAuthorizationEndpointUri) { $AzureADAuthorizationEndpointUri } else { "https://login.microsoftonline.com/$DelegatedOrganization" } $ippsArgs.AzureADAuthorizationEndpointUri = $ep } Connect-IPPSSession @ippsArgs $results.SecurityCompliance = 'connected' } else { $results.SecurityCompliance = 'ExchangeOnlineManagement module not installed' } } catch { $results.SecurityCompliance = "failed: $($_.Exception.Message)" } # Exchange Online try { if (Get-Command -Name 'Connect-ExchangeOnline' -ErrorAction SilentlyContinue) { $exoArgs = @{ ShowBanner = $false; ErrorAction = 'Stop' } if ($UserPrincipalName) { $exoArgs.UserPrincipalName = $UserPrincipalName } # Guest call: EXO takes the organization ALONE - intentionally NO # AzureADAuthorizationEndpointUri here (per the MS Learn guest example). if ($DelegatedOrganization) { $exoArgs.DelegatedOrganization = $DelegatedOrganization } Connect-ExchangeOnline @exoArgs $results.ExchangeOnline = 'connected' } else { $results.ExchangeOnline = 'ExchangeOnlineManagement module not installed' } } catch { $results.ExchangeOnline = "failed: $($_.Exception.Message)" } return [pscustomobject]$results } |