tests/Test-Assessment.41039.ps1
|
<#
.SYNOPSIS Zero-hour auto purge (ZAP) is enabled for malware, phishing, and spam in email #> function Test-Assessment-41039 { [ZtTest( Category = 'Email and collaboration security', CompatibleLicense = ('EXCHANGE_S_STANDARD'), ImplementationCost = 'Low', Pillar = 'SecOps', RiskLevel = 'High', Service = ('ExchangeOnline'), SfiPillar = 'Accelerate response and remediation', TenantType = ('Workforce'), TestId = 41039, Title = 'Zero-hour auto purge (ZAP) is enabled for malware, phishing, and spam in email', UserImpact = 'Low' )] [CmdletBinding()] param() #region Data Collection Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose $activity = 'Checking zero-hour auto purge configuration' $malwarePolicies = @() $malwareRules = @() $malwarePolicyQueryFailed = $false $malwareRuleQueryFailed = $false $spamPolicies = @() $spamRules = @() $spamPolicyQueryFailed = $false $spamRuleQueryFailed = $false # Q1: Read ZAP-related properties from anti-malware policies and their rules. Write-ZtProgress -Activity $activity -Status 'Getting anti-malware filter policies' try { $malwarePolicies = @(Get-MalwareFilterPolicy -ErrorAction Stop | Select-Object Identity, IsDefault, ZapEnabled) } catch { $malwarePolicyQueryFailed = $true Write-PSFMessage "Failed to retrieve anti-malware policies: $_" -Tag Test -Level Warning } Write-ZtProgress -Activity $activity -Status 'Getting anti-malware filter rules' try { $malwareRules = @(Get-MalwareFilterRule -ErrorAction Stop | Select-Object Name, MalwareFilterPolicy, Priority, State) } catch { $malwareRuleQueryFailed = $true Write-PSFMessage "Failed to retrieve anti-malware rules: $_" -Tag Test -Level Warning } # Q2: Read ZAP-related properties from anti-spam policies and their rules. Write-ZtProgress -Activity $activity -Status 'Getting hosted content filter policies' try { $spamPolicies = @(Get-HostedContentFilterPolicy -ErrorAction Stop | Select-Object Identity, IsDefault, SpamZapEnabled, PhishZapEnabled) } catch { $spamPolicyQueryFailed = $true Write-PSFMessage "Failed to retrieve anti-spam policies: $_" -Tag Test -Level Warning } Write-ZtProgress -Activity $activity -Status 'Getting hosted content filter rules' try { $spamRules = @(Get-HostedContentFilterRule -ErrorAction Stop | Select-Object Name, HostedContentFilterPolicy, Priority, State) } catch { $spamRuleQueryFailed = $true Write-PSFMessage "Failed to retrieve anti-spam rules: $_" -Tag Test -Level Warning } #endregion Data Collection #region Assessment Logic $malwarePolicyRows = @() $spamPolicyRows = @() $hasFailure = $false $hasInvestigate = $false $malwarePolicyUnavailable = $malwarePolicyQueryFailed -or $malwarePolicies.Count -eq 0 $spamPolicyUnavailable = $spamPolicyQueryFailed -or $spamPolicies.Count -eq 0 if ($malwarePolicyUnavailable) { $hasInvestigate = $true $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null ZapEnabled = $null Result = 'Investigate' StatusDetail = 'could not retrieve anti-malware policies' } } else { $malwarePolicyByIdentity = @{} foreach ($policy in $malwarePolicies) { $malwarePolicyByIdentity[$policy.Identity] = $policy } $defaultMalwarePolicies = @($malwarePolicies | Where-Object { $_.IsDefault -eq $true }) if ($defaultMalwarePolicies.Count -eq 0) { $hasInvestigate = $true $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null ZapEnabled = $null Result = 'Investigate' StatusDetail = 'default policy not found' } } foreach ($policy in $defaultMalwarePolicies) { $propertyKnown = $policy.ZapEnabled -is [bool] $propertyEnabled = $propertyKnown -and $policy.ZapEnabled $result = if (-not $propertyKnown) { $hasInvestigate = $true 'Investigate' } elseif ($propertyEnabled) { 'Pass' } else { $hasFailure = $true 'Fail' } $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = $policy.Identity IsDefault = $true RuleName = $null ZapEnabled = if ($propertyKnown) { $propertyEnabled } else { $null } Result = $result StatusDetail = if ($propertyKnown) { $null } else { 'ZapEnabled value is unavailable' } } } if ($malwareRuleQueryFailed) { $hasInvestigate = $true $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null ZapEnabled = $null Result = 'Investigate' StatusDetail = 'could not retrieve anti-malware rules' } } else { foreach ($rule in ($malwareRules | Where-Object { $_.State -eq 'Enabled' })) { $policy = $malwarePolicyByIdentity[$rule.MalwareFilterPolicy] if ($null -eq $policy) { $hasInvestigate = $true $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = $rule.MalwareFilterPolicy IsDefault = $false RuleName = $rule.Name ZapEnabled = $null Result = 'Investigate' StatusDetail = 'referenced policy not found' } continue } $propertyKnown = $policy.ZapEnabled -is [bool] $propertyEnabled = $propertyKnown -and $policy.ZapEnabled $result = if (-not $propertyKnown) { $hasInvestigate = $true 'Investigate' } elseif ($propertyEnabled) { 'Pass' } else { $hasFailure = $true 'Fail' } $malwarePolicyRows += [PSCustomObject]@{ PolicyIdentity = $policy.Identity IsDefault = $false RuleName = $rule.Name ZapEnabled = if ($propertyKnown) { $propertyEnabled } else { $null } Result = $result StatusDetail = if ($propertyKnown) { $null } else { 'ZapEnabled value is unavailable' } } } } } if ($spamPolicyUnavailable) { $hasInvestigate = $true $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null PhishZapEnabled = $null SpamZapEnabled = $null Result = 'Investigate' StatusDetail = 'could not retrieve anti-spam policies' } } else { $spamPolicyByIdentity = @{} foreach ($policy in $spamPolicies) { $spamPolicyByIdentity[$policy.Identity] = $policy } $defaultSpamPolicies = @($spamPolicies | Where-Object { $_.IsDefault -eq $true }) if ($defaultSpamPolicies.Count -eq 0) { $hasInvestigate = $true $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null PhishZapEnabled = $null SpamZapEnabled = $null Result = 'Investigate' StatusDetail = 'default policy not found' } } foreach ($policy in $defaultSpamPolicies) { $phishZapKnown = $policy.PhishZapEnabled -is [bool] $spamZapKnown = $policy.SpamZapEnabled -is [bool] $phishZapEnabled = $phishZapKnown -and $policy.PhishZapEnabled $spamZapEnabled = $spamZapKnown -and $policy.SpamZapEnabled $result = if (($phishZapKnown -and -not $phishZapEnabled) -or ($spamZapKnown -and -not $spamZapEnabled)) { $hasFailure = $true 'Fail' } elseif ($phishZapEnabled -and $spamZapEnabled) { 'Pass' } else { $hasInvestigate = $true 'Investigate' } $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = $policy.Identity IsDefault = $true RuleName = $null PhishZapEnabled = if ($phishZapKnown) { $phishZapEnabled } else { $null } SpamZapEnabled = if ($spamZapKnown) { $spamZapEnabled } else { $null } Result = $result StatusDetail = if ($phishZapKnown -and $spamZapKnown) { $null } else { 'one or more ZAP values are unavailable' } } } if ($spamRuleQueryFailed) { $hasInvestigate = $true $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = '—' IsDefault = $false RuleName = $null PhishZapEnabled = $null SpamZapEnabled = $null Result = 'Investigate' StatusDetail = 'could not retrieve anti-spam rules' } } else { foreach ($rule in ($spamRules | Where-Object { $_.State -eq 'Enabled' })) { $policy = $spamPolicyByIdentity[$rule.HostedContentFilterPolicy] if ($null -eq $policy) { $hasInvestigate = $true $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = $rule.HostedContentFilterPolicy IsDefault = $false RuleName = $rule.Name PhishZapEnabled = $null SpamZapEnabled = $null Result = 'Investigate' StatusDetail = 'referenced policy not found' } continue } $phishZapKnown = $policy.PhishZapEnabled -is [bool] $spamZapKnown = $policy.SpamZapEnabled -is [bool] $phishZapEnabled = $phishZapKnown -and $policy.PhishZapEnabled $spamZapEnabled = $spamZapKnown -and $policy.SpamZapEnabled $result = if (($phishZapKnown -and -not $phishZapEnabled) -or ($spamZapKnown -and -not $spamZapEnabled)) { $hasFailure = $true 'Fail' } elseif ($phishZapEnabled -and $spamZapEnabled) { 'Pass' } else { $hasInvestigate = $true 'Investigate' } $spamPolicyRows += [PSCustomObject]@{ PolicyIdentity = $policy.Identity IsDefault = $false RuleName = $rule.Name PhishZapEnabled = if ($phishZapKnown) { $phishZapEnabled } else { $null } SpamZapEnabled = if ($spamZapKnown) { $spamZapEnabled } else { $null } Result = $result StatusDetail = if ($phishZapKnown -and $spamZapKnown) { $null } else { 'one or more ZAP values are unavailable' } } } } } $passed = $false $customStatus = $null if ($hasFailure) { $testResultMarkdown = "❌ One or more in-scope policies disable ZAP for malware, spam, or phish; reclassified messages will remain in user mailboxes.`n`n%TestResult%" } elseif ($hasInvestigate) { $customStatus = 'Investigate' $testResultMarkdown = "⚠️ An email ZAP policy surface could not be evaluated completely because policy or rule data is unavailable, or an enabled rule references a policy that does not exist; manual review is required.`n`n%TestResult%" } else { $passed = $true $testResultMarkdown = "✅ Zero-hour auto purge is enabled for malware, spam, and phish across all in-scope EOP anti-malware and anti-spam policies.`n`n%TestResult%" } #endregion Assessment Logic #region Report Generation $maxDisplay = 10 $statusPriority = @{ Fail = 0; Investigate = 1; Pass = 2 } $sortedMalwareRows = @($malwarePolicyRows | Sort-Object { $statusPriority[$_.Result] }, PolicyIdentity) $displayMalwareRows = @($sortedMalwareRows | Select-Object -First $maxDisplay) $malwareTableRows = '' foreach ($row in $displayMalwareRows) { $defaultSuffix = if ($row.IsDefault) { ' [default]' } else { '' } $policyIdentity = "$(Get-SafeMarkdown -Text $row.PolicyIdentity)$defaultSuffix" $appliedViaRule = if ($row.IsDefault) { '— (catch-all)' } elseif ($row.RuleName) { Get-SafeMarkdown -Text $row.RuleName } else { '—' } $zapDisplay = if ($null -eq $row.ZapEnabled) { '⚠️ Unknown' } elseif ($row.ZapEnabled) { '✅ Yes' } else { '❌ No' } $resultDisplay = switch ($row.Result) { 'Pass' { '✅ Pass' } 'Fail' { '❌ Fail' } 'Investigate' { if ($row.StatusDetail) { "⚠️ Investigate — $($row.StatusDetail)" } else { '⚠️ Investigate' } } } $malwareTableRows += "| $policyIdentity | $appliedViaRule | $zapDisplay | $resultDisplay |`n" } if ($sortedMalwareRows.Count -gt $maxDisplay) { $malwareTableRows += "| ... | ... | ... | ... |`n" } $malwarePolicyDetails = if ($sortedMalwareRows.Count -gt 0) { @" | Policy identity | Applied via Rule | ZAP for malware | Status | | :-------------- | :--------------- | :-------------- | :----- | $malwareTableRows "@ } else { @' No in-scope anti-malware policy rows could be resolved; verify the default policy and enabled rule references. '@ } $sortedSpamRows = @($spamPolicyRows | Sort-Object { $statusPriority[$_.Result] }, PolicyIdentity) $displaySpamRows = @($sortedSpamRows | Select-Object -First $maxDisplay) $spamTableRows = '' foreach ($row in $displaySpamRows) { $defaultSuffix = if ($row.IsDefault) { ' [default]' } else { '' } $policyIdentity = "$(Get-SafeMarkdown -Text $row.PolicyIdentity)$defaultSuffix" $appliedViaRule = if ($row.IsDefault) { '— (catch-all)' } elseif ($row.RuleName) { Get-SafeMarkdown -Text $row.RuleName } else { '—' } $phishZapDisplay = if ($null -eq $row.PhishZapEnabled) { '⚠️ Unknown' } elseif ($row.PhishZapEnabled) { '✅ Yes' } else { '❌ No' } $spamZapDisplay = if ($null -eq $row.SpamZapEnabled) { '⚠️ Unknown' } elseif ($row.SpamZapEnabled) { '✅ Yes' } else { '❌ No' } $resultDisplay = switch ($row.Result) { 'Pass' { '✅ Pass' } 'Fail' { '❌ Fail' } 'Investigate' { if ($row.StatusDetail) { "⚠️ Investigate — $($row.StatusDetail)" } else { '⚠️ Investigate' } } } $spamTableRows += "| $policyIdentity | $appliedViaRule | $phishZapDisplay | $spamZapDisplay | $resultDisplay |`n" } if ($sortedSpamRows.Count -gt $maxDisplay) { $spamTableRows += "| ... | ... | ... | ... | ... |`n" } $spamPolicyDetails = if ($sortedSpamRows.Count -gt 0) { @" | Policy identity | Applied via Rule | ZAP for phishing | ZAP for spam | Status | | :-------------- | :--------------- | :--------------- | :----------- | :----- | $spamTableRows "@ } else { @' No in-scope anti-spam policy rows could be resolved; verify the default policy and enabled rule references. '@ } $threatPolicyLink = '' if ($sortedMalwareRows.Count -gt $maxDisplay -or $sortedSpamRows.Count -gt $maxDisplay) { $threatPolicyLink = @' [Microsoft 365 Defender > Policies & rules > Threat policies](https://security.microsoft.com/threatpolicy) '@ } $formatTemplate = @' ## Anti-malware policy settings {0} ## Anti-spam policy settings {1} {2} '@ $mdInfo = $formatTemplate -f $malwarePolicyDetails, $spamPolicyDetails, $threatPolicyLink $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo #endregion Report Generation $params = @{ TestId = '41039' Title = 'Zero-hour auto purge (ZAP) is enabled for malware, phishing, and spam in email' Status = $passed Result = $testResultMarkdown } if ($customStatus) { $params.CustomStatus = $customStatus } Add-ZtTestResultDetail @params } |