From 244ca90a32e013ee2f45efeb176b483bd352de11 Mon Sep 17 00:00:00 2001 From: Ross Parkel Date: Mon, 10 Mar 2025 16:23:41 +0100 Subject: [PATCH 1/4] Added show detailed explanation parameter --- M365/MDO/MDOThreatPolicyChecker.ps1 | 176 ++++++++++++++++++------ docs/M365/MDO/MDOThreatPolicyChecker.md | 1 + 2 files changed, 136 insertions(+), 41 deletions(-) diff --git a/M365/MDO/MDOThreatPolicyChecker.ps1 b/M365/MDO/MDOThreatPolicyChecker.ps1 index 7bb88da96f..a6c75e0d87 100644 --- a/M365/MDO/MDOThreatPolicyChecker.ps1 +++ b/M365/MDO/MDOThreatPolicyChecker.ps1 @@ -23,6 +23,8 @@ This script checks which Microsoft Defender for Office 365 and Exchange Online P Checks only MDO (Safe Attachment and Safe Links) policies for user(s) specified in the CSV file or EmailAddress parameter. .PARAMETER ShowDetailedPolicies In addition to the policy applied, show any policy details that are set to True, On, or not blank. +.PARAMETER ShowDetailedExplanation + Show specific explanation about why a policy is matched or not. .PARAMETER SkipConnectionCheck Skips connection check for Graph and Exchange Online. .PARAMETER SkipVersionCheck @@ -109,7 +111,7 @@ begin { $stGroupEmail = $GroupEmail.ToString() # Check the cache first - Write-Verbose "Looking Group $stGroupEmail in cache" + Write-Verbose "Searching cache for Group $stGroupEmail" if ($groupCache.ContainsKey($stGroupEmail)) { Write-Verbose "Group $stGroupEmail found in cache" return $groupCache[$stGroupEmail] @@ -117,7 +119,7 @@ begin { # Get the group $group = $null - Write-Verbose "Getting $stGroupEmail" + Write-Verbose "Getting Group $stGroupEmail" try { $group = Get-MgGroup -Filter "mail eq '$stGroupEmail'" -ErrorAction Stop } catch { @@ -158,7 +160,7 @@ begin { # Check the cache first $stEmail = $Email.ToString() $cacheKey = "$stEmail|$GroupObjectId" - Write-Verbose "Looking for $stEmail|$GroupObjectId in cache" + Write-Verbose "Searching cache for value of User in Group: $stEmail | $GroupObjectId" if ($memberCache.ContainsKey($cacheKey)) { Write-Verbose "Found $stEmail|$GroupObjectId in cache" return $memberCache[$cacheKey] @@ -255,7 +257,8 @@ begin { return $tempAddress } } catch { - Write-Host "Error getting recipient $EmailAddress`:`n$_" -ForegroundColor Red + Write-Host "Error getting recipient $EmailAddress $tempAddress" -ForegroundColor Red + Write-Verbose "$_" } } else { Write-Host "The domain $domain is not an accepted domain in your organization. Please provide a valid email address: $tempAddress " -ForegroundColor Red @@ -279,7 +282,11 @@ begin { $emailInRule = $emailExceptionInRule = $groupInRule = $groupExceptionInRule = $domainInRule = $domainExceptionInRule = $false if ($Outbound) { - Write-Verbose "Checking outbound rule $($rule.Name)" + if ($ShowDetailedExplanation) { + Write-Host "`n`t`tChecking outbound spam rule: `"$($rule.Name)`"" + } else { + Write-Verbose "Checking outbound spam rule: `"$($rule.Name)`"" + } $requestedProperties = 'From', 'ExceptIfFrom', 'FromMemberOf', 'ExceptIfFromMemberOf', 'SenderDomainIs', 'ExceptIfSenderDomainIs' $senderOrReceiver = $rule.From $exceptSenderOrReceiver = $rule.ExceptIfFrom @@ -288,7 +295,11 @@ begin { $domainsIs = $rule.SenderDomainIs $exceptIfDomainsIs = $rule.ExceptIfSenderDomainIs } else { - Write-Verbose "Checking inbound rule $($rule.Name)" + if ($ShowDetailedExplanation) { + Write-Host "`n`t`tChecking rule: `"$($rule.Name)`"" + } else { + Write-Verbose "Checking rule: `"$($rule.Name)`"" + } $requestedProperties = 'SentTo', 'ExceptIfSentTo', 'SentToMemberOf', 'ExceptIfSentToMemberOf', 'RecipientDomainIs', 'ExceptIfRecipientDomainIs' $senderOrReceiver = $rule.SentTo $exceptSenderOrReceiver = $rule.ExceptIfSentTo @@ -306,24 +317,47 @@ begin { Write-Verbose " " if ($senderOrReceiver -and $Email -in $senderOrReceiver) { - Write-Verbose "emailInRule" + if ($ShowDetailedExplanation) { + Write-Host "`t`tIncluded in rule as User. Other conditions must match also." + } else { + Write-Verbose "Included in rule as User. Other conditions must match also." + } $emailInRule = $true } if ($exceptSenderOrReceiver -and $Email -in $exceptSenderOrReceiver) { - Write-Verbose "emailExceptionInRule" + if ($ShowDetailedExplanation) { + Write-Host "`t`tExcluded from rule as User." + } else { + Write-Verbose "Excluded from rule as User." + } $emailExceptionInRule = $true } if ($memberOf) { foreach ($groupEmail in $memberOf) { - Write-Verbose "Checking member in $groupEmail" + if ($ShowDetailedExplanation) { + Write-Host "`t`tChecking if recipient is in Group $groupEmail" + } else { + Write-Verbose "Checking if recipient is in Group $groupEmail" + } $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { Write-Host "The group in $($rule.Name) with email address $groupEmail does not exist." -ForegroundColor Yellow } else { $groupInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupInRule) { - Write-Verbose "groupInRule $($Email.ToString()) - $($groupObjectId)" + if ($ShowDetailedExplanation) { + Write-Host "`t`tGroup membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" + } else { + Write-Verbose "Group membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" + } + break + } else { + if ($ShowDetailedExplanation) { + Write-Host "`t`tNo Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" + } else { + Write-Verbose "No Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" + } break } } @@ -332,14 +366,29 @@ begin { if ($exceptMemberOf) { foreach ($groupEmail in $exceptMemberOf) { - Write-Verbose "Checking member in exception $groupEmail" + if ($ShowDetailedExplanation) { + Write-Host "`t`tChecking if recipient is in excluded Group $groupEmail" + } else { + Write-Verbose "Checking if recipient is in excluded Group $groupEmail" + } $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { Write-Host "The group in $($rule.Name) with email address $groupEmail does not exist." -ForegroundColor Yellow } else { $groupExceptionInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupExceptionInRule) { - Write-Verbose "groupExceptionInRule $($Email.ToString()) - $($groupObjectId)" + if ($ShowDetailedExplanation) { + Write-Host "`t`tExcluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" + } else { + Write-Verbose "Excluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" + } + break + } else { + if ($ShowDetailedExplanation) { + Write-Host "`t`t$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" + } else { + Write-Verbose "$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" + } break } } @@ -349,11 +398,19 @@ begin { $temp = $Email.Host while ($temp.IndexOf(".") -gt 0) { if ($temp -in $domainsIs) { - Write-Verbose "domainInRule: $temp" + if ($ShowDetailedExplanation) { + Write-Host "`t`tDomain is in rule: $temp. Other conditions must match also." + } else { + Write-Verbose ("Domain is in rule: {0}. Other conditions must match also." -f $temp) + } $domainInRule = $true } if ($temp -in $exceptIfDomainsIs) { - Write-Verbose "domainExceptionInRule: $temp" + if ($ShowDetailedExplanation) { + Write-Host "`t`tExcluded from rule by domain: $temp" + } else { + Write-Verbose "Excluded from rule by domain: $temp" + } $domainExceptionInRule = $true } $temp = $temp.Substring($temp.IndexOf(".") + 1) @@ -364,19 +421,39 @@ begin { if (((($emailInRule -or (-not $senderOrReceiver)) -and ($domainInRule -or (-not $domainsIs)) -and ($groupInRule -or (-not $memberOf))) -and ($emailInRule -or $domainInRule -or $groupInRule)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule))) { - Write-Verbose "Return Rule $($rule.Name)" - Write-Verbose "emailInRule: $emailInRule domainInRule: $domainInRule groupInRule: $groupInRule " - Write-Verbose "emailExceptionInRule: $emailExceptionInRule groupExceptionInRule: $groupExceptionInRule domainExceptionInRule: $domainExceptionInRule " + if ($ShowDetailedExplanation) { + Write-Host "`t`tPolicy match found: `"$($rule.Name)`"" + Write-Host ("`t`tIncluded in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) + Write-Host ("`t`tExcluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + } else { + Write-Verbose "Policy match found: `"$($rule.Name)`"" + Write-Verbose ("Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) + Write-Verbose ("Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + } return $rule + } else { + if ($ShowDetailedExplanation) { + Write-Host "`t`tThe rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. Due to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." + Write-Host ("`t`tIncluded in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) + Write-Host ("`t`tExcluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + } else { + Write-Verbose "The rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. Due to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." + Write-Verbose ("Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) + Write-Verbose ("Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + } } # Check for implicit inclusion (no mailboxes included at all), which is possible for Presets and SA/SL. They are included if not explicitly excluded. Only inbound if ((-not $Outbound) -and (((-not $senderOrReceiver) -and (-not $domainsIs) -and (-not $memberOf)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule)))) { - Write-Verbose "Return Rule $($rule.Name)" - Write-Verbose "senderOrReceiver: $senderOrReceiver domainsIs: $domainsIs memberOf: $memberOf " - Write-Verbose "emailExceptionInRule: $emailExceptionInRule groupExceptionInRule: $groupExceptionInRule domainExceptionInRule: $domainExceptionInRule " + if ($ShowDetailedExplanation) { + Write-Host "`t`tThe recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. Implicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." + Write-Host "`t`tRule of matching policy: `"$($rule.Name)`"" + } else { + Write-Verbose "The recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. Implicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." + Write-Verbose "Rule of matching policy: `"$($rule.Name)`"" + } return $rule } } @@ -449,7 +526,7 @@ begin { SetWriteVerboseAction ${Function:Write-DebugLog} SetWriteWarningAction ${Function:Write-HostLog} - $BuildVersion = "" + $BuildVersion = "25.01.23.2258" Write-Host ("MDOThreatPolicyChecker.ps1 script version $($BuildVersion)") -ForegroundColor Green @@ -586,6 +663,20 @@ process { $issues.Add("`t`t-> Illogical inclusions of Users and Domains. `n`t`t`tThe policy will only apply to Users whose email domains also match any Domains you have specified. `n`t`t`tThis makes the Domain inclusion redundant and confusing.`n`t`t`tSuggestion: use one or the other type of inclusion.`n") } + # Do the same checks for Outbound spam policies + if ($policy.From -and $policy.ExceptIfFrom) { + $issues.Add("`t`t-> User inclusions and exclusions. `n`t`t`tExcluding and including Users individually is redundant and confusing as only the included Users could possibly be included.`n") + } + if ($policy.SenderDomainIs -and $policy.ExceptIfSenderDomainIs) { + $issues.Add("`t`t-> Domain inclusions and exclusions. `n`t`t`tExcluding and including Domains is redundant and confusing as only the included Domains could possibly be included.`n") + } + if ($policy.From -and $policy.FromMemberOf) { + $issues.Add("`t`t-> Illogical inclusions of Users and Groups. `n`t`t`tThe policy will only apply to Users who are also members of any Groups you have specified. `n`t`t`tThis makes the Group inclusion redundant and confusing.`n`t`t`tSuggestion: use one or the other type of inclusion.`n") + } + if ($policy.From -and $policy.SenderDomainIs) { + $issues.Add("`t`t-> Illogical inclusions of Users and Domains. `n`t`t`tThe policy will only apply to Users whose email domains also match any Domains you have specified. `n`t`t`tThis makes the Domain inclusion redundant and confusing.`n`t`t`tSuggestion: use one or the other type of inclusion.`n") + } + # If there are any issues, print the policy details once and then list all the issues if ($issues.Count -gt 0) { if ($policy.State -eq "Enabled") { @@ -593,7 +684,7 @@ process { } else { $color = "Yellow" } - Write-Host ("Policy $($policy.Name):") + Write-Host ("Policy `"$($policy.Name)`":") Write-Host ("`tType: $($cmdlets[$cmdlet]).") Write-Host ("`tState: $($policy.State).") -ForegroundColor $color Write-Host ("`tIssues: ") -ForegroundColor Red @@ -712,11 +803,11 @@ process { if ($hostedOutboundSpamFilterRules) { $outboundSpamMatchedRule = Test-Rules -Rules $hostedOutboundSpamFilterRules -email $stEmailAddress -Outbound if ($null -eq $outboundSpamMatchedRule) { - Write-Host "`nOutbound Spam:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nOutbound Spam policy applied:`n`tDefault policy" -ForegroundColor Yellow $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy "Default" } else { - $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.Name - Write-Host "`nOutbound Spam:`n`tName: $($outboundSpamMatchedRule.Name)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow + $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy + Write-Host "`nOutbound Spam policy applied:`n`tName: $($outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow } if ($hostedOutboundSpamFilterPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $hostedOutboundSpamFilterPolicy @@ -738,11 +829,11 @@ process { if ($hostedOutboundSpamFilterRules) { $outboundSpamMatchedRule = Test-Rules -Rules $hostedOutboundSpamFilterRules -Email $stEmailAddress -Outbound if ($null -eq $outboundSpamMatchedRule) { - Write-Host "`nOutbound Spam:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nOutbound Spam policy applied:`n`tDefault policy" -ForegroundColor Yellow $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy "Default" } else { - $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.Name - Write-Host "`nOutbound Spam:`n`tName: $($outboundSpamMatchedRule.Name)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow + $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy + Write-Host "`nOutbound Spam policy applied:`n`tName: $($outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow } if ($hostedOutboundSpamFilterPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $hostedOutboundSpamFilterPolicy @@ -756,11 +847,11 @@ process { $malwareMatchedRule = Test-Rules -Rules $malwareFilterRules -Email $stEmailAddress } if ($null -eq $malwareMatchedRule) { - Write-Host "`nMalware:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nMalware policy applied:`n`tDefault policy" -ForegroundColor Yellow $malwareFilterPolicy = Get-MalwareFilterPolicy "Default" } else { - $malwareFilterPolicy = Get-MalwareFilterPolicy $malwareMatchedRule.Name - Write-Host "`nMalware:`n`tName: $($malwareMatchedRule.Name)`n`tPriority: $($malwareMatchedRule.Priority)" -ForegroundColor Yellow + $malwareFilterPolicy = Get-MalwareFilterPolicy $malwareMatchedRule.MalwareFilterPolicy + Write-Host "`nMalware policy applied:`n`tName: $($malwareMatchedRule.MalwareFilterPolicy)`n`tPriority: $($malwareMatchedRule.Priority)" -ForegroundColor Yellow } if ($malwareFilterPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $malwareFilterPolicy @@ -771,11 +862,11 @@ process { $antiPhishMatchedRule = Test-Rules -Rules $antiPhishRules -Email $stEmailAddress } if ($null -eq $antiPhishMatchedRule) { - Write-Host "`nAnti-phish:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nAnti-phish policy applied:`n`tDefault policy" -ForegroundColor Yellow $antiPhishPolicy = Get-AntiPhishPolicy "Office365 AntiPhish Default" } else { - $antiPhishPolicy = Get-AntiPhishPolicy $antiPhishMatchedRule.Name - Write-Host "`nAnti-phish:`n`tName: $($antiPhishMatchedRule.Name)`n`tPriority: $($antiPhishMatchedRule.Priority)" -ForegroundColor Yellow + $antiPhishPolicy = Get-AntiPhishPolicy $antiPhishMatchedRule.AntiPhishPolicy + Write-Host "`nAnti-phish policy applied:`n`tName: $($antiPhishMatchedRule.AntiPhishPolicy)`n`tPriority: $($antiPhishMatchedRule.Priority)" -ForegroundColor Yellow } if ($antiPhishPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $antiPhishPolicy @@ -786,11 +877,11 @@ process { $spamMatchedRule = Test-Rules -Rules $hostedContentFilterRules -Email $stEmailAddress } if ($null -eq $spamMatchedRule) { - Write-Host "`nAnti-spam:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nAnti-spam policy applied:`n`tDefault policy" -ForegroundColor Yellow $hostedContentFilterPolicy = Get-HostedContentFilterPolicy "Default" } else { - $hostedContentFilterPolicy = Get-HostedContentFilterPolicy $spamMatchedRule.Name - Write-Host "`nAnti-spam:`n`tName: $($spamMatchedRule.Name)`n`tPriority: $($spamMatchedRule.Priority)" -ForegroundColor Yellow + $hostedContentFilterPolicy = Get-HostedContentFilterPolicy $spamMatchedRule.HostedContentFilterPolicy + Write-Host "`nAnti-spam policy applied:`n`tName: $($spamMatchedRule.HostedContentFilterPolicy)`n`tPriority: $($spamMatchedRule.Priority)" -ForegroundColor Yellow } if ($hostedContentFilterPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $hostedContentFilterPolicy @@ -801,11 +892,11 @@ process { $outboundSpamMatchedRule = Test-Rules -Rules $hostedOutboundSpamFilterRules -email $stEmailAddress -Outbound } if ($null -eq $outboundSpamMatchedRule) { - Write-Host "`nOutbound Spam:`n`tDefault policy" -ForegroundColor Yellow + Write-Host "`nOutbound Spam policy applied:`n`tDefault policy" -ForegroundColor Yellow $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy "Default" } else { - $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.Name - Write-Host "`nOutbound Spam:`n`tName: $($outboundSpamMatchedRule.Name)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow + $hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy $outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy + Write-Host "`nOutbound Spam policy applied:`n`tName: $($outboundSpamMatchedRule.HostedOutboundSpamFilterPolicy)`n`tPriority: $($outboundSpamMatchedRule.Priority)" -ForegroundColor Yellow } if ($hostedOutboundSpamFilterPolicy -and $ShowDetailedPolicies) { Show-DetailedPolicy -Policy $hostedOutboundSpamFilterPolicy @@ -918,5 +1009,8 @@ process { } } } + if (-not $ShowDetailedExplanation) { + Write-Host ("`nFor details about why a policy applies to a recipient, use the -ShowDetailedExplanation parameter and run this script again.") + } Write-Host " " -} +} \ No newline at end of file diff --git a/docs/M365/MDO/MDOThreatPolicyChecker.md b/docs/M365/MDO/MDOThreatPolicyChecker.md index e39bb8d76f..3fb0e9ee0c 100644 --- a/docs/M365/MDO/MDOThreatPolicyChecker.md +++ b/docs/M365/MDO/MDOThreatPolicyChecker.md @@ -125,6 +125,7 @@ EmailAddress | Allows you to specify email address or multiple addresses separat IncludeMDOPolicies | Checks both EOP and MDO (Safe Attachment and Safe Links) policies for user(s) specified in the CSV file or EmailAddress parameter. OnlyMDOPolicies | Checks only MDO (Safe Attachment and Safe Links) policies for user(s) specified in the CSV file or EmailAddress parameter. ShowDetailedPolicies | In addition to the policy applied, show any policy details that are set to True, On, or not blank. +ShowDetailedExplanation | Show specific explanation about why a policy is matched or not. SkipConnectionCheck | Skips connection check for Graph and Exchange Online. SkipVersionCheck | Skips the version check of the script. ScriptUpdateOnly | Just updates script version to latest one. From ef0409ddff0b9ede406185fec5a459bb21227870 Mon Sep 17 00:00:00 2001 From: Ross Parkel Date: Tue, 11 Mar 2025 09:09:19 +0100 Subject: [PATCH 2/4] Small changes --- M365/MDO/MDOThreatPolicyChecker.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/M365/MDO/MDOThreatPolicyChecker.ps1 b/M365/MDO/MDOThreatPolicyChecker.ps1 index a6c75e0d87..a9f03a8264 100644 --- a/M365/MDO/MDOThreatPolicyChecker.ps1 +++ b/M365/MDO/MDOThreatPolicyChecker.ps1 @@ -526,7 +526,7 @@ begin { SetWriteVerboseAction ${Function:Write-DebugLog} SetWriteWarningAction ${Function:Write-HostLog} - $BuildVersion = "25.01.23.2258" + $BuildVersion = "" Write-Host ("MDOThreatPolicyChecker.ps1 script version $($BuildVersion)") -ForegroundColor Green @@ -1013,4 +1013,4 @@ process { Write-Host ("`nFor details about why a policy applies to a recipient, use the -ShowDetailedExplanation parameter and run this script again.") } Write-Host " " -} \ No newline at end of file +} From c2e88c497a43c60d1bbe5fd5a29b6e5708009243 Mon Sep 17 00:00:00 2001 From: Ross Parkel Date: Tue, 11 Mar 2025 10:47:57 +0100 Subject: [PATCH 3/4] Message format improvements --- M365/MDO/MDOThreatPolicyChecker.ps1 | 108 +++++++++++++++++----------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/M365/MDO/MDOThreatPolicyChecker.ps1 b/M365/MDO/MDOThreatPolicyChecker.ps1 index a9f03a8264..aabf83c2b6 100644 --- a/M365/MDO/MDOThreatPolicyChecker.ps1 +++ b/M365/MDO/MDOThreatPolicyChecker.ps1 @@ -78,6 +78,12 @@ param( [Parameter(Mandatory = $false, ParameterSetName = 'AppliedMDOEmail')] [switch]$ShowDetailedPolicies, + [Parameter(Mandatory = $false, ParameterSetName = 'AppliedCsv')] + [Parameter(Mandatory = $false, ParameterSetName = 'AppliedEmail')] + [Parameter(Mandatory = $false, ParameterSetName = 'AppliedMDOCsv')] + [Parameter(Mandatory = $false, ParameterSetName = 'AppliedMDOEmail')] + [switch]$ShowDetailedExplanation, + [Parameter(Mandatory = $false)] [switch]$SkipConnectionCheck, @@ -282,10 +288,11 @@ begin { $emailInRule = $emailExceptionInRule = $groupInRule = $groupExceptionInRule = $domainInRule = $domainExceptionInRule = $false if ($Outbound) { + $message = "Checking outbound spam rule: `"$($rule.Name)`"" if ($ShowDetailedExplanation) { - Write-Host "`n`t`tChecking outbound spam rule: `"$($rule.Name)`"" + Write-Host "`t`t$message" } else { - Write-Verbose "Checking outbound spam rule: `"$($rule.Name)`"" + Write-Verbose $message } $requestedProperties = 'From', 'ExceptIfFrom', 'FromMemberOf', 'ExceptIfFromMemberOf', 'SenderDomainIs', 'ExceptIfSenderDomainIs' $senderOrReceiver = $rule.From @@ -295,10 +302,11 @@ begin { $domainsIs = $rule.SenderDomainIs $exceptIfDomainsIs = $rule.ExceptIfSenderDomainIs } else { + $message = "Checking rule: `"$($rule.Name)`"" if ($ShowDetailedExplanation) { - Write-Host "`n`t`tChecking rule: `"$($rule.Name)`"" + Write-Host "`n`t`t$message" } else { - Write-Verbose "Checking rule: `"$($rule.Name)`"" + Write-Verbose $message } $requestedProperties = 'SentTo', 'ExceptIfSentTo', 'SentToMemberOf', 'ExceptIfSentToMemberOf', 'RecipientDomainIs', 'ExceptIfRecipientDomainIs' $senderOrReceiver = $rule.SentTo @@ -317,28 +325,31 @@ begin { Write-Verbose " " if ($senderOrReceiver -and $Email -in $senderOrReceiver) { + $message = "Included in rule as User. Other conditions must match also." if ($ShowDetailedExplanation) { - Write-Host "`t`tIncluded in rule as User. Other conditions must match also." + Write-Host "`t`t$message" } else { - Write-Verbose "Included in rule as User. Other conditions must match also." + Write-Verbose $message } $emailInRule = $true } if ($exceptSenderOrReceiver -and $Email -in $exceptSenderOrReceiver) { + $message = "Excluded from rule as User." if ($ShowDetailedExplanation) { - Write-Host "`t`tExcluded from rule as User." + Write-Host "`t`t$message" } else { - Write-Verbose "Excluded from rule as User." + Write-Verbose $message } $emailExceptionInRule = $true } if ($memberOf) { foreach ($groupEmail in $memberOf) { + $message = "Checking if recipient is in Group $groupEmail" if ($ShowDetailedExplanation) { - Write-Host "`t`tChecking if recipient is in Group $groupEmail" + Write-Host "`t`t$message" } else { - Write-Verbose "Checking if recipient is in Group $groupEmail" + Write-Verbose $message } $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { @@ -346,17 +357,19 @@ begin { } else { $groupInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupInRule) { + $message = "Group membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" if ($ShowDetailedExplanation) { - Write-Host "`t`tGroup membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" + Write-Host "`t`t$message" } else { - Write-Verbose "Group membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" + Write-Verbose $message } break } else { + $message = "No Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" if ($ShowDetailedExplanation) { - Write-Host "`t`tNo Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" + Write-Host "`t`t$message" } else { - Write-Verbose "No Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" + Write-Verbose $message } break } @@ -366,10 +379,11 @@ begin { if ($exceptMemberOf) { foreach ($groupEmail in $exceptMemberOf) { + $message = "Checking if recipient is in excluded Group $groupEmail" if ($ShowDetailedExplanation) { - Write-Host "`t`tChecking if recipient is in excluded Group $groupEmail" + Write-Host "`t`t$message" } else { - Write-Verbose "Checking if recipient is in excluded Group $groupEmail" + Write-Verbose $message } $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { @@ -377,17 +391,19 @@ begin { } else { $groupExceptionInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupExceptionInRule) { + $message = "Excluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" if ($ShowDetailedExplanation) { - Write-Host "`t`tExcluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" + Write-Host "`t`t$message" } else { - Write-Verbose "Excluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" + Write-Verbose $message } break } else { + $message = "$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" if ($ShowDetailedExplanation) { - Write-Host "`t`t$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" + Write-Host "`t`t$message" } else { - Write-Verbose "$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" + Write-Verbose $message } break } @@ -398,18 +414,20 @@ begin { $temp = $Email.Host while ($temp.IndexOf(".") -gt 0) { if ($temp -in $domainsIs) { + $message = "Domain is in rule: $temp. Other conditions must match also." if ($ShowDetailedExplanation) { - Write-Host "`t`tDomain is in rule: $temp. Other conditions must match also." + Write-Host "`t`t$message" } else { - Write-Verbose ("Domain is in rule: {0}. Other conditions must match also." -f $temp) + Write-Verbose $message } $domainInRule = $true } if ($temp -in $exceptIfDomainsIs) { + $message = "Excluded from rule by domain: $temp" if ($ShowDetailedExplanation) { - Write-Host "`t`tExcluded from rule by domain: $temp" + Write-Host "`t`t$message" } else { - Write-Verbose "Excluded from rule by domain: $temp" + Write-Verbose $message } $domainExceptionInRule = $true } @@ -421,25 +439,31 @@ begin { if (((($emailInRule -or (-not $senderOrReceiver)) -and ($domainInRule -or (-not $domainsIs)) -and ($groupInRule -or (-not $memberOf))) -and ($emailInRule -or $domainInRule -or $groupInRule)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule))) { + $message = "Policy match found: `"$($rule.Name)`"" + $messageDetail = "Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." + $messageDetail2 = "Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." if ($ShowDetailedExplanation) { - Write-Host "`t`tPolicy match found: `"$($rule.Name)`"" - Write-Host ("`t`tIncluded in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) - Write-Host ("`t`tExcluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + Write-Host "`t`t$message" + Write-Host ("`t`t$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) + Write-Host ("`t`t$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) } else { - Write-Verbose "Policy match found: `"$($rule.Name)`"" - Write-Verbose ("Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) - Write-Verbose ("Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + Write-Verbose $message + Write-Verbose ("$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) + Write-Verbose ("$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) } return $rule } else { + $message = "The rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. `n`t`tDue to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." + $messageDetail = "Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." + $messageDetail2 = "Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." if ($ShowDetailedExplanation) { - Write-Host "`t`tThe rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. Due to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." - Write-Host ("`t`tIncluded in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) - Write-Host ("`t`tExcluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + Write-Host "`t`t$message" + Write-Host ("`t`t$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) + Write-Host ("`t`t$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) } else { - Write-Verbose "The rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. Due to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." - Write-Verbose ("Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." -f $emailInRule, $groupInRule, $domainInRule) - Write-Verbose ("Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) + Write-Verbose $message + Write-Verbose ("$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) + Write-Verbose ("$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) } } @@ -447,12 +471,14 @@ begin { if ((-not $Outbound) -and (((-not $senderOrReceiver) -and (-not $domainsIs) -and (-not $memberOf)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule)))) { + $message = "The recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. `n`t`tImplicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." + $messageDetail = "Rule of matching policy: `"$($rule.Name)`"" if ($ShowDetailedExplanation) { - Write-Host "`t`tThe recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. Implicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." - Write-Host "`t`tRule of matching policy: `"$($rule.Name)`"" + Write-Host "`t`t$message" + Write-Host "`t`t$messageDetail" } else { - Write-Verbose "The recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. Implicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." - Write-Verbose "Rule of matching policy: `"$($rule.Name)`"" + Write-Verbose $message + Write-Verbose $messageDetail } return $rule } @@ -785,7 +811,7 @@ process { $stEmailAddress = $email.ToString() # Initialize a variable to capture all policy details $allPolicyDetails = "" - Write-Host "`n`nPolicies applied to $stEmailAddress..." + Write-Host "`n`nPolicies applied to $stEmailAddress..." -ForegroundColor Yellow if ( -not $OnlyMDOPolicies) { # Check the Strict EOP rules first as they have higher precedence From 8e57cf62cb0a8eb2b7ae021eaa99ad15f3bd0677 Mon Sep 17 00:00:00 2001 From: Ross Parkel Date: Wed, 12 Mar 2025 17:29:54 +0100 Subject: [PATCH 4/4] Created function for detailed explanation --- M365/MDO/MDOThreatPolicyChecker.ps1 | 142 +++++++--------------------- 1 file changed, 36 insertions(+), 106 deletions(-) diff --git a/M365/MDO/MDOThreatPolicyChecker.ps1 b/M365/MDO/MDOThreatPolicyChecker.ps1 index aabf83c2b6..21446421b2 100644 --- a/M365/MDO/MDOThreatPolicyChecker.ps1 +++ b/M365/MDO/MDOThreatPolicyChecker.ps1 @@ -107,6 +107,21 @@ begin { # Cache of members to reduce number of calls to Get-MgGroupMember $memberCache = @{} + function Write-DetailedExplanationOption { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Message, + [Parameter(Mandatory = $true)] + [switch]$ShowDetailedExplanation + ) + if ($ShowDetailedExplanation) { + Write-Host "`t`t$message" + } else { + Write-Verbose $message + } + } + function Get-GroupObjectId { [OutputType([string])] param( @@ -286,14 +301,9 @@ begin { foreach ($rule in $Rules) { $senderOrReceiver = $exceptSenderOrReceiver = $memberOf = $exceptMemberOf = $domainsIs = $exceptIfDomainsIs = $null $emailInRule = $emailExceptionInRule = $groupInRule = $groupExceptionInRule = $domainInRule = $domainExceptionInRule = $false - + Write-Host " " if ($Outbound) { - $message = "Checking outbound spam rule: `"$($rule.Name)`"" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Checking outbound spam rule: `"$($rule.Name)`"" -ShowDetailedExplanation:$ShowDetailedExplanation $requestedProperties = 'From', 'ExceptIfFrom', 'FromMemberOf', 'ExceptIfFromMemberOf', 'SenderDomainIs', 'ExceptIfSenderDomainIs' $senderOrReceiver = $rule.From $exceptSenderOrReceiver = $rule.ExceptIfFrom @@ -302,12 +312,7 @@ begin { $domainsIs = $rule.SenderDomainIs $exceptIfDomainsIs = $rule.ExceptIfSenderDomainIs } else { - $message = "Checking rule: `"$($rule.Name)`"" - if ($ShowDetailedExplanation) { - Write-Host "`n`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Checking rule: `"$($rule.Name)`"" -ShowDetailedExplanation:$ShowDetailedExplanation $requestedProperties = 'SentTo', 'ExceptIfSentTo', 'SentToMemberOf', 'ExceptIfSentToMemberOf', 'RecipientDomainIs', 'ExceptIfRecipientDomainIs' $senderOrReceiver = $rule.SentTo $exceptSenderOrReceiver = $rule.ExceptIfSentTo @@ -325,52 +330,27 @@ begin { Write-Verbose " " if ($senderOrReceiver -and $Email -in $senderOrReceiver) { - $message = "Included in rule as User. Other conditions must match also." - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Included in rule as User. Other conditions must match also." -ShowDetailedExplanation:$ShowDetailedExplanation $emailInRule = $true } if ($exceptSenderOrReceiver -and $Email -in $exceptSenderOrReceiver) { - $message = "Excluded from rule as User." - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Excluded from rule as User." -ShowDetailedExplanation:$ShowDetailedExplanation $emailExceptionInRule = $true } if ($memberOf) { foreach ($groupEmail in $memberOf) { - $message = "Checking if recipient is in Group $groupEmail" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Checking if recipient is in Group $groupEmail" -ShowDetailedExplanation:$ShowDetailedExplanation $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { Write-Host "The group in $($rule.Name) with email address $groupEmail does not exist." -ForegroundColor Yellow } else { $groupInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupInRule) { - $message = "Group membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Group membership match: $($Email.ToString()) is a member of Group $($groupObjectId)" -ShowDetailedExplanation:$ShowDetailedExplanation break } else { - $message = "No Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "No Group match because $($Email.ToString()) is not a member of Group $($groupObjectId)" -ShowDetailedExplanation:$ShowDetailedExplanation break } } @@ -379,32 +359,17 @@ begin { if ($exceptMemberOf) { foreach ($groupEmail in $exceptMemberOf) { - $message = "Checking if recipient is in excluded Group $groupEmail" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Checking if recipient is in excluded Group $groupEmail" -ShowDetailedExplanation:$ShowDetailedExplanation $groupObjectId = Get-GroupObjectId -GroupEmail $groupEmail if ([string]::IsNullOrEmpty($groupObjectId)) { Write-Host "The group in $($rule.Name) with email address $groupEmail does not exist." -ForegroundColor Yellow } else { $groupExceptionInRule = Test-IsInGroup -Email $Email -GroupObjectId $groupObjectId if ($groupExceptionInRule) { - $message = "Excluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Excluded from rule by group membership. $($Email.ToString()) is in excluded Group $($groupObjectId)" -ShowDetailedExplanation:$ShowDetailedExplanation break } else { - $message = "$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "$($Email.ToString()) is not excluded from rule by membership in Group $($groupObjectId)" -ShowDetailedExplanation:$ShowDetailedExplanation break } } @@ -414,21 +379,11 @@ begin { $temp = $Email.Host while ($temp.IndexOf(".") -gt 0) { if ($temp -in $domainsIs) { - $message = "Domain is in rule: $temp. Other conditions must match also." - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Domain is in rule: $temp. Other conditions must match also." -ShowDetailedExplanation:$ShowDetailedExplanation $domainInRule = $true } if ($temp -in $exceptIfDomainsIs) { - $message = "Excluded from rule by domain: $temp" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - } else { - Write-Verbose $message - } + Write-DetailedExplanationOption -Message "Excluded from rule by domain: $temp" -ShowDetailedExplanation:$ShowDetailedExplanation $domainExceptionInRule = $true } $temp = $temp.Substring($temp.IndexOf(".") + 1) @@ -439,47 +394,22 @@ begin { if (((($emailInRule -or (-not $senderOrReceiver)) -and ($domainInRule -or (-not $domainsIs)) -and ($groupInRule -or (-not $memberOf))) -and ($emailInRule -or $domainInRule -or $groupInRule)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule))) { - $message = "Policy match found: `"$($rule.Name)`"" - $messageDetail = "Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." - $messageDetail2 = "Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - Write-Host ("`t`t$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) - Write-Host ("`t`t$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) - } else { - Write-Verbose $message - Write-Verbose ("$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) - Write-Verbose ("$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) - } + Write-DetailedExplanationOption -Message "Policy match found: `"$($rule.Name)`"" -ShowDetailedExplanation:$ShowDetailedExplanation + Write-DetailedExplanationOption -Message "Included in rule as User: $emailInRule. Included in rule by Group membership: $groupInRule. Included in rule by Domain: $domainInRule." -ShowDetailedExplanation:$ShowDetailedExplanation + Write-DetailedExplanationOption -Message "Excluded from rule as User: $emailExceptionInRule. Excluded from rule by group membership: $groupExceptionInRule. Excluded from rule by domain: $domainExceptionInRule." -ShowDetailedExplanation:$ShowDetailedExplanation return $rule } else { - $message = "The rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. `n`t`tDue to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." - $messageDetail = "Included in rule as User: {0}. Included in rule by Group membership: {1}. Included in rule by Domain: {2}." - $messageDetail2 = "Excluded from rule as User: {0}. Excluded from rule by group membership: {1}. Excluded from rule by domain: {2}." - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - Write-Host ("`t`t$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) - Write-Host ("`t`t$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) - } else { - Write-Verbose $message - Write-Verbose ("$messageDetail" -f $emailInRule, $groupInRule, $domainInRule) - Write-Verbose ("$messageDetail2" -f $emailExceptionInRule, $groupExceptionInRule, $domainExceptionInRule) - } + Write-DetailedExplanationOption -Message "The rule/policy does not explicitly include the recipient because not all User, Group, and Domain properties which have values include the recipient. `n`t`tDue to the AND operator between the User, Group, and Domain inclusion properties, if any of those properties have non-null values (they are not empty), the recipient must be included in that property." -ShowDetailedExplanation:$ShowDetailedExplanation + Write-DetailedExplanationOption -Message "Included in rule as User: $emailInRule. Included in rule by Group membership: $groupInRule. Included in rule by Domain: $domainInRule." -ShowDetailedExplanation:$ShowDetailedExplanation + Write-DetailedExplanationOption -Message "Excluded from rule as User: $emailExceptionInRule. Excluded from rule by group membership: $groupExceptionInRule. Excluded from rule by domain: $domainExceptionInRule." -ShowDetailedExplanation:$ShowDetailedExplanation } # Check for implicit inclusion (no mailboxes included at all), which is possible for Presets and SA/SL. They are included if not explicitly excluded. Only inbound if ((-not $Outbound) -and (((-not $senderOrReceiver) -and (-not $domainsIs) -and (-not $memberOf)) -and ((-not $emailExceptionInRule) -and (-not $groupExceptionInRule) -and (-not $domainExceptionInRule)))) { - $message = "The recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. `n`t`tImplicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." - $messageDetail = "Rule of matching policy: `"$($rule.Name)`"" - if ($ShowDetailedExplanation) { - Write-Host "`t`t$message" - Write-Host "`t`t$messageDetail" - } else { - Write-Verbose $message - Write-Verbose $messageDetail - } + Write-DetailedExplanationOption -Message "The recipient is IMPLICITLY included. There are no recipients explicitly included in the policy, and the user is not explicitly excluded either in the User, Group, or Domain exclusion properties. `n`t`tImplicit inclusion is possible for Preset policies and Safe Attachments and Safe Links in which no explicit inclusions have been made." -ShowDetailedExplanation:$ShowDetailedExplanation + Write-DetailedExplanationOption -Message "Rule of matching policy: `"$($rule.Name)`"" -ShowDetailedExplanation:$ShowDetailedExplanation return $rule } }