public/ExchangeOnline/Register-EXOReport.ps1

<# Mail Domain section #>
function Get-MailDomainReport {
    Write-Host "Checking domains"
    $Domains = Get-DkimSigningConfig | Select-Object -Property Id, @{Name = "Default"; Expression = { $_.IsDefault } }, @{Name = "DKIM"; Expression = { $_.Enabled } }
    if (-not ($Domains)) { $Domains = Get-AcceptedDomain | Select-Object -Property Id, "Default", @{Name = "DKIM"; Expression = { $false } } }
    $DomainsReport = @()
    foreach ($Domain in $Domains) {
        $ProcessedCount++
        Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Domain.Id)"
        $Domain = Get-DMARC -Domain $Domain
        $Domain = Get-SPF -Domain $Domain
        $DomainsReport += $Domain
    }
    Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Domain.Id)" -Status "Ready" -Completed
    $Report = $DomainsReport | ConvertTo-Html -As Table -Property Id, DKIM, DMARC, SPF, "DMARC record", "SPF record", "DMARC hint", "SPF hint", "Default" -Fragment -PreContent "<h3 id='EXO_DOMAIN'>Domains</h3>"
    $Report = $Report -Replace "<td>False</td><td>False</td><td>False</td>", "<td class='red'>False</td><td class='red'>False</td><td class='red'>False</td>"
    $Report = $Report -Replace "<td>False</td><td>False</td><td>True</td>", "<td class='red'>False</td><td class='red'>False</td><td>True</td>"
    $Report = $Report -Replace "<td>True</td><td>False</td><td>False</td>", "<td>True</td><td class='red'>False</td><td class='red'>False</td>"
    $Report = $Report -Replace "<td>True</td><td>False</td><td>True</td>", "<td>True</td><td class='red'>False</td><td>True</td>"
    $Report = $Report -Replace "<td>False</td><td>True</td><td>False</td>", "<td class='red'>False</td><td>True</td><td class='red'>False</td>"
    $Report = $Report -Replace "<td>False</td><td>True</td><td>True</td>", "<td class='red'>False</td><td>True</td><td>True</td>"
    $Report = $Report -Replace "<td>Should be p=reject</td>", "<td class='orange'>Should be p=reject</td>"
    $Report = $Report -Replace "<td>Not sufficiently stricth</td>", "<td class='orange'>Not sufficiently strict</td>"
    $Report = $Report -Replace "<td>Not effective enough</td>", "<td class='red'>Not effective enough</td>"
    $Report = $Report -Replace "<td>Does not protect</td>", "<td class='red'>Does not protect</td>"
    $Report = $Report -Replace "<td>No qualifier found</td>", "<td class='red'>No qualifier found</td>"
    return $Report
}
function Get-DMARC {
    param($Domain)
    $DMARCRecord = (Resolve-Dns -Query "_dmarc.$($Domain.Id)" -QueryType TXT | Select-Object -Expand Answers).Text
    if ($null -eq $DMARCRecord ) {
        $DMARC = $false
    }
    else {
        switch -Regex ($DMARCRecord ) {
            ('p=none') {
                $DmarcHint = "Does not protect"
                $DMARC = $true
            }
            ('p=quarantine') {
                $DmarcHint = "Should be p=reject"
                $DMARC = $true
            }
            ('p=reject') {
                $DmarcHint = "Will protect"
                $DMARC = $true
            }
            ('sp=none') {
                $DmarcHint += "Does not protect"
                $DMARC = $true
            }
            ('sp=quarantine') {
                $DmarcHint += "Should be p=reject"
                $DMARC = $true
            }
            ('sp=reject') {
                $DmarcHint += "Will protect"
                $DMARC = $true
            }
        }
    }
    $Domain | Add-Member NoteProperty "DMARC" $DMARC
    $Domain | Add-Member NoteProperty "DMARC record" "$($DMARCRecord )"
    $Domain | Add-Member NoteProperty "DMARC hint" $DmarcHint
    return $Domain
}
function Get-SPF {
    param($Domain)
    $SPFRecord = (Resolve-Dns -Query $Domain.Id -QueryType TXT | Select-Object -Expand Answers).Text | Where-Object { $_ -match "v=spf1" }
    if ($SPFRecord -match "redirect") {
        $redirect = $SPFRecord.Split(" ")
        $RedirectName = $redirect -match "redirect" -replace "redirect="
        $SPFRecord = (Resolve-Dns -Query $RedirectName -QueryType TXT | Select-Object -Expand Answers).Text | Where-Object { $_ -match "v=spf1" }
    }
    if ($null -eq $SPFRecord) {
        $SPF = $false
    }
    if ($SPFRecord -is [array]) {
        $SPFHint = "More than one SPF-record"
        $SPF = $true
    }
    Else {
        switch -Regex ($SPFRecord) {
            '~all' {
                $SPFHint = "Not sufficiently strict"
                $SPF = $true
            }
            '-all' {
                $SPFHint = "Sufficiently strict"
                $SPF = $true
            }
            "\?all" {
                $SPFHint = "Not effective enough"
                $SPF = $true
            }
            '\+all' {
                $SPFHint = "Not effective enough"
                $SPF = $true
            }
            Default {
                $SPFHint = "No qualifier found"
                $SPF = $true
            }
        }
    }
    $Domain | Add-Member NoteProperty "SPF" "$($SPF)"
    $Domain | Add-Member NoteProperty "SPF record" "$($SPFRecord)"
    $Domain | Add-Member NoteProperty "SPF hint" $SPFHint
    return $Domain
}

<# Mail connector section#>
function Get-MailConnectorReport {
    Write-Host "Checking mail connectors"
    if (-not ($Inbound = Get-InboundConnector)) { $InboundReport = "<br><h3 id='EXO_CONNECTOR_IN'>Inbound mail connector</h3><p>Not found</p>" }
    else { $InboundReport = $Inbound | ConvertTo-Html -As Table -Property Name, SenderDomains, SenderIPAddresses, Enabled -Fragment -PreContent "<br><h3 id='EXO_CONNECTOR_IN'>Inbound mail connector</h3>" }
    if (-not ($Outbound = Get-OutboundConnector -IncludeTestModeConnectors:$true)) { $OutboundReport = "<br><h3 id='EXO_CONNECTOR_OUT'>Outbound mail connector</h3><p>Not found</p>" }
    else { $OutboundReport = $Outbound | ConvertTo-Html -As Table -Property Name, RecipientDomains, SmartHosts, Enabled -Fragment -PreContent "<br><h3 id='EXO_CONNECTOR_OUT'>Outbound mail connector</h3>" }
    $Report = @()
    $Report += $InboundReport
    $Report += $OutboundReport
    return $Report
}

<# User mailbox section #>
function Get-UserMailboxReport {
    param(
        [System.Boolean]$Language
    )
    Write-Host "Checking user mailboxes"
    if ( -not ($Mailboxes = Get-EXOMailbox -RecipientTypeDetails UserMailbox -ResultSize:Unlimited -Properties DisplayName, UserPrincipalName)) {
        return "<br><h3 id='EXO_USER'>User mailbox</h3><p>Not found</p>"
    }
    if ($Language) {
        Update-MailboxLang -Mailbox $Mailboxes
    }
    $MailboxReport = @()
    foreach ($Mailbox in $Mailboxes) {
        $ProcessedCount++
        Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Mailbox.DisplayName)"
        $MailboxReport += Get-MailboxLoginAndLocation $Mailbox
    }
    Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Mailbox.DisplayName)" -Status "Ready" -Completed
    return $MailboxReport | ConvertTo-Html -As Table -Property UserPrincipalName, DisplayName, Language, TimeZone, LoginAllowed `
        -Fragment -PreContent "<br><h3 id='EXO_USER'>User mailbox</h3>"
}
function Update-MailboxLang {
    param(
        $Mailbox
    )
    Write-Host "Setting mailboxes language:" $script:MailboxLanguageCode "timezone:" $script:MailboxTimeZone
    $Mailbox | Set-MailboxRegionalConfiguration -LocalizeDefaultFolderName:$true -Language $script:MailboxLanguageCode -TimeZone $script:MailboxTimeZone
}

<# Shared mailbox section #>
function Get-SharedMailboxReport {
    param(
        [System.Boolean]$Language,
        [System.Boolean]$DisableLogin,
        [System.Boolean]$EnableCopy
    )
    Write-Host "Checking shared mailboxes"
    if ( -not ($Mailboxes = Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited -Properties DisplayName,
            UserPrincipalName, MessageCopyForSentAsEnabled, MessageCopyForSendOnBehalfEnabled)) {
        return "<br><h3 id='EXO_SHARED'>Shared mailbox</h3><p>Not found</p>"
    }
    if ($Language) { Update-MailboxLang -Mailbox $Mailboxes }
    if ($DisableLogin) { Disable-UserAccount $Mailboxes }
    if ($EnableCopy) {
        Enable-SharedMailboxEnableCopyToSent $Mailboxes
        $Mailboxes = Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited -Properties DisplayName,
        UserPrincipalName, MessageCopyForSentAsEnabled, MessageCopyForSendOnBehalfEnabled
    }
    $MailboxReport = @()
    foreach ($Mailbox in $Mailboxes) {
        $ProcessedCount++
        Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Mailbox.DisplayName)"
        $MailboxReport += Get-MailboxLoginAndLocation $Mailbox
    }
    Write-Progress -Activity "Processed count: $ProcessedCount; Currently processing: $($Mailbox.DisplayName)" -Status "Ready" -Completed
    $Report = $MailboxReport | ConvertTo-Html -As Table -Property UserPrincipalName, DisplayName, Language, TimeZone, MessageCopyForSentAsEnabled,
    MessageCopyForSendOnBehalfEnabled, LoginAllowed -Fragment -PreContent "<br><h3 id='EXO_SHARED'>Shared mailbox</h3>"
    $Report = $Report -Replace "<td>True</td><td>True</td><td>True</td>", "<td>True</td><td>True</td><td class='red'>True</td>"
    $Report = $Report -Replace "<td>False</td><td>False</td><td>True</td>", "<td>False</td><td>False</td><td class='red'>True</td>"
    $Report = $Report -Replace "<td>True</td><td>False</td><td>True</td>", "<td>True</td><td>False</td><td class='red'>True</td>"
    $Report = $Report -Replace "<td>False</td><td>True</td><td>True</td>", "<td>False</td><td>True</td><td class='red'>True</td>"
    return $Report
}
function Get-MailboxLoginAndLocation {
    param (
        $Mailbox
    )
    $ReginalConfig = $Mailbox | Get-MailboxRegionalConfiguration
    Add-Member -InputObject $Mailbox -NotePropertyName "Language" -NotePropertyValue $ReginalConfig.Language
    Add-Member -InputObject $Mailbox -NotePropertyName "TimeZone" -NotePropertyValue $ReginalConfig.TimeZone
    Add-Member -InputObject $Mailbox -NotePropertyName "LoginAllowed" -NotePropertyValue (Request-UserAccountStatus $Mailbox.UserPrincipalName)
    return $Mailbox
}
function Enable-SharedMailboxEnableCopyToSent {
    param(
        $Mailbox
    )
    Write-Host "Enable shared mailbox copy to sent"
    $Mailbox | Set-Mailbox -MessageCopyForSentAsEnabled $True -MessageCopyForSendOnBehalfEnabled $True
}

<# Unified mailbox section #>
function Get-UnifiedMailboxReport {
    param(
        [System.Boolean]$HideFromClient
    )
    Write-Host "Checking unified mailboxes"
    if ( -not ($Mailboxes = Get-UnifiedGroup -ResultSize Unlimited)) {
        return "<br><h3 id='EXO_UNIFIED'>Unified mailbox</h3><p>Not found</p>"
    }
    if ($HideFromClient) {
        Write-Host "Hiding unified mailboxes from outlook client"
        $Mailboxes | Set-UnifiedGroup -HiddenFromExchangeClientsEnabled:$true -HiddenFromAddressListsEnabled:$false
        $Mailboxes = Get-UnifiedGroup -ResultSize Unlimited 
    }
    return $Mailboxes | Sort-Object -Property PrimarySmtpAddress | ConvertTo-Html -As Table -Property DisplayName, PrimarySmtpAddress, HiddenFromAddressListsEnabled, HiddenFromExchangeClientsEnabled -Fragment -PreContent "<br><h3 id='EXO_UNIFIED'>Unified mailbox</h3>" -PostContent "<p>Unified groups = Microsoft 365 groups</p>"
}