Public/Get-MailboxSecurityAudit.ps1

function Get-MailboxSecurityAudit {
    <#
    .SYNOPSIS
        Audits mailboxes for forwarding, inbox forwarding rules, auditing, and SMTP AUTH.
    .DESCRIPTION
        Requires Connect-ExchangeOnline. Read-only. For each mailbox reports:
          * Mailbox-level forwarding (ForwardingSmtpAddress / ForwardingAddress)
          * Inbox rules that forward, redirect, or forward-as-attachment, flagging external targets
          * Whether mailbox auditing is enabled
          * Whether SMTP client authentication is enabled (per mailbox and tenant default)
    .PARAMETER AcceptedDomain
        Domains treated as internal. Defaults to the tenant's accepted domains.
    .PARAMETER ResultSize
        Number of mailboxes to scan. Default Unlimited.
    .PARAMETER SkipInboxRules
        Skip the (slow) per-mailbox inbox rule scan.
    .PARAMETER OutputFolder
        Folder for CSV output. Defaults to ./output.
    .EXAMPLE
        Get-MailboxSecurityAudit -ResultSize 100
    .NOTES
        Role required: View-Only Organization Management or Exchange Administrator.
    #>

    [CmdletBinding()]
    param(
        [string[]]$AcceptedDomain,
        [string]$ResultSize = 'Unlimited',
        [switch]$SkipInboxRules,
        [string]$OutputFolder = (Join-Path (Get-Location) 'output')
    )
    $ErrorActionPreference = 'Stop'
    if (-not (Get-Command Get-EXOMailbox -ErrorAction SilentlyContinue)) {
        throw 'Get-EXOMailbox not found. Run Connect-ExchangeOnline first.'
    }
    New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null

    if (-not $AcceptedDomain) { $AcceptedDomain = (Get-AcceptedDomain).DomainName }
    $tenantSmtpAuthDisabled = (Get-TransportConfig).SmtpClientAuthenticationDisabled

    function Test-IsExternal {
        param([string]$Address)
        if (-not $Address) { return $false }
        # Rule targets look like "Name" [SMTP:user@contoso.com]; pull out the address.
        $addr = if ($Address -match '([\w.+-]+@[\w.-]+)') { $Matches[1] } else { $Address }
        $domain = ($addr -split '@')[-1].TrimEnd(']')
        return $domain -notin $AcceptedDomain
    }

    $mailboxes = Get-EXOMailbox -ResultSize $ResultSize -RecipientTypeDetails UserMailbox, SharedMailbox `
        -Properties ForwardingSmtpAddress, ForwardingAddress, DeliverToMailboxAndForward, AuditEnabled
    $casLookup = @{}
    Get-EXOCASMailbox -ResultSize $ResultSize -Properties SmtpClientAuthenticationDisabled |
        ForEach-Object { $casLookup[$_.PrimarySmtpAddress] = $_.SmtpClientAuthenticationDisabled }

    $i = 0
    $rows = foreach ($mbx in $mailboxes) {
        $i++
        Write-Progress -Activity 'Auditing mailboxes' -Status $mbx.PrimarySmtpAddress -PercentComplete ($i / @($mailboxes).Count * 100)

        $fwdRules = @()
        if (-not $SkipInboxRules) {
            $fwdRules = @(Get-InboxRule -Mailbox $mbx.PrimarySmtpAddress -ErrorAction SilentlyContinue |
                Where-Object { $_.Enabled -and ($_.ForwardTo -or $_.RedirectTo -or $_.ForwardAsAttachmentTo) })
        }
        $ruleTargets = $fwdRules | ForEach-Object { $_.ForwardTo; $_.RedirectTo; $_.ForwardAsAttachmentTo } | Where-Object { $_ }
        $mbxFwd = ($mbx.ForwardingSmtpAddress -replace '^smtp:', '')

        # $null on the CAS mailbox means "inherit tenant setting".
        $casValue = $casLookup[$mbx.PrimarySmtpAddress]
        $smtpAuthEnabled = if ($null -eq $casValue) { -not $tenantSmtpAuthDisabled } else { -not $casValue }

        [pscustomobject]@{
            Mailbox                 = $mbx.PrimarySmtpAddress
            Type                    = $mbx.RecipientTypeDetails
            ForwardingSmtpAddress   = $mbxFwd
            ForwardingAddress       = $mbx.ForwardingAddress
            DeliverAndForward       = $mbx.DeliverToMailboxAndForward
            ExternalMailboxForward  = Test-IsExternal $mbxFwd
            ForwardingRuleCount     = $fwdRules.Count
            ForwardingRuleNames     = $fwdRules.Name -join ';'
            ExternalRuleForward     = [bool]($ruleTargets | Where-Object { Test-IsExternal $_ })
            AuditEnabled            = $mbx.AuditEnabled
            SmtpAuthEnabled         = $smtpAuthEnabled
        }
    }
    Write-Progress -Activity 'Auditing mailboxes' -Completed

    $file = Join-Path $OutputFolder "MailboxSecurityAudit-$(Get-Date -Format 'yyyyMMdd-HHmm').csv"
    $rows | Export-Csv -Path $file -NoTypeInformation
    $flagged = @($rows | Where-Object { $_.ExternalMailboxForward -or $_.ExternalRuleForward -or -not $_.AuditEnabled -or $_.SmtpAuthEnabled })
    Write-Information "Mailboxes: $(@($rows).Count) Flagged: $($flagged.Count) Tenant SMTP AUTH disabled: $tenantSmtpAuthDisabled -> $file" -InformationAction Continue
}