Scripts/Get-AuditLogSettings.ps1

function Get-MailboxAuditStatus {
<#
    .SYNOPSIS
    Retrieves audit status and settings for all mailboxes in Microsoft 365.
 
    .DESCRIPTION
    Retrieves detailed information about mailbox audit settings, including audit status, bypass settings,
    and configured audit actions for owners, delegates, and administrators.
 
    .PARAMETER OutputDir
    Specifies the output directory for the audit status report.
    Default: Output\Audit Status
 
    .PARAMETER Encoding
    Specifies the encoding of the CSV output file.
    Default: UTF8
 
    .PARAMETER UserIds
    UserIds is the UserIds parameter filtering the log entries by the account of the user who performed the actions.
 
    .PARAMETER LogLevel
    Specifies the level of logging:
    None: No logging
    Minimal: Critical errors only
    Standard: Normal operational logging
    Default: Standard
     
    .EXAMPLE
    Get-MailboxAuditStatus
    Retrieves audit status for all mailboxes and exports to a CSV file in the default directory.
         
    .EXAMPLE
    Get-MailboxAuditStatus -OutputDir C:\Temp -Encoding UTF32
    Retrieves audit status and saves the output to C:\Temp with UTF-32 encoding.
#>

    [CmdletBinding()]
    param (
        [string]$OutputDir = "Output\Audit Status",
        [string]$Encoding = "UTF8",
        [ValidateSet('None', 'Minimal', 'Standard')]
        [string]$LogLevel = 'Standard',
        [string]$UserIds
    )

    Set-LogLevel -Level ([LogLevel]::$LogLevel)
    $summary = @{
        TotalMailboxes = 0
        AuditEnabled = 0
        AuditDisabled = 0
        AuditBypass = 0
        OwnerActionsConfigured = 0
        DelegateActionsConfigured = 0
        AdminActionsConfigured = 0
        ProcessedMailboxes = 0
        StartTime = Get-Date
        ProcessingTime = $null
        OrgWideAuditingEnabled = $false
    }

    Write-LogFile -Message "=== Starting Mailbox Audit Status Collection ===" -Color "Cyan" -Level Minimal

    if (!(Test-Path $OutputDir)) {
        New-Item -ItemType Directory -Force -Path $OutputDir > $null
    } else {
        if (!(Test-Path -Path $OutputDir)) {
            Write-LogFile -Message "[ERROR] Custom directory invalid: $OutputDir" -Level Minimal -Color "Red"
            return
        }
    }

    $date = Get-Date -Format "yyyyMMddHHmm"
    $outputFile = "$date-MailboxAuditStatus.csv"
    $outputDirectory = Join-Path $OutputDir $outputFile

    try {
        $orgConfig = Get-OrganizationConfig | Select-Object -ExpandProperty AuditDisabled
        $summary.OrgWideAuditingEnabled = -not $orgConfig
        
        if ($orgConfig) {
            Write-LogFile -Message "[WARNING] Organization-wide auditing is disabled!" -Level Minimal -Color "Red"
        } else {
            Write-LogFile -Message "[INFO] Organization-wide auditing is enabled - This overrides individual mailbox settings" -Level Standard -Color "Green"
        }
    }
    catch {
        Write-LogFile -Message "[INFO] Ensure you are connected to M365 by running the Connect-ExchangeOnline or Connect-M365 command before executing this script" -Level Minimal -Color "Yellow"
        Write-LogFile -Message "[ERROR] An error occurred: $($_.Exception.Message)" -Level Minimal -Color "Red"
        throw
    }

    Write-LogFile -Message "[INFO] Retrieving mailbox list..." -Level Standard
    $mailboxes = Get-EXOMailbox -ResultSize unlimited -PropertySets All
    $summary.TotalMailboxes = $mailboxes.Count
    Write-LogFile -Message "[INFO] Found $($mailboxes.Count) mailboxes to process" -Level Standard

    Write-LogFile -Message "[INFO] Retrieving audit bypass associations..." -Level Standard
    $bypassLookup = @{}

    foreach ($mailbox in $mailboxes) {
        $bypassLookup[$mailbox.UserPrincipalName] = $false
    }

    try {
        Write-LogFile -Message "[INFO] Attempting bulk retrieval of audit bypass associations..." -Level Standard
        $bypassAssociations = Get-MailboxAuditBypassAssociation -ResultSize Unlimited -WarningAction SilentlyContinue | 
            Select-Object Identity, AuditBypassEnabled | 
            Where-Object { $_.AuditBypassEnabled -eq $true }
        
        foreach ($bypass in $bypassAssociations) {
            if ($null -ne $bypass.Identity) {
                $bypassLookup[$bypass.Identity] = $True
            }
        }
    }
    catch {
        Write-LogFile -Message "[WARNING] Bulk retrieval failed, likely due to too many mailboxes. This will timeout the cmdlet. Processing mailboxes individually..." -Level Standard -Color "Yellow"
        Write-LogFile -Message "[WARNING] This may take some time..." -Level Standard -Color "Yellow"

        $batchSize = 10
        for ($i = 0; $i -lt $mailboxes.Count; $i += $batchSize) {
            $batch = $mailboxes | Select-Object -Skip $i -First $batchSize
            
            foreach ($mbx in $batch) {
                try {
                    $bypass = Get-MailboxAuditBypassAssociation -Identity $mbx.UserPrincipalName -WarningAction SilentlyContinue | Select-Object Identity, AuditBypassEnabled
                    if ($bypass -and $bypass.Identity) {
                        $bypassLookup[$bypass.Identity] = [bool]$bypass.AuditBypassEnabled 
                    }
                    else {
                        $bypassLookup[$mbx.UserPrincipalName] = $false
                    }
                }
                catch {
                    $bypassLookup[$mbx.UserPrincipalName] = $false
                    continue
                }
            }
            
            $processed = [Math]::Min($i + $batchSize, $mailboxes.Count)
            $percentage = [math]::Round(($processed / $mailboxes.Count) * 100, 2)
            Write-LogFile -Message "[INFO] Processed bypass status: $processed/$($mailboxes.Count) mailboxes ($percentage%)" -Level Standard
            Start-Sleep -Seconds 5 # Otherwise it might still timeout.
        }
    }

    $results = @()

    foreach ($mailbox in $mailboxes) {
        $summary.ProcessedMailboxes++
        $bypassStatus = $bypassLookup[$mailbox.UserPrincipalName]

        if ($mailbox.AuditEnabled) { $summary.AuditEnabled++ }
        else { $summary.AuditDisabled++ }
        if ($bypassStatus) { $summary.AuditBypass++ }
        if ($mailbox.AuditOwner) { $summary.OwnerActionsConfigured++ }
        if ($mailbox.AuditDelegate) { $summary.DelegateActionsConfigured++ }
        if ($mailbox.AuditAdmin) { $summary.AdminActionsConfigured++ }

         # Sort the audit actions for each category
         $ownerActions = if ($mailbox.AuditOwner) { 
            ($mailbox.AuditOwner | Sort-Object) -join ', ' 
        } else { 
            '' 
        }
        
        $delegateActions = if ($mailbox.AuditDelegate) { 
            ($mailbox.AuditDelegate | Sort-Object) -join ', ' 
        } else { 
            '' 
        }
        
        $adminActions = if ($mailbox.AuditAdmin) { 
            ($mailbox.AuditAdmin | Sort-Object) -join ', ' 
        } else { 
            '' 
        }

        $defaultAuditSet = if ($mailbox.DefaultAuditSet) {
            ($mailbox.DefaultAuditSet | Sort-Object) -join ', '
        } else {
            ''
        }

        $results += [PSCustomObject]@{
            UserPrincipalName = $mailbox.UserPrincipalName
            DisplayName = $mailbox.DisplayName
            RecipientTypeDetails = $mailbox.RecipientTypeDetails
            AuditEnabled = $mailbox.AuditEnabled
            AuditBypassEnabled = $bypassStatus
            DefaultAuditSet = $defaultAuditSet
            OwnerAuditActions = $ownerActions
            OwnerAuditActionsCount = if ($mailbox.AuditOwner) { $mailbox.AuditOwner.Count } else { 0 }
            DelegateAuditActions = $delegateActions
            DelegateAuditActionsCount = if ($mailbox.AuditDelegate) { $mailbox.AuditDelegate.Count } else { 0 }
            AdminAuditActions = $adminActions
            AdminAuditActionsCount = if ($mailbox.AuditAdmin) { $mailbox.AuditAdmin.Count } else { 0 }
            EffectiveAuditState = if ($summary.OrgWideAuditingEnabled -and -not $bypassStatus) { 
                "Enabled (Organization Policy)" 
            } elseif ($bypassStatus) {
                "Bypassed"
            } else {
                "Disabled"
            }
        }
    }

    $results | Export-Csv -Path $outputDirectory -NoTypeInformation -Encoding $Encoding
    $summary.ProcessingTime = (Get-Date) - $summary.StartTime
    
    Write-LogFile -Message "`nOrganization Configuration:" -Level Standard -Color "Cyan"
    Write-LogFile -Message " Organization-wide Auditing: $(if ($summary.OrgWideAuditingEnabled) { 'Enabled' } else { 'Disabled' })" -Level Standard
    if ($summary.OrgWideAuditingEnabled) {
        Write-LogFile -Message " [!] Organization-wide auditing overrides individual mailbox settings" -Level Standard
        Write-LogFile -Message " [!] Default actions are automatically logged for all non-bypassed mailboxes" -Level Standard
    }
    Write-LogFile -Message "`nMailbox Statistics:" -Level Standard -Color "Cyan"
    Write-LogFile -Message " Total Mailboxes: $($summary.TotalMailboxes)" -Level Standard
    Write-LogFile -Message " Audit Enabled: $($summary.AuditEnabled)" -Level Standard
    Write-LogFile -Message " Audit Disabled: $($summary.AuditDisabled)" -Level Standard
    Write-LogFile -Message " Audit Bypass Enabled: $($summary.AuditBypass)" -Level Standard
    
    Write-LogFile -Message "`nAudit Actions Configured:" -Level Standard -Color "Cyan"
    Write-LogFile -Message " Owner Actions: $($summary.OwnerActionsConfigured)" -Level Standard
    Write-LogFile -Message " Delegate Actions: $($summary.DelegateActionsConfigured)" -Level Standard
    Write-LogFile -Message " Admin Actions: $($summary.AdminActionsConfigured)" -Level Standard
    
    Write-LogFile -Message "`nOutput Details:" -Level Standard -Color "Cyan"
    Write-LogFile -Message " Output File: $outputDirectory" -Level Standard
    Write-LogFile -Message " Processing Time: $($summary.ProcessingTime.ToString('mm\:ss'))" -Level Standard
    Write-LogFile -Message "===================================" -Color "Cyan" -Level Standard
}