Private/Resolve-METCoverageMatrix.ps1
|
function Resolve-METCoverageMatrix { # Resolves the effective MDO/EOP protection tier and winning policy name for every # address in AllMailboxes. Returns a case-insensitive hashtable keyed by # PrimarySmtpAddress where each value is: # [PSCustomObject]@{ EopTier; EopPolicy; AtpTier; AtpPolicy } # # EopTier values (ascending protection): Default < Custom < Standard < Strict # AtpTier values (ascending protection): BuiltIn < Custom < Standard < Strict # # EOP covers anti-spam and anti-malware; ATP covers Safe Links, Safe Attachments, # and Anti-Phish. The two preset rule sets are resolved independently because # their recipient conditions can diverge. [CmdletBinding()] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [string[]] $AllMailboxes, [Parameter(Mandatory)] [hashtable] $GroupCache, [System.Collections.Generic.List[string]] $RetrievalErrors ) $eopRank = @{ Default = 0; Custom = 1; Standard = 2; Strict = 3 } $atpRank = @{ BuiltIn = 0; Custom = 1; Standard = 2; Strict = 3 } $eopTier = @{} $eopPolicy = @{} $atpTier = @{} $atpPolicy = @{} foreach ($mbx in $AllMailboxes) { $eopTier[$mbx] = 'Default' $eopPolicy[$mbx] = 'Default Anti-Spam Policy' $atpTier[$mbx] = 'BuiltIn' $atpPolicy[$mbx] = 'Built-In Protection Policy' } try { $eopPresetRules = @(Get-EOPProtectionPolicyRule -ErrorAction Stop) } catch { $eopPresetRules = @() if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve EOP preset policy rules. $($_.ToString())") } } try { $atpPresetRules = @(Get-ATPProtectionPolicyRule -ErrorAction Stop) } catch { $atpPresetRules = @() if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve MDO preset policy rules. $($_.ToString())") } } # ── EOP presets (Strict first so it wins over Standard on overlap) ──────── foreach ($tier in @('Strict', 'Standard')) { $meta = Resolve-METPresetPolicy -Tier $tier -Stack EOP -Rules $eopPresetRules if (-not $meta.Enabled -or -not $meta.Rule) { continue } try { $covered = @(Expand-METRuleRecipients -Rule $meta.Rule -AllMailboxes $AllMailboxes -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) foreach ($addr in $covered) { if ($eopTier.ContainsKey($addr) -and $eopRank[$tier] -gt $eopRank[$eopTier[$addr]]) { $eopTier[$addr] = $tier $eopPolicy[$addr] = $meta.PolicyName } } } catch { Write-Verbose "EOP preset '$tier' recipient expansion failed: $_" if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to expand EOP preset '$tier' recipients. $($_.ToString())") } } } # ── ATP presets (resolved independently - conditions may differ from EOP) ─ foreach ($tier in @('Strict', 'Standard')) { $meta = Resolve-METPresetPolicy -Tier $tier -Stack ATP -Rules $atpPresetRules if (-not $meta.Enabled -or -not $meta.Rule) { continue } try { $covered = @(Expand-METRuleRecipients -Rule $meta.Rule -AllMailboxes $AllMailboxes -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) foreach ($addr in $covered) { if ($atpTier.ContainsKey($addr) -and $atpRank[$tier] -gt $atpRank[$atpTier[$addr]]) { $atpTier[$addr] = $tier $atpPolicy[$addr] = $meta.PolicyName } } } catch { Write-Verbose "ATP preset '$tier' recipient expansion failed: $_" if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to expand MDO preset '$tier' recipients. $($_.ToString())") } } } # ── Custom EOP policies - only evaluate addresses still at Default ──────── $eopNeedsCustom = @($AllMailboxes | Where-Object { $eopTier[$_] -eq 'Default' }) if ($eopNeedsCustom.Count -gt 0) { try { $rules = @( Get-HostedContentFilterRule -ErrorAction Stop | Where-Object { $_.State -eq 'Enabled' -and $_.Name -ne 'Default' } | Sort-Object Priority ) foreach ($rule in $rules) { $covered = @(Expand-METRuleRecipients -Rule $rule -AllMailboxes $eopNeedsCustom -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) foreach ($addr in $covered) { if ($eopTier.ContainsKey($addr) -and $eopTier[$addr] -eq 'Default') { $eopTier[$addr] = 'Custom' $eopPolicy[$addr] = $rule.Name } } } } catch { Write-Verbose "Custom EOP (anti-spam) rule expansion failed: $_" if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve or expand custom EOP anti-spam rules. $($_.ToString())") } } } # ── Custom ATP policies - Safe Links as primary signal ─────────────────── $atpNeedsCustom = @($AllMailboxes | Where-Object { $atpTier[$_] -eq 'BuiltIn' }) if ($atpNeedsCustom.Count -gt 0) { try { $rules = @( Get-SafeLinksRule -ErrorAction Stop | Where-Object { $_.State -eq 'Enabled' } | Sort-Object Priority ) foreach ($rule in $rules) { $covered = @(Expand-METRuleRecipients -Rule $rule -AllMailboxes $atpNeedsCustom -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) foreach ($addr in $covered) { if ($atpTier.ContainsKey($addr) -and $atpTier[$addr] -eq 'BuiltIn') { $atpTier[$addr] = 'Custom' $atpPolicy[$addr] = if ($rule.SafeLinksPolicy) { $rule.SafeLinksPolicy } else { $rule.Name } } } } } catch { Write-Verbose "Custom Safe Links rule expansion failed: $_" if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve or expand custom Safe Links rules. $($_.ToString())") } } } # ── Anti-Phish as fallback ATP signal for addresses still at BuiltIn ───── $atpNeedsCustom = @($AllMailboxes | Where-Object { $atpTier[$_] -eq 'BuiltIn' }) if ($atpNeedsCustom.Count -gt 0) { try { $rules = @( Get-AntiPhishRule -ErrorAction Stop | Where-Object { $_.State -eq 'Enabled' -and $_.Name -ne 'Office365 AntiPhish Default' } | Sort-Object Priority ) foreach ($rule in $rules) { $covered = @(Expand-METRuleRecipients -Rule $rule -AllMailboxes $atpNeedsCustom -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) foreach ($addr in $covered) { if ($atpTier.ContainsKey($addr) -and $atpTier[$addr] -eq 'BuiltIn') { $atpTier[$addr] = 'Custom' $atpPolicy[$addr] = $rule.Name } } } } catch { Write-Verbose "Custom Anti-Phish rule expansion failed: $_" if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve or expand custom Anti-Phish rules. $($_.ToString())") } } } # ── Combine into a single result hashtable ──────────────────────────────── $matrix = @{} foreach ($mbx in $AllMailboxes) { $matrix[$mbx] = [PSCustomObject]@{ EopTier = $eopTier[$mbx] EopPolicy = $eopPolicy[$mbx] AtpTier = $atpTier[$mbx] AtpPolicy = $atpPolicy[$mbx] } } return $matrix } |