Src/Private/Get-AbrExoClientAccess.ps1
|
function Get-AbrExoClientAccess { <# .SYNOPSIS Documents Exchange Online client access protocols (OWA, MAPI, ActiveSync, POP, IMAP), authentication policies, and modern authentication status. .NOTES Version: 0.1.0 Author: Pai Wei Sing #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string]$TenantId ) begin { Write-PScriboMessage -Message "Collecting Exchange Online Client Access configuration for $TenantId." Show-AbrDebugExecutionTime -Start -TitleMessage 'ClientAccess' } process { Section -Style Heading2 'Protocols & Authentication' { Paragraph "The following section documents client access protocols, authentication policies, and how users connect to Exchange Online in tenant $TenantId." BlankLine #region Modern Auth Status try { Write-Host " - Retrieving modern authentication configuration..." $OrgConfig = Get-OrganizationConfig -ErrorAction Stop $ModernAuthEnabled = $OrgConfig.OAuth2ClientProfileEnabled -eq $true $BasicAuthBlocked = $OrgConfig.DefaultPublicFolderMailbox # proxy check; use auth policies below Section -Style Heading3 'Modern Authentication Status' { Paragraph "Modern Authentication (OAuth 2.0) is the recommended authentication method for Exchange Online. Legacy Basic Authentication has been retired by Microsoft for most protocols." BlankLine $MaObj = [System.Collections.ArrayList]::new() $maInObj = [ordered] @{ 'Modern Authentication (OAuth2) Enabled' = $ModernAuthEnabled 'Recommendation' = if ($ModernAuthEnabled) { 'OK: Modern Auth is enabled.' } else { 'CRITICAL: Enable Modern Auth immediately.' } } $MaObj.Add([pscustomobject](ConvertTo-HashToYN $maInObj)) | Out-Null $null = (& { if ($HealthCheck.ExchangeOnline.Mailboxes) { $null = ($MaObj | Where-Object { $_.'Modern Authentication (OAuth2) Enabled' -eq 'No' } | Set-Style -Style Critical | Out-Null) } }) $MaTableParams = @{ Name = "Modern Authentication - $TenantId"; List = $true; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $MaTableParams['Caption'] = "- $($MaTableParams.Name)" } $MaObj | Table @MaTableParams } } catch { Write-ExoError 'ClientAccess' "Unable to retrieve modern auth status: $($_.Exception.Message)" } #endregion #region Authentication Policies try { Write-Host " - Retrieving authentication policies..." $AuthPolicies = Get-AuthenticationPolicy -ErrorAction Stop | Sort-Object Name if ($AuthPolicies -and @($AuthPolicies).Count -gt 0) { Section -Style Heading3 'Authentication Policies' { Paragraph "Authentication policies control which legacy protocols are permitted per user or tenant-wide. $(@($AuthPolicies).Count) policy/policies are configured." BlankLine $ApObj = [System.Collections.ArrayList]::new() foreach ($Policy in $AuthPolicies) { $apInObj = [ordered] @{ 'Policy Name' = $Policy.Name 'Allow Basic - SMTP' = $Policy.AllowBasicAuthSmtp 'Allow Basic - IMAP' = $Policy.AllowBasicAuthImap 'Allow Basic - POP' = $Policy.AllowBasicAuthPop 'Allow Basic - OWA' = $Policy.AllowBasicAuthWebServices 'Allow Basic - EAS' = $Policy.AllowBasicAuthActiveSync 'Allow Basic - EWS' = $Policy.AllowBasicAuthWebServices 'Allow Basic - MAPI' = $Policy.AllowBasicAuthMapi 'Allow Basic - PowerShell' = $Policy.AllowBasicAuthPowershell } $ApObj.Add([pscustomobject](ConvertTo-HashToYN $apInObj)) | Out-Null } $null = (& { if ($HealthCheck.ExchangeOnline.Mailboxes) { # Flag any policy that allows basic auth on any protocol $null = ($ApObj | Where-Object { $_.'Allow Basic - SMTP' -eq 'Yes' -or $_.'Allow Basic - IMAP' -eq 'Yes' -or $_.'Allow Basic - POP' -eq 'Yes' -or $_.'Allow Basic - MAPI' -eq 'Yes' } | Set-Style -Style Critical | Out-Null) } }) $ApTableParams = @{ Name = "Authentication Policies - $TenantId"; List = $false; ColumnWidths = 22, 9, 9, 9, 9, 9, 9, 9, 7, 8 } # 9 properties: use List=$true for wide policy tables to avoid column overflow $ApTableParams = @{ Name = "Authentication Policies - $TenantId"; List = $false; ColumnWidths = 24, 9, 9, 9, 9, 9, 9, 9, 13 } if ($Report.ShowTableCaptions) { $ApTableParams['Caption'] = "- $($ApTableParams.Name)" } if ($ApObj.Count -gt 0) { $ApObj | Table @ApTableParams } $script:ExcelSheets['Auth Policies'] = $ApObj } } else { Paragraph "No custom authentication policies configured. Tenant-wide defaults apply." } } catch { Write-ExoError 'ClientAccess' "Unable to retrieve authentication policies: $($_.Exception.Message)" } #endregion #region CAS Mailbox Plans (per-plan protocol enablement) try { Write-Host " - Retrieving CAS mailbox plans..." $CasPlans = Get-CASMailboxPlan -ErrorAction Stop | Sort-Object DisplayName if ($CasPlans -and @($CasPlans).Count -gt 0) { Section -Style Heading3 'Client Access Protocol Settings (by Plan)' { Paragraph "CAS Mailbox Plans define which protocols are enabled per licence plan. The following $(@($CasPlans).Count) plan(s) are configured." BlankLine $CpObj = [System.Collections.ArrayList]::new() foreach ($Plan in $CasPlans) { $cpInObj = [ordered] @{ 'Plan Name' = $Plan.DisplayName 'OWA Enabled' = $Plan.OwaMailboxPolicy -ne $null 'EAS Enabled' = $Plan.ActiveSyncEnabled 'IMAP Enabled' = $Plan.ImapEnabled 'POP Enabled' = $Plan.PopEnabled 'MAPI Enabled' = $Plan.MAPIEnabled 'EWS Enabled' = $Plan.EwsEnabled } $CpObj.Add([pscustomobject](ConvertTo-HashToYN $cpInObj)) | Out-Null } $null = (& { if ($HealthCheck.ExchangeOnline.Mailboxes) { $null = ($CpObj | Where-Object { $_.'IMAP Enabled' -eq 'Yes' -or $_.'POP Enabled' -eq 'Yes' } | Set-Style -Style Warning | Out-Null) } }) $CpTableParams = @{ Name = "CAS Mailbox Plans - $TenantId"; List = $false; ColumnWidths = 28, 12, 12, 12, 12, 12, 12 } if ($Report.ShowTableCaptions) { $CpTableParams['Caption'] = "- $($CpTableParams.Name)" } if ($CpObj.Count -gt 0) { $CpObj | Table @CpTableParams } $script:ExcelSheets['CAS Plans'] = $CpObj } } } catch { Write-ExoError 'ClientAccess' "Unable to retrieve CAS mailbox plans: $($_.Exception.Message)" } #endregion #region OWA Policies try { Write-Host " - Retrieving OWA mailbox policies..." $OwaPolicies = Get-OwaMailboxPolicy -ErrorAction Stop | Sort-Object IsDefault -Descending if ($OwaPolicies -and @($OwaPolicies).Count -gt 0) { Section -Style Heading3 'Outlook Web App (OWA) Policies' { Paragraph "The following $(@($OwaPolicies).Count) OWA mailbox policy/policies control the Outlook Web App experience for users." BlankLine $OwaObj = [System.Collections.ArrayList]::new() foreach ($Policy in $OwaPolicies) { $owaInObj = [ordered] @{ 'Policy Name' = $Policy.Name 'Default Policy' = $Policy.IsDefault 'Public Attachments' = $Policy.DirectFileAccessOnPublicComputersEnabled 'Private Attachments' = $Policy.DirectFileAccessOnPrivateComputersEnabled 'Instant Messaging' = $Policy.InstantMessagingEnabled 'Text Messaging' = $Policy.TextMessagingEnabled 'Theme Selection' = $Policy.ThemeSelectionEnabled 'Phishing Reporting' = $Policy.ReportJunkEmailEnabled 'ActiveSync Integration' = $Policy.ActiveSyncIntegrationEnabled } $OwaObj.Add([pscustomobject](ConvertTo-HashToYN $owaInObj)) | Out-Null } # 9 columns = 100% $OwaTableParams = @{ Name = "OWA Mailbox Policies - $TenantId"; List = $false; ColumnWidths = 20, 8, 10, 10, 10, 10, 9, 9, 8, 6 } # Fix: 9 props → 9 widths = 100 $OwaTableParams = @{ Name = "OWA Mailbox Policies - $TenantId"; List = $false; ColumnWidths = 20, 9, 10, 10, 11, 10, 10, 10, 10 } if ($Report.ShowTableCaptions) { $OwaTableParams['Caption'] = "- $($OwaTableParams.Name)" } if ($OwaObj.Count -gt 0) { $OwaObj | Table @OwaTableParams } $script:ExcelSheets['OWA Policies'] = $OwaObj } } } catch { Write-ExoError 'ClientAccess' "Unable to retrieve OWA policies: $($_.Exception.Message)" } #endregion #region Per-mailbox protocol exceptions (InfoLevel 2) if ($InfoLevel.ClientAccess -ge 2) { try { Write-Host " - Retrieving per-mailbox CAS settings (exceptions only)..." $CasMailboxes = Get-CASMailbox -ResultSize Unlimited -ErrorAction Stop | Where-Object { $_.ImapEnabled -eq $true -or $_.PopEnabled -eq $true -or $_.MAPIEnabled -eq $false -or $_.ActiveSyncEnabled -eq $false } | Sort-Object DisplayName if ($CasMailboxes -and @($CasMailboxes).Count -gt 0) { Section -Style Heading3 'Per-Mailbox Protocol Exceptions' { Paragraph "The following $(@($CasMailboxes).Count) mailbox(es) have non-standard protocol settings (IMAP/POP enabled, MAPI/ActiveSync disabled)." BlankLine $CmObj = [System.Collections.ArrayList]::new() foreach ($Cas in $CasMailboxes) { $cmInObj = [ordered] @{ 'Display Name' = $Cas.DisplayName 'UPN' = $Cas.PrimarySmtpAddress 'MAPI Enabled' = $Cas.MAPIEnabled 'EAS Enabled' = $Cas.ActiveSyncEnabled 'OWA Enabled' = $Cas.OWAEnabled 'IMAP Enabled' = $Cas.ImapEnabled 'POP Enabled' = $Cas.PopEnabled 'EWS Enabled' = $Cas.EwsEnabled } $CmObj.Add([pscustomobject](ConvertTo-HashToYN $cmInObj)) | Out-Null } $null = (& { if ($HealthCheck.ExchangeOnline.Mailboxes) { $null = ($CmObj | Where-Object { $_.'IMAP Enabled' -eq 'Yes' -or $_.'POP Enabled' -eq 'Yes' } | Set-Style -Style Warning | Out-Null) $null = ($CmObj | Where-Object { $_.'MAPI Enabled' -eq 'No' } | Set-Style -Style Warning | Out-Null) } }) $CmTableParams = @{ Name = "Per-Mailbox Protocol Exceptions - $TenantId"; List = $false; ColumnWidths = 16, 22, 9, 9, 9, 9, 9, 9, 8 } if ($Report.ShowTableCaptions) { $CmTableParams['Caption'] = "- $($CmTableParams.Name)" } if ($CmObj.Count -gt 0) { $CmObj | Table @CmTableParams } $script:ExcelSheets['Protocol Exceptions'] = $CmObj } } else { Paragraph "No per-mailbox protocol exceptions detected. All mailboxes use plan defaults." } } catch { Write-ExoError 'ClientAccess' "Unable to retrieve per-mailbox CAS settings: $($_.Exception.Message)" } } #endregion } } end { Show-AbrDebugExecutionTime -End -TitleMessage 'ClientAccess' } } |