add: Core logic to switch between versions

This commit is contained in:
DrIOS
2024-12-24 15:51:03 -06:00
parent ca021695a4
commit 5753ab8a4f
6 changed files with 67 additions and 43 deletions

View File

@@ -9,6 +9,7 @@ The format is based on and uses the types of changes according to [Keep a Change
- Link to App Authentication documentation in `New-M365SecurityAuditAuthObject` help file.
- TestDefinitions-v4.0.0.csv file to the helper folder for version choices.
- Test Definition Placeholders
- Added steps to function to account for new logic and create an updated test definition object when version 4.0.0 is selected.
## [0.1.26] - 2024-08-04

View File

@@ -296,6 +296,7 @@ function Get-CISExoOutput {
return $spamPolicies
}
'2.1.7' {
# v4 needs same info.
# Test-AntiPhishingPolicy.ps1
<#
$antiPhishPolicies = @(
@@ -340,9 +341,6 @@ function Get-CISExoOutput {
$antiPhishPolicies = Get-AntiPhishPolicy
return $antiPhishPolicies
}
'2.1.7-v4' {
# Placeholder Test-AntiPhishingPolicy.ps1
}
'2.1.9' {
# Test-EnableDKIM.ps1
# 2.1.9 (L1) Ensure DKIM is enabled for all Exchange Online Domains

View File

@@ -38,15 +38,12 @@ function Get-CISMgOutput {
Write-Verbose "Get-CISMgOutput: Returning data for Rec: $Rec"
switch ($rec) {
'1.1.1' {
# V4 needs same info
# 1.1.1 - MicrosoftGraphPlaceholder
# Test-AdministrativeAccountCompliance
$AdminRoleAssignmentsAndUsers = Get-AdminRoleUserAndAssignment
return $AdminRoleAssignmentsAndUsers
}
'1.1.1-v4' {
# 1.1.1-v4 - MicrosoftGraphPlaceholder
# Placeholder for the new v4 logic for Test-AdministrativeAccountCompliance
}
'1.1.4' {
# 1.1.4 - MicrosoftGraphPlaceholder
# Placeholder for Test-AdminAccountLicenses
@@ -61,7 +58,7 @@ function Get-CISMgOutput {
}
'1.2.1' {
# Test-ManagedApprovedPublicGroups
$allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility
$allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq 'Public' } | Select-Object DisplayName, Visibility
return $allGroups
}
'1.2.2' {
@@ -94,7 +91,7 @@ function Get-CISMgOutput {
'6.1.2' {
# Test-MailboxAuditingE3
$tenantSKUs = Get-MgSubscribedSku -All
$e3SkuPartNumber = "SPE_E3"
$e3SkuPartNumber = 'SPE_E3'
$foundE3Sku = $tenantSKUs | Where-Object { $_.SkuPartNumber -eq $e3SkuPartNumber }
if ($foundE3Sku.Count -ne 0) {
$allE3Users = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($foundE3Sku.SkuId) )" -All
@@ -107,7 +104,7 @@ function Get-CISMgOutput {
'6.1.3' {
# Test-MailboxAuditingE5
$tenantSKUs = Get-MgSubscribedSku -All
$e5SkuPartNumber = "SPE_E5"
$e5SkuPartNumber = 'SPE_E5'
$foundE5Sku = $tenantSKUs | Where-Object { $_.SkuPartNumber -eq $e5SkuPartNumber }
if ($foundE5Sku.Count -ne 0) {
$allE5Users = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($foundE5Sku.SkuId) )" -All

View File

@@ -25,8 +25,8 @@ function Invoke-TestFunction {
if ('ApprovedFederatedDomains' -in $functionCmd.Parameters.Keys) {
$paramList.ApprovedFederatedDomains = $ApprovedFederatedDomains
}
# Use splatting to pass parameters
Write-Verbose "Running $functionName..."
# Version-aware logging
Write-Verbose "Running $functionName (Version: $($script:Version400 ? '4.0.0' : '3.0.0'))..."
try {
$result = & $functionName @paramList
# Assuming each function returns an array of CISAuditResult or a single CISAuditResult

View File

@@ -4,6 +4,7 @@
.DESCRIPTION
The Invoke-M365SecurityAudit cmdlet performs a comprehensive security audit based on the specified parameters.
It allows auditing of various configurations and settings within a Microsoft 365 environment in alignment with CIS benchmarks designated "Automatic".
Supports selection of CIS benchmark definitions version (default is 4.0.0).
.PARAMETER TenantAdminUrl
The URL of the tenant admin. If not specified, none of the SharePoint Online tests will run.
.PARAMETER DomainName
@@ -12,7 +13,7 @@
.PARAMETER ELevel
Specifies the E-Level (E3 or E5) for the audit. This parameter is optional and can be combined with the ProfileLevel parameter.
.PARAMETER ProfileLevel
Specifies the profile level (L1 or L2) for the audit. This parameter is mandatory, but only when ELevel is selected. Otherwise it is not required.
Specifies the profile level (L1 or L2) for the audit. This parameter is mandatory, but only when ELevel is selected. Otherwise, it is not required.
.PARAMETER IncludeIG1
If specified, includes tests where IG1 is true.
.PARAMETER IncludeIG2
@@ -39,6 +40,8 @@
If specified, the cmdlet will not prompt for confirmation before proceeding with established connections and will disconnect from all of them.
.PARAMETER AuthParams
Specifies an authentication object containing parameters for application-based authentication. If provided, this will be used for connecting to services.
.PARAMETER Version
Specifies the CIS benchmark definitions version to use. Default is 4.0.0. Valid values are "3.0.0" or "4.0.0".
.EXAMPLE
PS> Invoke-M365SecurityAudit
# Performs a security audit using default parameters.
@@ -51,6 +54,9 @@
.EXAMPLE
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -SkipRecommendation '1.1.3', '2.1.1'
# Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1.
.EXAMPLE
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -Version "3.0.0"
# Performs a security audit using the CIS benchmark definitions version 3.0.0.
.EXAMPLE
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com"
PS> Export-M365SecurityAuditTable -AuditResults $auditResults -ExportPath "C:\temp" -ExportOriginalTests -ExportAllTests
@@ -89,9 +95,10 @@
.LINK
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
#>
function Invoke-M365SecurityAudit {
# Add confirm to high
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High" , DefaultParameterSetName = 'Default')]
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High' , DefaultParameterSetName = 'Default')]
[OutputType([CISAuditResult[]])]
param (
[Parameter(Mandatory = $false, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'. If not specified none of the Sharepoint Online tests will run.")]
@@ -101,21 +108,21 @@ function Invoke-M365SecurityAudit {
[ValidatePattern('^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$')]
[string]$DomainName,
# E-Level with optional ProfileLevel selection
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter', HelpMessage = "Specifies the E-Level (E3 or E5) for the audit.")]
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter', HelpMessage = 'Specifies the E-Level (E3 or E5) for the audit.')]
[ValidateSet('E3', 'E5')]
[string]$ELevel,
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter', HelpMessage = "Specifies the profile level (L1 or L2) for the audit.")]
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter', HelpMessage = 'Specifies the profile level (L1 or L2) for the audit.')]
[ValidateSet('L1', 'L2')]
[string]$ProfileLevel,
# IG Filters, one at a time
[Parameter(Mandatory = $true, ParameterSetName = 'IG1Filter', HelpMessage = "Includes tests where IG1 is true.")]
[Parameter(Mandatory = $true, ParameterSetName = 'IG1Filter', HelpMessage = 'Includes tests where IG1 is true.')]
[switch]$IncludeIG1,
[Parameter(Mandatory = $true, ParameterSetName = 'IG2Filter', HelpMessage = "Includes tests where IG2 is true.")]
[Parameter(Mandatory = $true, ParameterSetName = 'IG2Filter', HelpMessage = 'Includes tests where IG2 is true.')]
[switch]$IncludeIG2,
[Parameter(Mandatory = $true, ParameterSetName = 'IG3Filter', HelpMessage = "Includes tests where IG3 is true.")]
[Parameter(Mandatory = $true, ParameterSetName = 'IG3Filter', HelpMessage = 'Includes tests where IG3 is true.')]
[switch]$IncludeIG3,
# Inclusion of specific recommendation numbers
[Parameter(Mandatory = $true, ParameterSetName = 'RecFilter', HelpMessage = "Specifies specific recommendations to include in the audit. Accepts an array of recommendation numbers.")]
[Parameter(Mandatory = $true, ParameterSetName = 'RecFilter', HelpMessage = 'Specifies specific recommendations to include in the audit. Accepts an array of recommendation numbers.')]
[ValidateSet(
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
@@ -127,7 +134,7 @@ function Invoke-M365SecurityAudit {
)]
[string[]]$IncludeRecommendation,
# Exclusion of specific recommendation numbers
[Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter', HelpMessage = "Specifies specific recommendations to exclude from the audit. Accepts an array of recommendation numbers.")]
[Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter', HelpMessage = 'Specifies specific recommendations to exclude from the audit. Accepts an array of recommendation numbers.')]
[ValidateSet(
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
@@ -139,24 +146,27 @@ function Invoke-M365SecurityAudit {
)]
[string[]]$SkipRecommendation,
# Common parameters for all parameter sets
[Parameter(Mandatory = $false, HelpMessage = "Specifies the approved cloud storage providers for the audit. Accepts an array of cloud storage provider names.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies the approved cloud storage providers for the audit. Accepts an array of cloud storage provider names.')]
[ValidateSet(
'GoogleDrive', 'ShareFile', 'Box', 'DropBox', 'Egnyte'
)]
[string[]]$ApprovedCloudStorageProviders = @(),
[Parameter(Mandatory = $false, HelpMessage = "Specifies the approved federated domains for the audit test 8.2.1. Accepts an array of allowed domain names.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies the approved federated domains for the audit test 8.2.1. Accepts an array of allowed domain names.')]
[ValidatePattern('^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$')]
[string[]]$ApprovedFederatedDomains,
[Parameter(Mandatory = $false, HelpMessage = "Specifies that the cmdlet will not establish a connection to Microsoft 365 services.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies that the cmdlet will not establish a connection to Microsoft 365 services.')]
[switch]$DoNotConnect,
[Parameter(Mandatory = $false, HelpMessage = "Specifies that the cmdlet will not disconnect from Microsoft 365 services after execution.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies that the cmdlet will not disconnect from Microsoft 365 services after execution.')]
[switch]$DoNotDisconnect,
[Parameter(Mandatory = $false, HelpMessage = "Specifies that the cmdlet will not check for the presence of required modules.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies that the cmdlet will not check for the presence of required modules.')]
[switch]$NoModuleCheck,
[Parameter(Mandatory = $false, HelpMessage = "Specifies that the cmdlet will not prompt for confirmation before proceeding with established connections and will disconnect from all of them.")]
[Parameter(Mandatory = $false, HelpMessage = 'Specifies that the cmdlet will not prompt for confirmation before proceeding with established connections and will disconnect from all of them.')]
[switch]$DoNotConfirmConnections,
[Parameter(Mandatory = $false, HelpMessage = "Specifies an authentication object containing parameters for application-based authentication.")]
[CISAuthenticationParameters]$AuthParams
[Parameter(Mandatory = $false, HelpMessage = 'Specifies an authentication object containing parameters for application-based authentication.')]
[CISAuthenticationParameters]$AuthParams,
[Parameter(Mandatory = $false, HelpMessage = "Specifies the CIS benchmark definitions version to use. Default is 4.0.0. Valid values are '3.0.0' or '4.0.0'.")]
[ValidateSet('3.0.0', '4.0.0')]
[string]$Version = '4.0.0'
)
Begin {
if ($script:MaximumFunctionCount -lt 8192) {
@@ -171,15 +181,33 @@ function Invoke-M365SecurityAudit {
# Format the required modules list
$requiredModulesFormatted = Format-RequiredModuleList -RequiredModules $requiredModules
# Check and install required modules if necessary
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Modules: $requiredModulesFormatted", "Assert-ModuleAvailability")) {
Write-Information "Checking for and installing required modules..."
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Modules: $requiredModulesFormatted", 'Assert-ModuleAvailability')) {
Write-Information 'Checking for and installing required modules...'
foreach ($module in $requiredModules) {
Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModules $module.SubModules
}
}
# Load test definitions from CSV
$testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv"
$testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath 'helper\TestDefinitions.csv'
$testDefinitions = Import-Csv -Path $testDefinitionsPath
if ($Version -eq '4.0.0') {
$script:Version400 = $true
$testDefinitionsV4Path = Join-Path -Path $PSScriptRoot -ChildPath 'helper\TestDefinitions-v4.0.0.csv'
$testDefinitionsV4 = Import-Csv -Path $testDefinitionsV4Path
# Merge the definitions, prioritizing version 4.0.0
$mergedDefinitions = @{}
foreach ($test in $testDefinitions) {
$mergedDefinitions[$test.Rec] = $test
}
foreach ($testV4 in $testDefinitionsV4) {
$mergedDefinitions[$testV4.Rec] = $testV4 # Overwrite if Rec exists
}
# Convert back to an array
$testDefinitions = $mergedDefinitions.Values
Write-Verbose "Total tests after merging: $(($testDefinitions).Count)"
$overwrittenTests = $testDefinitionsV4 | Where-Object { $testDefinitions[$_.Rec] }
Write-Verbose "Overwritten tests: $($overwrittenTests.Rec -join ', ')"
}
# Load the Test Definitions into the script scope for use in other functions
$script:TestDefinitionsObject = $testDefinitions
# Apply filters based on parameter sets
@@ -199,7 +227,7 @@ function Invoke-M365SecurityAudit {
$requiredConnections = $requiredConnections | Where-Object { $_ -ne 'SPO' }
$testDefinitions = $testDefinitions | Where-Object { $_.Connection -ne 'SPO' }
if ($null -eq $testDefinitions) {
throw "No tests to run as no SharePoint Online tests are available."
throw 'No tests to run as no SharePoint Online tests are available.'
}
}
}
@@ -213,15 +241,15 @@ function Invoke-M365SecurityAudit {
Process {
$allAuditResults = [System.Collections.ArrayList]::new() # Initialize a collection to hold all results
# Dynamically dot-source the test scripts
$testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "tests"
$testFiles = Get-ChildItem -Path $testsFolderPath -Filter "Test-*.ps1" |
$testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath 'tests'
$testFiles = Get-ChildItem -Path $testsFolderPath -Filter 'Test-*.ps1' |
Where-Object { $testsToLoad -contains $_.BaseName }
$totalTests = $testFiles.Count
$currentTestIndex = 0
# Establishing connections if required
try {
$actualUniqueConnections = Get-UniqueConnection -Connections $requiredConnections
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')", "Connect")) {
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')", 'Connect')) {
Write-Information "Establishing connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')"
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections -SkipConfirmation:$DoNotConfirmConnections -AuthParams $AuthParams
}
@@ -230,12 +258,12 @@ function Invoke-M365SecurityAudit {
Throw "Connection execution aborted: $_"
}
try {
if ($PSCmdlet.ShouldProcess("Measure and display audit results for $($totalTests) tests", "Measure")) {
if ($PSCmdlet.ShouldProcess("Measure and display audit results for $($totalTests) tests", 'Measure')) {
Write-Information "A total of $($totalTests) tests were selected to run..."
# Import the test functions
$testFiles | ForEach-Object {
$currentTestIndex++
Write-Progress -Activity "Loading Test Scripts" -Status "Loading $($currentTestIndex) of $($totalTests): $($_.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100)
Write-Progress -Activity 'Loading Test Scripts' -Status "Loading $($currentTestIndex) of $($totalTests): $($_.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100)
Try {
# Dot source the test function
. $_.FullName
@@ -250,7 +278,7 @@ function Invoke-M365SecurityAudit {
# Execute each test function from the prepared list
foreach ($testFunction in $testFiles) {
$currentTestIndex++
Write-Progress -Activity "Executing Tests" -Status "Executing $($currentTestIndex) of $($totalTests): $($testFunction.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100)
Write-Progress -Activity 'Executing Tests' -Status "Executing $($currentTestIndex) of $($totalTests): $($testFunction.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100)
$functionName = $testFunction.BaseName
Write-Information "Executing test function: $functionName"
$auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName -ApprovedCloudStorageProviders $ApprovedCloudStorageProviders -ApprovedFederatedDomains $ApprovedFederatedDomains
@@ -261,7 +289,7 @@ function Invoke-M365SecurityAudit {
Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests
# Return all collected audit results
# Define the test numbers to check
$TestNumbersToCheck = "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4"
$TestNumbersToCheck = '1.1.1', '1.3.1', '6.1.2', '6.1.3', '7.3.4'
# Check for large details in the audit results
$exceedingTests = Get-ExceededLengthResultDetail -AuditResults $allAuditResults -TestNumbersToCheck $TestNumbersToCheck -ReturnExceedingTestsOnly -DetailsLengthLimit 30000
if ($exceedingTests.Count -gt 0) {
@@ -278,7 +306,7 @@ function Invoke-M365SecurityAudit {
$script:FailedTests.Add([PSCustomObject]@{ Test = $_.Name; Error = $_ })
}
finally {
if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services: $($actualUniqueConnections -join ', ')", "Disconnect")) {
if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services: $($actualUniqueConnections -join ', ')", 'Disconnect')) {
# Clean up sessions
Disconnect-M365Suite -RequiredConnections $requiredConnections
}

View File

@@ -1,7 +1,7 @@
Index,TestFileName,Rec,RecDescription,ELevel,ProfileLevel,CISControl,CISDescription,IG1,IG2,IG3,Automated,Connection
1,Test-AdministrativeAccountCompliance.ps1,1.1.1,Ensure Administrative accounts are cloud-only,E3,L1,5.4,Restrict Administrator Privileges to Dedicated Administrator Accounts,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
1,Test-AdministrativeAccountCompliance4.ps1,1.1.1,Ensure Administrative accounts are cloud-only,E3,L1,5.4,Restrict Administrator Privileges to Dedicated Administrator Accounts,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
2,Test-AdminAccountLicenses.ps1,1.1.4,Ensure administrative accounts use licenses with a reduced application footprint,E3,L1,5.4,Restrict Administrator Privileges to Dedicated Administrator Accounts,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
3,Test-AntiPhishingPolicy.ps1,2.1.7,Ensure that an anti-phishing policy has been created,E5,L2,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
3,Test-AntiPhishingPolicy4.ps1,2.1.7,Ensure that an anti-phishing policy has been created,E5,L2,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
4,Test-AttachmentFiltering.ps1,2.1.11,Ensure comprehensive attachment filtering is applied,E3,L2,9.6,Block unnecessary file types attempting to enter the enterprises email gateway,FALSE,TRUE,TRUE,TRUE,EXO
5,Test-ConnectionFilterIPAllowList.ps1,2.1.12,(L1) Ensure the connection filter IP allow list is not used,E3,L1,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
6,Test-ConnectionFilterSafeList.ps1,2.1.13,(L1) Ensure the connection filter safe list is off,E3,L1,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
1 Index TestFileName Rec RecDescription ELevel ProfileLevel CISControl CISDescription IG1 IG2 IG3 Automated Connection
2 1 Test-AdministrativeAccountCompliance.ps1 Test-AdministrativeAccountCompliance4.ps1 1.1.1 Ensure Administrative accounts are cloud-only E3 L1 5.4 Restrict Administrator Privileges to Dedicated Administrator Accounts TRUE TRUE TRUE TRUE Microsoft Graph
3 2 Test-AdminAccountLicenses.ps1 1.1.4 Ensure administrative accounts use licenses with a reduced application footprint E3 L1 5.4 Restrict Administrator Privileges to Dedicated Administrator Accounts TRUE TRUE TRUE TRUE Microsoft Graph
4 3 Test-AntiPhishingPolicy.ps1 Test-AntiPhishingPolicy4.ps1 2.1.7 Ensure that an anti-phishing policy has been created E5 L2 9.7 Deploy and Maintain Email Server Anti-Malware Protections FALSE FALSE TRUE TRUE EXO
5 4 Test-AttachmentFiltering.ps1 2.1.11 Ensure comprehensive attachment filtering is applied E3 L2 9.6 Block unnecessary file types attempting to enter the enterprise’s email gateway FALSE TRUE TRUE TRUE EXO
6 5 Test-ConnectionFilterIPAllowList.ps1 2.1.12 (L1) Ensure the connection filter IP allow list is not used E3 L1 9.7 Deploy and Maintain Email Server Anti-Malware Protections FALSE FALSE TRUE TRUE EXO
7 6 Test-ConnectionFilterSafeList.ps1 2.1.13 (L1) Ensure the connection filter safe list is off E3 L1 9.7 Deploy and Maintain Email Server Anti-Malware Protections FALSE FALSE TRUE TRUE EXO