public/maester/entra/Test-MtSpExchangeAppAccessPolicy.ps1
|
<# .SYNOPSIS Check if service principals with Exchange permissions have application access policies configured. .DESCRIPTION Service principals with Exchange permissions can access all mailboxes by default. This test verifies that proper access policies are in place. .EXAMPLE Test-MtSpExchangeAppAccessPolicy Returns true if all service principals with Exchange permissions have access policies configured .LINK https://maester.dev/docs/commands/Test-MtSpExchangeAppAccessPolicy #> function Test-MtSpExchangeAppAccessPolicy { [CmdletBinding()] [OutputType([bool])] param() Write-Verbose 'Running Test-MtSpExchangeAppAccessPolicy' if (-not (Test-MtConnection ExchangeOnline)) { Add-MtTestResultDetail -SkippedBecause NotConnectedExchange return $null } try { # Note: If you make any changes to this list, please keep it in sync # with the markdown file Test-MtSpExchangeAppAccessPolicy.md $exchangePermissions = @( 'Mail.Read', 'Mail.ReadBasic', 'Mail.ReadBasic.All', 'Mail.ReadWrite', 'Mail.Send', 'MailboxSettings.Read', 'MailboxSettings.ReadWrite', 'Calendars.Read', 'Calendars.ReadWrite', 'Contacts.Read', 'Contacts.ReadWrite' ) # Get service principals with Exchange permissions $msGraph = Invoke-MtGraphRequest -RelativeUri 'servicePrincipals' -Filter "appId eq '00000003-0000-0000-c000-000000000000'" $availablePermissions = $msGraph.AppRoles | Select-Object Id, Value $servicePrincipals = Invoke-MtGraphRequest -RelativeUri 'servicePrincipals' $principalsWithExchangePerms = $servicePrincipals | ForEach-Object { $sp = $_ $appRoles = Invoke-MtGraphRequest -RelativeUri "servicePrincipals/$($sp.Id)/appRoleAssignments" $permissions = $appRoles.AppRoleId | ForEach-Object { $roleId = $_ ($availablePermissions | Where-Object { $_.Id -eq $roleId }).Value } if ($permissions | Where-Object { $_ -in $exchangePermissions }) { [PSCustomObject]@{ Id = $sp.Id DisplayName = $sp.DisplayName AppId = $sp.AppId Permissions = $permissions -join ', ' } } } # Get application access policies $appAccessPolicies = Get-ApplicationAccessPolicy # Prepare result table showing all apps with Exchange permissions $detailMarkdown = "### Applications with Exchange Permissions`n`n" $detailMarkdown += "| Application | Permissions | Access Policy? |`n" $detailMarkdown += "| --- | --- | --- |`n" $missingPolicies = @() foreach ($sp in $principalsWithExchangePerms) { $hasPolicy = $appAccessPolicies.AppId -contains $sp.AppId $policyStatus = if ($hasPolicy) { '✅ Yes' } else { '❌ No' } $filteredPermissions = $sp.Permissions -split ', ' | Where-Object { $_ -in $exchangePermissions } $portalLink = Get-MtLinkServicePrincipal -ServicePrincipal $sp -Blade Permissions $detailMarkdown += "| $portalLink | $($filteredPermissions -join ', ') | $policyStatus |`n" if (-not $hasPolicy) { $missingPolicies += $sp } } $invalidCount = ($missingPolicies | Measure-Object).Count $result = $invalidCount -eq 0 if ($result) { $testResultMarkdown = 'Well done. We did not find any applications with tenant-wide Exchange permissions to all mailboxes.' } else { $testResultMarkdown = "Found **$invalidCount** applications with tenant-wide access to all Exchange mailboxes." } $testResultMarkdown += "`n`n" + $detailMarkdown Add-MtTestResultDetail -Result $testResultMarkdown return $result } catch { Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ return $null } } |