Src/Private/Get-AbrExoAntiPhishing.ps1

function Get-AbrExoAntiPhishing {
    <#
    .SYNOPSIS
    Documents Exchange Online anti-phishing policy configuration with ACSC E8 and CIS compliance assessments.
    .NOTES
        Version: 0.1.0
        Author: Pai Wei Sing
    #>

    [CmdletBinding()]
    param (
        [Parameter(Position = 0, Mandatory)]
        [string]$TenantId
    )

    begin {
        Write-PScriboMessage -Message "Collecting Exchange Online Anti-Phishing configuration for $TenantId."
        Show-AbrDebugExecutionTime -Start -TitleMessage 'AntiPhishing'
    }

    process {
        Section -Style Heading2 'Anti-Phishing Policies' {
            Paragraph "The following section documents the anti-phishing policies configured for tenant $TenantId."
            BlankLine

            # Compliance variable defaults
            $AntiPhishPolicyCount           = 0
            $ImpersonationProtectionEnabled = $false
            $MailboxIntelligenceEnabled     = $false
            $SpoofIntelligenceEnabled       = $false
            $DmarcRejectEnabled             = $false
            $FirstContactSafetyTip          = $false

            try {
                Write-Host " - Retrieving anti-phishing policies..."
                $AntiPhishPolicies = Get-AntiPhishPolicy -ErrorAction Stop | Sort-Object IsDefault -Descending

                $AntiPhishPolicyCount = @($AntiPhishPolicies).Count

                if ($AntiPhishPolicies) {
                    $DefaultPolicy = $AntiPhishPolicies | Where-Object { $_.IsDefault } | Select-Object -First 1
                    if (-not $DefaultPolicy) { $DefaultPolicy = $AntiPhishPolicies | Select-Object -First 1 }

                    $ImpersonationProtectionEnabled = ($DefaultPolicy.EnableUserImpersonation -eq $true -or
                                                       $DefaultPolicy.EnableOrganizationDomainsProtection -eq $true)
                    $MailboxIntelligenceEnabled     = ($DefaultPolicy.EnableMailboxIntelligence -eq $true)
                    $SpoofIntelligenceEnabled       = ($DefaultPolicy.EnableSpoofIntelligence -eq $true)
                    $DmarcRejectEnabled             = ($DefaultPolicy.HonorDmarcPolicy -eq $true)
                    $FirstContactSafetyTip          = ($DefaultPolicy.EnableFirstContactSafetyTips -eq $true)

                    # Summary object — key security toggles only (11 columns)
                    $PhishSumObj = [System.Collections.ArrayList]::new()
                    # Detail object — full settings in List format (stored for Excel, rendered per-policy if InfoLevel 2)
                    $PhishObj = [System.Collections.ArrayList]::new()
                    foreach ($Policy in $AntiPhishPolicies) {
                        $phishSumInObj = [ordered] @{
                            'Policy Name'           = $Policy.Name
                            'Default'               = $Policy.IsDefault
                            'Enabled'               = $Policy.Enabled
                            'Threshold'             = $Policy.PhishThresholdLevel
                            'User Imp.'             = $Policy.EnableUserImpersonation
                            'Domain Imp.'           = $Policy.EnableOrganizationDomainsProtection
                            'Mailbox Intel'         = $Policy.EnableMailboxIntelligence
                            'Spoof Intel'           = $Policy.EnableSpoofIntelligence
                            'DMARC Honor'           = $Policy.HonorDmarcPolicy
                            'First Contact Tip'     = $Policy.EnableFirstContactSafetyTips
                            'Unauth Sender'         = $Policy.EnableUnauthenticatedSender
                        }
                        $PhishSumObj.Add([pscustomobject](ConvertTo-HashToYN $phishSumInObj)) | Out-Null

                        $phishInObj = [ordered] @{
                            'Policy Name'                      = $Policy.Name
                            'Default Policy'                   = $Policy.IsDefault
                            'Enabled'                          = $Policy.Enabled
                            'Phish Threshold Level'            = $Policy.PhishThresholdLevel
                            'User Impersonation Protection'    = $Policy.EnableUserImpersonation
                            'Domain Impersonation Protection'  = $Policy.EnableOrganizationDomainsProtection
                            'Mailbox Intelligence'             = $Policy.EnableMailboxIntelligence
                            'Mailbox Intel Protection'         = $Policy.EnableMailboxIntelligenceProtection
                            'Spoof Intelligence'               = $Policy.EnableSpoofIntelligence
                            'Honor DMARC Policy'               = $Policy.HonorDmarcPolicy
                            'First Contact Safety Tip'         = $Policy.EnableFirstContactSafetyTips
                            'Unauth Sender Indicator'          = $Policy.EnableUnauthenticatedSender
                            'Impersonation Action (User)'      = $Policy.TargetedUserProtectionAction
                            'Impersonation Action (Domain)'    = $Policy.TargetedDomainProtectionAction
                            'Mailbox Intel Action'             = $Policy.MailboxIntelligenceProtectionAction
                            'Spoof Action'                     = $Policy.AuthenticationFailAction
                        }
                        $PhishObj.Add([pscustomobject](ConvertTo-HashToYN $phishInObj)) | Out-Null
                    }

                    $null = (& {
                        if ($HealthCheck.ExchangeOnline.AntiPhishing) {
                            $null = ($PhishSumObj | Where-Object { $_.'User Imp.' -eq 'No' -or
                                $_.'Domain Imp.' -eq 'No' } | Set-Style -Style Critical | Out-Null)
                            $null = ($PhishSumObj | Where-Object { $_.'Spoof Intel' -eq 'No' } | Set-Style -Style Critical | Out-Null)
                            $null = ($PhishSumObj | Where-Object { $_.'Mailbox Intel' -eq 'No' } | Set-Style -Style Warning | Out-Null)
                            $null = ($PhishSumObj | Where-Object { $_.'DMARC Honor' -eq 'No' } | Set-Style -Style Warning | Out-Null)
                        }
                    })

                    # Summary table — 11 cols = 100%
                    $PhishTableParams = @{
                        Name         = "Anti-Phishing Policy Summary - $TenantId"
                        List         = $false
                        ColumnWidths = 16, 7, 7, 8, 8, 9, 9, 9, 9, 10, 8
                    }
                    if ($Report.ShowTableCaptions) { $PhishTableParams['Caption'] = "- $($PhishTableParams.Name)" }
                    $PhishSumObj | Table @PhishTableParams

                    # Full detail in List format (InfoLevel 2)
                    if ($InfoLevel.AntiPhishing -ge 2) {
                        BlankLine
                        foreach ($PolicyDetail in $PhishObj) {
                            $PhishDetailParams = @{ Name = "Anti-Phishing Policy Detail: $($PolicyDetail.'Policy Name') - $TenantId"; List = $true; ColumnWidths = 45, 55 }
                            if ($Report.ShowTableCaptions) { $PhishDetailParams['Caption'] = "- $($PhishDetailParams.Name)" }
                            $PolicyDetail | Table @PhishDetailParams
                        }
                    }

                    $script:ExcelSheets['Anti-Phishing'] = $PhishObj

                    #region Protected Users (Impersonation)
                    if ($InfoLevel.AntiPhishing -ge 2) {
                        $AllProtectedUsers = [System.Collections.ArrayList]::new()
                        foreach ($Policy in $AntiPhishPolicies) {
                            if ($Policy.TargetedUsersToProtect -and $Policy.TargetedUsersToProtect.Count -gt 0) {
                                foreach ($User in $Policy.TargetedUsersToProtect) {
                                    $null = $AllProtectedUsers.Add([pscustomobject]@{
                                        'Policy'        = $Policy.Name
                                        'Protected User' = $User
                                    })
                                }
                            }
                        }
                        if ($AllProtectedUsers.Count -gt 0) {
                            Section -Style Heading3 'Impersonation Protected Users' {
                                Paragraph "The following users are configured for impersonation protection across all anti-phishing policies."
                                BlankLine
                                $PuTableParams = @{ Name = "Protected Users - $TenantId"; List = $false; ColumnWidths = 40, 60 }
                                if ($Report.ShowTableCaptions) { $PuTableParams['Caption'] = "- $($PuTableParams.Name)" }
                                $AllProtectedUsers | Table @PuTableParams
                            }
                        }

                        # Protected Domains
                        $AllProtectedDomains = [System.Collections.ArrayList]::new()
                        foreach ($Policy in $AntiPhishPolicies) {
                            if ($Policy.TargetedDomainsToProtect -and $Policy.TargetedDomainsToProtect.Count -gt 0) {
                                foreach ($Domain in $Policy.TargetedDomainsToProtect) {
                                    $null = $AllProtectedDomains.Add([pscustomobject]@{
                                        'Policy'           = $Policy.Name
                                        'Protected Domain' = $Domain
                                    })
                                }
                            }
                        }
                        if ($AllProtectedDomains.Count -gt 0) {
                            Section -Style Heading3 'Impersonation Protected Domains' {
                                Paragraph "The following domains are configured for impersonation protection across all anti-phishing policies."
                                BlankLine
                                $PdTableParams = @{ Name = "Protected Domains - $TenantId"; List = $false; ColumnWidths = 40, 60 }
                                if ($Report.ShowTableCaptions) { $PdTableParams['Caption'] = "- $($PdTableParams.Name)" }
                                $AllProtectedDomains | Table @PdTableParams
                            }
                        }
                    }
                    #endregion

                    #region Policy Assignments
                    $PhishRules = Get-AntiPhishRule -ErrorAction SilentlyContinue | Sort-Object Priority
                    if ($InfoLevel.AntiPhishing -ge 2 -and $PhishRules) {
                        Section -Style Heading3 'Anti-Phishing Policy Assignments' {
                            Paragraph "The following policy assignments determine which recipients are protected by each anti-phishing policy."
                            BlankLine

                            $RuleObj = [System.Collections.ArrayList]::new()
                            foreach ($Rule in $PhishRules) {
                                $ruleInObj = [ordered] @{
                                    'Rule Name'  = $Rule.Name
                                    'Priority'   = $Rule.Priority
                                    'State'      = $Rule.State
                                    'Policy'     = $Rule.AntiPhishPolicy
                                    'Applied To' = (@($Rule.SentTo) + @($Rule.SentToMemberOf) + @($Rule.RecipientDomainIs)) -join ', '
                                }
                                $RuleObj.Add([pscustomobject]$ruleInObj) | Out-Null
                            }

                            $null = (& {
                                if ($HealthCheck.ExchangeOnline.AntiPhishing) {
                                    $null = ($RuleObj | Where-Object { $_.State -eq 'Disabled' } | Set-Style -Style Warning | Out-Null)
                                }
                            })

                            $RuleTableParams = @{ Name = "Anti-Phishing Policy Assignments - $TenantId"; List = $false; ColumnWidths = 22, 8, 8, 22, 40 }
                            if ($Report.ShowTableCaptions) { $RuleTableParams['Caption'] = "- $($RuleTableParams.Name)" }
                            $RuleObj | Table @RuleTableParams
                        }
                    }
                    #endregion
                } else {
                    Paragraph "No anti-phishing policies found. EOP default policy may apply."
                }
            } catch {
                Write-ExoError 'AntiPhishing' "Unable to retrieve anti-phishing policies: $($_.Exception.Message)"
                Paragraph "Unable to retrieve anti-phishing policy data: $($_.Exception.Message)"
            }


            BlankLine
            Paragraph "ACSC Essential Eight Assessment"
            BlankLine
            $e8Vars = @{
                AntiPhishPolicyCount            = $AntiPhishPolicyCount
                ImpersonationProtectionEnabled  = $ImpersonationProtectionEnabled
                MailboxIntelligenceEnabled      = $MailboxIntelligenceEnabled
                SpoofIntelligenceEnabled        = $SpoofIntelligenceEnabled
                DmarcRejectEnabled              = $DmarcRejectEnabled
                FirstContactSafetyTip           = $FirstContactSafetyTip
            }
            $e8Checks = Build-AbrExoComplianceChecks -Definitions (Get-AbrExoE8Checks 'AntiPhishing') -Framework 'E8' -CallerVariables $e8Vars
            New-AbrExoE8AssessmentTable -Checks $e8Checks -Name 'Anti-Phishing' -TenantId $TenantId
            if ($e8Checks) {
                foreach ($row in $e8Checks) {
                    $null = $script:E8AllChecks.Add([pscustomobject]@{
                        Section = 'Anti-Phishing'
                        ML      = $row.ML
                        Control = $row.Control
                        Status  = $row.Status
                        Detail  = $row.Detail
                    })
                }
            }

            BlankLine
            Paragraph "CIS Microsoft 365 Foundations Benchmark Assessment"
            BlankLine
            $cisVars = @{
                ImpersonationProtectionEnabled = $ImpersonationProtectionEnabled
                SpoofIntelligenceEnabled       = $SpoofIntelligenceEnabled
                MailboxIntelligenceEnabled     = $MailboxIntelligenceEnabled
            }
            $cisChecks = Build-AbrExoComplianceChecks -Definitions (Get-AbrExoCISChecks 'AntiPhishing') -Framework 'CIS' -CallerVariables $cisVars
            New-AbrExoCISAssessmentTable -Checks $cisChecks -Name 'Anti-Phishing' -TenantId $TenantId
            if ($cisChecks) {
                foreach ($row in $cisChecks) {
                    $null = $script:CISAllChecks.Add([pscustomobject]@{
                        Section    = 'Anti-Phishing'
                        CISControl = $row.CISControl
                        Level      = $row.Level
                        Status     = $row.Status
                        Detail     = $row.Detail
                    })
                }
            }
        }

    }



    end {

        Show-AbrDebugExecutionTime -End -TitleMessage 'AntiPhishing'

    }

}