Public/Export-M365MailForwardingReport.ps1
|
function Export-M365MailForwardingReport { <# .SYNOPSIS Generates an interactive HTML report of inbox rules that forward mail externally. .DESCRIPTION Builds on Get-M365MailForwarding and renders a self-contained HTML page: a KPI overview (rules, affected users, enabled rules) and a searchable table with rule, action, external recipients and enabled state. Read-only. Scanning every mailbox can be slow on large tenants. .PARAMETER Path Target path of the HTML file. Default: .\MailForwarding-Report.html .PARAMETER BrandName Branding. For CloudNest365: -BrandName 'CloudNest365' .PARAMETER PassThru Also emit the objects on the pipeline. .PARAMETER NoOpen Do not open the report automatically. .EXAMPLE Export-M365MailForwardingReport -BrandName 'CloudNest365' #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string]$Path = (Join-Path (Get-Location) 'MailForwarding-Report.html'), [string]$BrandName = 'TenantToolbox', [string]$BrandTagline = 'M365 Tenant Administration', [switch]$Csv, [switch]$Excel, [string]$DataPath, [switch]$NoHtml, [switch]$PassThru, [switch]$NoOpen ) Assert-TTGraph Write-Host "Scanning mailboxes for external forwarding rules (may take a while) ..." -ForegroundColor DarkGray $data = @(Get-M365MailForwarding) $total = $data.Count $users = @($data | Select-Object -ExpandProperty UPN -Unique).Count $enabled = @($data | Where-Object Enabled).Count $genAt = Get-Date -Format 'yyyy-MM-dd HH:mm' $tenant = (Get-MgContext).TenantId $rows = foreach ($r in ($data | Sort-Object @{E = { -[int][bool]$_.Enabled } }, User)) { $fEnabled = if ($r.Enabled) { '1' } else { '0' } $enBadge = if ($r.Enabled) { "<span class='b b-bad'>enabled</span>" } else { "<span class='muted'>disabled</span>" } $extChips = (@($r.External) | ForEach-Object { "<span class='chip chip-exc'>$(TTEnc $_)</span>" }) -join ' ' $searchAttr = TTEnc ("$($r.User) $($r.UPN) $($r.Rule) $(@($r.External) -join ' ')".ToLower()) $nameAttr = TTEnc ([string]$r.User).ToLower() @" <tr class="item" data-f-enabled="$fEnabled" data-name="$nameAttr" data-search="$searchAttr"> <td><div class="u"><b>$(TTEnc $r.User)</b><span class="upn">$(TTEnc $r.UPN)</span></div></td> <td>$(TTEnc $r.Rule)</td> <td>$(TTEnc $r.Action)</td> <td><div class="chips">$extChips</div></td> <td>$enBadge</td> </tr> "@ } $kpiHtml = New-TTKpis @( @{ n = $total; l = 'Forwarding rules'; filter = 'all' } @{ n = $users; l = 'Affected users'; kind = 'bad' } @{ n = $enabled; l = 'Enabled rules'; kind = 'bad'; filter = 'enabled' } ) $toolbar = New-TTToolbar -SearchPlaceholder 'Search user, rule or recipient ...' -Filters @( @{ label = 'All'; key = 'all' }, @{ label = 'Enabled'; key = 'enabled' } ) $body = @" <div class="panel"> <table class="tbl"> <thead><tr><th data-sort="name">User</th><th>Rule</th><th>Action</th><th>External recipients</th><th>State</th></tr></thead> <tbody> $($rows -join "`n") </tbody> </table> <div class="empty" id="empty">No forwarding rule matches the filters.</div> </div> "@ $sub = "Tenant $tenant · generated $genAt · $total external forwarding rules on $users users" $html = New-TTHtmlPage -Title 'External Mail Forwarding' -Heading 'External Mail Forwarding' -Sub $sub ` -BrandName $BrandName -BrandTagline $BrandTagline -KpiHtml $kpiHtml -ToolbarHtml $toolbar -BodyHtml $body Write-TTLog -Level INFO -Message "Mail forwarding report created: $Path ($total rules, $users users, $enabled enabled)." if ($enabled -gt 0) { Write-Host " Warning: $enabled enabled external-forwarding rule(s) - review for compromise!" -ForegroundColor Red } $flat = $data | Select-Object User, UPN, Rule, Action, @{N = 'External'; E = { $_.External -join '; ' } }, Enabled Complete-TTReport -Html $html -Path $Path -Data $flat -Csv:$Csv -Excel:$Excel -DataPath $DataPath -NoHtml:$NoHtml -NoOpen:$NoOpen -Kind 'Mail-Forwarding-Report' if ($PassThru) { $data } } |