Private/Resolve-METAntiPhishEffectivePolicy.ps1
|
function Resolve-METAntiPhishEffectivePolicy { [CmdletBinding()] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [string[]] $AllMailboxes, [Parameter(Mandatory)] [hashtable] $GroupCache, [AllowEmptyCollection()] [object[]] $Rules, [AllowEmptyCollection()] [object[]] $Policies, [AllowEmptyCollection()] [object[]] $PresetRules, [System.Collections.Generic.List[string]] $RetrievalErrors ) function Get-AntiPhishScopeDescription { param([object] $Rule) if (-not $Rule) { return 'Default catch-all' } $parts = [System.Collections.Generic.List[string]]::new() if ($Rule.SentTo) { $parts.Add("Recipients: $(@($Rule.SentTo).Count)") } if ($Rule.SentToMemberOf) { $parts.Add("Groups: $(@($Rule.SentToMemberOf).Count)") } if ($Rule.RecipientDomainIs) { $parts.Add("Domains: $(@($Rule.RecipientDomainIs) -join ', ')") } if ($parts.Count -eq 0) { $parts.Add('Catch-all (no inclusion conditions)') } $exceptions = @($Rule.ExceptIfSentTo | Where-Object { $_ }).Count + @($Rule.ExceptIfSentToMemberOf | Where-Object { $_ }).Count + @($Rule.ExceptIfRecipientDomainIs | Where-Object { $_ }).Count if ($exceptions -gt 0) { $parts.Add("Exceptions: $exceptions") } return ($parts -join '; ') } if (-not $PSBoundParameters.ContainsKey('Rules')) { try { $Rules = @(Get-AntiPhishRule -ErrorAction Stop) } catch { $Rules = @() if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve anti-phishing rules. $($_.ToString())") } } } if (-not $PSBoundParameters.ContainsKey('Policies')) { try { $Policies = @(Get-AntiPhishPolicy -ErrorAction Stop) } catch { $Policies = @() if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve anti-phishing policies. $($_.ToString())") } } } if (-not $PSBoundParameters.ContainsKey('PresetRules')) { try { $PresetRules = @(Get-ATPProtectionPolicyRule -ErrorAction Stop) } catch { $PresetRules = @() if ($null -ne $RetrievalErrors) { $RetrievalErrors.Add("Unable to retrieve MDO preset policy rules. $($_.ToString())") } } } $assignments = @{} $policyDetails = [System.Collections.Generic.List[object]]::new() $evaluationRules = @($PresetRules | Where-Object { $_.State -eq 'Enabled' -and $_.Name -match 'Evaluation' }) if ($evaluationRules.Count -gt 0 -and $null -ne $RetrievalErrors) { $RetrievalErrors.Add('An enabled Defender for Office 365 evaluation policy was detected. Its anti-phishing precedence is not yet modeled.') } foreach ($tier in @('Strict', 'Standard')) { $stableName = "$tier Preset Security Policy" $rule = $PresetRules | Where-Object { $_.Name -eq $stableName -and $_.State -eq 'Enabled' } | Select-Object -First 1 $policy = $Policies | Where-Object { $_.Name -eq $stableName } | Select-Object -First 1 if (-not $policy) { $policy = $Policies | Where-Object { $_.Name -like "$stableName*" } | Select-Object -First 1 } $covered = if ($rule) { @(Expand-METRuleRecipients -Rule $rule -AllMailboxes $AllMailboxes -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) } else { @() } foreach ($recipient in $covered) { if (-not $assignments.ContainsKey($recipient)) { $assignments[$recipient] = [PSCustomObject]@{ Recipient = $recipient; PolicyName = if ($policy) { $policy.Name } else { $stableName } PolicyType = 'Preset'; Tier = $tier; Priority = $null ScopeDescription = Get-AntiPhishScopeDescription $rule; Policy = $policy; Rule = $rule } } } if ($rule -or $policy) { $policyDetails.Add([PSCustomObject]@{ PolicyName = if ($policy) { $policy.Name } else { $stableName } PolicyType = 'Preset'; Tier = $tier; Priority = $null ScopeDescription = Get-AntiPhishScopeDescription $rule EffectiveRecipients = @($covered | Where-Object { $assignments[$_].Tier -eq $tier }).Count State = if ($rule) { 'Enabled' } else { 'Inactive' }; Policy = $policy; Rule = $rule }) } if ($rule -and -not $policy -and $null -ne $RetrievalErrors) { $RetrievalErrors.Add("Enabled $tier preset rule was returned, but its anti-phishing policy object was not returned.") } } $presetPolicyNames = @($policyDetails | Where-Object PolicyType -eq 'Preset' | ForEach-Object PolicyName) $customRules = @($Rules | Where-Object { $_.State -eq 'Enabled' -and $_.Name -notmatch '^(Strict|Standard) Preset Security Policy' } | Sort-Object Priority) foreach ($rule in $customRules) { $policyName = if ($rule.AntiPhishPolicy) { [string]$rule.AntiPhishPolicy } else { [string]$rule.Name } $policy = $Policies | Where-Object { $_.Name -eq $policyName } | Select-Object -First 1 if (-not $policy -and $null -ne $RetrievalErrors) { $RetrievalErrors.Add("Enabled anti-phishing rule '$($rule.Name)' references policy '$policyName', but that policy was not returned.") } $matched = @(Expand-METRuleRecipients -Rule $rule -AllMailboxes $AllMailboxes -GroupCache $GroupCache -RetrievalErrors $RetrievalErrors) $covered = @($matched | Where-Object { -not $assignments.ContainsKey($_) }) $shadowed = @($matched | Where-Object { $assignments.ContainsKey($_) }) $shadowedBy = @($shadowed | ForEach-Object { $prior = $assignments[$_] if ($prior.PolicyType -eq 'Preset') { "Preset: '$($prior.PolicyName)'" } elseif (-not $prior.Rule.SentTo -and -not $prior.Rule.SentToMemberOf -and -not $prior.Rule.RecipientDomainIs) { "CustomCatchAll: '$($prior.PolicyName)'" } else { "Custom: '$($prior.PolicyName)'" } } | Sort-Object -Unique) foreach ($recipient in $covered) { $assignments[$recipient] = [PSCustomObject]@{ Recipient = $recipient; PolicyName = $policyName; PolicyType = 'Custom'; Tier = 'Custom' Priority = $rule.Priority; ScopeDescription = Get-AntiPhishScopeDescription $rule Policy = $policy; Rule = $rule } } $policyDetails.Add([PSCustomObject]@{ PolicyName = $policyName; PolicyType = 'Custom'; Tier = 'Custom'; Priority = $rule.Priority ScopeDescription = Get-AntiPhishScopeDescription $rule; MatchedRecipients = @($matched).Count EffectiveRecipients = @($covered).Count; ShadowedRecipients = @($shadowed).Count; ShadowedBy = $shadowedBy State = 'Enabled'; Policy = $policy; Rule = $rule }) } foreach ($rule in @($Rules | Where-Object { $_.State -ne 'Enabled' })) { $policyName = if ($rule.AntiPhishPolicy) { [string]$rule.AntiPhishPolicy } else { [string]$rule.Name } $policy = $Policies | Where-Object Name -eq $policyName | Select-Object -First 1 $policyDetails.Add([PSCustomObject]@{ PolicyName = $policyName; PolicyType = 'Custom'; Tier = 'Custom'; Priority = $rule.Priority ScopeDescription = Get-AntiPhishScopeDescription $rule; EffectiveRecipients = 0 State = if ($rule.State) { [string]$rule.State } else { 'Disabled' }; Policy = $policy; Rule = $rule }) } $defaultPolicy = $Policies | Where-Object { $_.IsDefault -eq $true -or $_.Name -eq 'Office365 AntiPhish Default' } | Select-Object -First 1 $defaultCount = 0 foreach ($recipient in $AllMailboxes) { if (-not $assignments.ContainsKey($recipient)) { $assignments[$recipient] = [PSCustomObject]@{ Recipient = $recipient; PolicyName = if ($defaultPolicy) { $defaultPolicy.Name } else { 'Office365 AntiPhish Default' } PolicyType = 'Default'; Tier = 'Default'; Priority = $null; ScopeDescription = 'Default catch-all' Policy = $defaultPolicy; Rule = $null } $defaultCount++ } } if ($defaultPolicy -or $defaultCount -gt 0) { $policyDetails.Add([PSCustomObject]@{ PolicyName = if ($defaultPolicy) { $defaultPolicy.Name } else { 'Office365 AntiPhish Default' } PolicyType = 'Default'; Tier = 'Default'; Priority = $null; ScopeDescription = 'Default catch-all' EffectiveRecipients = $defaultCount; State = 'Enabled'; Policy = $defaultPolicy; Rule = $null }) } if ($defaultCount -gt 0 -and -not $defaultPolicy -and $null -ne $RetrievalErrors) { $RetrievalErrors.Add('Recipients fall through to the default anti-phishing policy, but that policy object was not returned.') } $associated = @($Rules | ForEach-Object { if ($_.AntiPhishPolicy) { [string]$_.AntiPhishPolicy } else { [string]$_.Name } }) foreach ($policy in @($Policies | Where-Object { $_.IsDefault -ne $true -and $_.Name -notin $presetPolicyNames -and $associated -notcontains $_.Name })) { $policyDetails.Add([PSCustomObject]@{ PolicyName = [string]$policy.Name; PolicyType = 'Unassociated'; Tier = 'Custom'; Priority = $null ScopeDescription = 'No associated rule'; EffectiveRecipients = 0; State = 'Inactive' Policy = $policy; Rule = $null }) } [PSCustomObject]@{ RecipientAssignments = @($AllMailboxes | ForEach-Object { $assignments[$_] }) PolicySummaries = @($policyDetails) } } |