Src/Private/Get-AbrExoAntiMalware.ps1

function Get-AbrExoAntiMalware {
    <#
    .SYNOPSIS
    Documents Exchange Online anti-malware 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-Malware configuration for $TenantId."
        Show-AbrDebugExecutionTime -Start -TitleMessage 'AntiMalware'
    }

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

            # Compliance variable defaults
            $MalwarePolicyEnabled           = $false
            $CommonAttachmentFilterEnabled  = $false
            $ZapForMalwareEnabled           = $false
            $MalwareAdminNotifyEnabled      = $false

            try {
                Write-Host " - Retrieving anti-malware policies..."
                $MalwarePolicies = Get-MalwareFilterPolicy -ErrorAction Stop | Sort-Object IsDefault -Descending

                if ($MalwarePolicies) {
                    $DefaultPolicy = $MalwarePolicies | Where-Object { $_.IsDefault } | Select-Object -First 1
                    if (-not $DefaultPolicy) { $DefaultPolicy = $MalwarePolicies | Select-Object -First 1 }
                    $MalwarePolicyEnabled          = $true
                    $CommonAttachmentFilterEnabled = ($DefaultPolicy.EnableFileFilter -eq $true)
                    $ZapForMalwareEnabled          = ($DefaultPolicy.ZapEnabled -eq $true)
                    $MalwareAdminNotifyEnabled     = ($DefaultPolicy.EnableInternalSenderAdminNotifications -eq $true -or
                                                      $DefaultPolicy.EnableExternalSenderAdminNotifications -eq $true)

                    $MalwareObj = [System.Collections.ArrayList]::new()
                    foreach ($Policy in $MalwarePolicies) {
                        $malInObj = [ordered] @{
                            'Policy Name'                        = $Policy.Name
                            'Default Policy'                     = $Policy.IsDefault
                            'Action'                             = $Policy.Action
                            'Common Attachment Filter'           = $Policy.EnableFileFilter
                            'ZAP Enabled'                        = $Policy.ZapEnabled
                            'Internal Sender Admin Notify'       = $Policy.EnableInternalSenderAdminNotifications
                            'External Sender Admin Notify'       = $Policy.EnableExternalSenderAdminNotifications
                            'Internal Admin Notify Address'      = if ($Policy.InternalSenderAdminAddress) { $Policy.InternalSenderAdminAddress } else { 'Not Set' }
                            'Delete Unscanned Attachments'       = $Policy.DeleteAttachmentAndUseDefaultAlertText
                        }
                        $MalwareObj.Add([pscustomobject](ConvertTo-HashToYN $malInObj)) | Out-Null
                    }

                    $null = (& {
                        if ($HealthCheck.ExchangeOnline.AntiMalware) {
                            $null = ($MalwareObj | Where-Object { $_.'Common Attachment Filter' -eq 'No' } | Set-Style -Style Critical | Out-Null)
                            $null = ($MalwareObj | Where-Object { $_.'ZAP Enabled' -eq 'No' } | Set-Style -Style Warning | Out-Null)
                            $null = ($MalwareObj | Where-Object { $_.'Internal Sender Admin Notify' -eq 'No' } | Set-Style -Style Warning | Out-Null)
                        }
                    })

                    $MalTableParams = @{ Name = "Anti-Malware Policies - $TenantId"; List = $false; ColumnWidths = 15, 8, 8, 12, 8, 12, 12, 16, 9 }
                    if ($Report.ShowTableCaptions) { $MalTableParams['Caption'] = "- $($MalTableParams.Name)" }
                    $MalwareObj | Table @MalTableParams

                    $script:ExcelSheets['Anti-Malware'] = $MalwareObj

                    #region Common Attachment Filter File Types
                    if ($InfoLevel.AntiMalware -ge 2) {
                        $DefaultFileTypes = $DefaultPolicy.FileTypes
                        if ($DefaultFileTypes -and $DefaultFileTypes.Count -gt 0) {
                            Section -Style Heading3 'Blocked File Types (Common Attachment Filter)' {
                                Paragraph "The following file types are blocked by the common attachment filter in the default anti-malware policy."
                                BlankLine
                                Paragraph ($DefaultFileTypes -join ', ')
                            }
                        }
                    }
                    #endregion

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

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

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

                            $RuleTableParams = @{ Name = "Anti-Malware 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-malware policies found. This is unexpected and should be investigated."
                }
            } catch {
                Write-ExoError 'AntiMalware' "Unable to retrieve anti-malware policies: $($_.Exception.Message)"
                Paragraph "Unable to retrieve anti-malware policy data: $($_.Exception.Message)"
            }


            BlankLine
            Paragraph "ACSC Essential Eight Assessment"
            BlankLine
            $e8Vars = @{
                MalwarePolicyEnabled            = $MalwarePolicyEnabled
                CommonAttachmentFilterEnabled   = $CommonAttachmentFilterEnabled
                ZapForMalwareEnabled            = $ZapForMalwareEnabled
                MalwareAdminNotifyEnabled       = $MalwareAdminNotifyEnabled
            }
            $e8Checks = Build-AbrExoComplianceChecks -Definitions (Get-AbrExoE8Checks 'AntiMalware') -Framework 'E8' -CallerVariables $e8Vars
            New-AbrExoE8AssessmentTable -Checks $e8Checks -Name 'Anti-Malware' -TenantId $TenantId
            if ($e8Checks) {
                foreach ($row in $e8Checks) {
                    $null = $script:E8AllChecks.Add([pscustomobject]@{
                        Section = 'Anti-Malware'
                        ML      = $row.ML
                        Control = $row.Control
                        Status  = $row.Status
                        Detail  = $row.Detail
                    })
                }
            }

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

    }



    end {

        Show-AbrDebugExecutionTime -End -TitleMessage 'AntiMalware'

    }

}