diff --git a/Diagnostics/HealthChecker/Analyzer/Get-FilteredSettingOverrideInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Get-FilteredSettingOverrideInformation.ps1
index 481b9275b0..c49b44b7b4 100644
--- a/Diagnostics/HealthChecker/Analyzer/Get-FilteredSettingOverrideInformation.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Get-FilteredSettingOverrideInformation.ps1
@@ -29,11 +29,11 @@ function Get-FilteredSettingOverrideInformation {
[string]$FilterSectionName,
[Parameter(Mandatory = $true)]
- [string]$FilterParameterName
+ [string[]]$FilterParameterName
)
begin {
Write-Verbose "Calling: $($MyInvocation.MyCommand)"
- Write-Verbose "Trying to filter down results for ComponentName: $FilterComponentName SectionName: $FilterSectionName ParameterName: $FilterParameterName"
+ Write-Verbose "Trying to filter down results for ComponentName: $FilterComponentName SectionName: $FilterSectionName ParameterName: $([string]::Join(", ", $FilterParameterName))"
$results = New-Object "System.Collections.Generic.List[object]"
$findFromOverride = $null
$usedAdSettings = $false
@@ -63,47 +63,50 @@ function Get-FilteredSettingOverrideInformation {
Write-Verbose "Working on entry: $($entry.Name)"
foreach ($p in [array]($entry.Parameters)) {
Write-Verbose "Working on parameter: $p"
- if ($p.Contains($FilterParameterName)) {
- $value = $p.Substring($FilterParameterName.Length + 1) # Add plus 1 for '='
- # everything matched, however, only add it to the list for the following reasons
- # - Status is Accepted and not from AD and a unique value in the list
- # - Or From AD and current logic determines it applies
+ foreach ($currentFilterParameterName in $FilterParameterName) {
+ if ($p.Contains($currentFilterParameterName)) {
+ $value = $p.Substring($currentFilterParameterName.Length + 1) # Add plus 1 for '='
+ # everything matched, however, only add it to the list for the following reasons
+ # - Status is Accepted and not from AD and a unique value in the list
+ # - Or From AD and current logic determines it applies
- if ($usedAdSettings) {
- # can have it apply by build and server parameter
- if (($null -eq $entry.MinVersion -or
- $FilterServerVersion -ge $entry.MinVersion) -and
+ if ($usedAdSettings) {
+ # can have it apply by build and server parameter
+ if (($null -eq $entry.MinVersion -or
+ $FilterServerVersion -ge $entry.MinVersion) -and
(($null -eq $entry.MaxVersion -or
- $FilterServerVersion -le $entry.MaxVersion)) -and
+ $FilterServerVersion -le $entry.MaxVersion)) -and
(($null -eq $entry.Server -or
- $entry.Server.ToLower().Contains($adjustedFilterServer)))) {
- $status = $entry.Status
+ $entry.Server -contains $adjustedFilterServer))) {
+ $status = $entry.Status.ToString()
+ } else {
+ $status = "DoesNotApply"
+ }
} else {
- $status = "DoesNotApply"
+ $status = $entry.Status.ToString()
}
- } else {
- $status = $entry.Status
- }
- if ($status -eq "Accepted" -and
+ # Add to the list if the status is Accepted, and we do not have that ParameterName yet in the list.
+ if ($status -eq "Accepted" -and
($results.Count -lt 1 -or
- -not ($results.ParameterValue.ToLower().Contains($value.ToLower())))) {
- $results.Add([PSCustomObject]@{
- Name = $entry.Name
- Reason = $entry.Reason
- ModifiedBy = $entry.ModifiedBy
- ComponentName = $entry.ComponentName
- SectionName = $entry.SectionName
- ParameterName = $FilterParameterName
- ParameterValue = $value
- Status = $entry.Status
- TrueStatus = $status
- FromAdSettings = $usedAdSettings
- })
- } elseif ($status -eq "Accepted") {
- Write-Verbose "Already have 1 Accepted value added to list no need to add another one. Skip adding $($entry.Name)"
- } else {
- Write-Verbose "Already have parameter value added to the. Skip adding $($entry.Name)"
+ -not ($results.ParameterName -contains $currentFilterParameterName))) {
+ $results.Add([PSCustomObject]@{
+ Name = $entry.Name
+ Reason = $entry.Reason
+ ModifiedBy = $entry.ModifiedBy
+ ComponentName = $entry.ComponentName
+ SectionName = $entry.SectionName
+ ParameterName = $currentFilterParameterName
+ ParameterValue = $value
+ Status = $entry.Status
+ TrueStatus = $status
+ FromAdSettings = $usedAdSettings
+ })
+ } elseif ($status -eq "Accepted") {
+ Write-Verbose "Already have 1 Accepted value added to list no need to add another one. Skip adding $($entry.Name)"
+ } else {
+ Write-Verbose "Already have parameter value added to the list. Skip adding $($entry.Name)"
+ }
}
}
}
diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
index 5dc05064ed..12cd4301b0 100644
--- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
@@ -74,6 +74,21 @@ function Invoke-AnalyzerFrequentConfigurationIssues {
}
Add-AnalyzedResultInformation @params
+ $detailsValue = $exchangeInformation.RegistryValues.EnableEccCertificateSupport
+ $displayWriteType = "Grey"
+
+ if (-not (Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -SUName "Nov24SU") -and $detailsValue -eq "1") {
+ $detailsValue = "1 --- Warning: On a build that doesn't support this configuration yet.`r`n`t`tMore Information: https://aka.ms/HC-EccCertificateChange"
+ $displayWriteType = "Yellow"
+ }
+
+ $params = $baseParams + @{
+ Name = "EnableEccCertificateSupport Registry Value"
+ Details = $detailsValue
+ DisplayWriteType = $displayWriteType
+ }
+ Add-AnalyzedResultInformation @params
+
$displayValue = $exchangeInformation.RegistryValues.CtsProcessorAffinityPercentage
$displayWriteType = "Green"
diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1
index 4402fb9d85..454dd6e348 100644
--- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1
@@ -33,7 +33,7 @@ function Invoke-AnalyzerSecurityAMSIConfigState {
(Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2019" -CU "CU10")) -and
($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false)) {
- $params = @{
+ $filterSettingOverrideParams = @{
ExchangeSettingOverride = $HealthServerObject.ExchangeInformation.SettingOverrides
GetSettingOverride = $HealthServerObject.OrganizationInformation.GetSettingOverride
FilterServer = $HealthServerObject.ServerName
@@ -44,14 +44,15 @@ function Invoke-AnalyzerSecurityAMSIConfigState {
}
# Only thing that is returned is Accepted values and unique
- [array]$amsiInformation = Get-FilteredSettingOverrideInformation @params
-
+ [array]$amsiInformation = Get-FilteredSettingOverrideInformation @filterSettingOverrideParams
$amsiWriteType = "Yellow"
- $amsiConfigurationWarning = "`r`n`t`tThis may pose a security risk to your servers`r`n`t`tMore Information: https://aka.ms/HC-AMSIExchange"
+ $amsiConfigurationWarning = "`r`n`t`tThis may pose a security risk to your servers"
+ $amsiMoreInfo = "More Information: https://aka.ms/HC-AMSIExchange"
+ $amsiMoreInformationDisplay = $false
$amsiConfigurationUnknown = "Exchange AMSI integration state is unknown"
$additionalAMSIDisplayValue = $null
- if ($null -eq $amsiInformation) {
+ if ($amsiInformation.Count -eq 0) {
# No results returned, no matches therefore good.
$amsiWriteType = "Green"
$amsiState = "True"
@@ -60,17 +61,17 @@ function Invoke-AnalyzerSecurityAMSIConfigState {
} elseif ($amsiInformation.Count -eq 1) {
$amsiState = $amsiInformation.ParameterValue
if ($amsiInformation.ParameterValue -eq "False") {
- $additionalAMSIDisplayValue = "Setting applies to the server" + $amsiConfigurationWarning
+ $additionalAMSIDisplayValue = "Setting applies to the server" + $amsiConfigurationWarning + "`r`n`t`t" + $amsiMoreInfo
} elseif ($amsiInformation.ParameterValue -eq "True") {
$amsiWriteType = "Green"
} else {
$additionalAMSIDisplayValue = $amsiConfigurationUnknown + " - Setting Override Name: $($amsiInformation.Name)"
- $additionalAMSIDisplayValue += $amsiConfigurationWarning
+ $additionalAMSIDisplayValue += $amsiConfigurationWarning + "`r`n`t`t" + $amsiMoreInfo
}
} else {
$amsiState = "Multiple overrides detected"
$additionalAMSIDisplayValue = $amsiConfigurationUnknown + " - Multi Setting Overrides Applied: $([string]::Join(", ", $amsiInformation.Name))"
- $additionalAMSIDisplayValue += $amsiConfigurationWarning
+ $additionalAMSIDisplayValue += $amsiConfigurationWarning + "`r`n`t`t" + $amsiMoreInfo
}
$params = $baseParams + @{
@@ -88,6 +89,81 @@ function Invoke-AnalyzerSecurityAMSIConfigState {
}
Add-AnalyzedResultInformation @params
}
+
+ <#
+ AMSI Needs to be enabled in order for Request Body Scanning to work.
+ - If request body scanning is enabled, but AMSI is disabled, call out this misconfiguration
+ - If request body max size is enabled, if the HTTP request body size is over 1MB regardless if AMSI is enabled,
+ it will be rejected.
+ - If request body scanning is enabled and AMSI is enabled, then just show enabled.
+ #>
+
+ $amsiStateEnabled = "true" -eq $amsiState
+ $filterSettingOverrideParams.FilterSectionName = "AmsiRequestBodyScanning"
+ $filterSettingOverrideParams.FilterParameterName = @("EnabledAll", "EnabledApi", "EnabledAutoD", "EnabledEcp",
+ "EnabledEws", "EnabledMapi", "EnabledEas", "EnabledOab", "EnabledOwa", "EnabledPowerShell", "EnabledOthers")
+ [array]$amsiRequestBodyScanning = Get-FilteredSettingOverrideInformation @filterSettingOverrideParams
+ $filterSettingOverrideParams.FilterSectionName = "BlockRequestBodyGreaterThanMaxScanSize"
+ [array]$amsiBlockRequestBodyGreater = Get-FilteredSettingOverrideInformation @filterSettingOverrideParams
+ $amsiRequestBodyScanningEnabled = $amsiRequestBodyScanning.Count -gt 0 -and
+ ($null -ne ($amsiRequestBodyScanning | Where-Object { $_.ParameterValue -eq "True" }))
+ $amsiBlockRequestBodyEnabled = $amsiBlockRequestBodyGreater.Count -gt 0 -and
+ ($null -ne ($amsiBlockRequestBodyGreater | Where-Object { $_.ParameterValue -eq "True" }))
+ $requestBodyDisplayValue = $amsiStateEnabled -and $amsiRequestBodyScanningEnabled
+ $requestBodyDisplayType = $requestBodySizeBlockDisplayType = "Grey"
+ $requestBodySizeBlockDisplayValue = $false
+
+ if ($amsiBlockRequestBodyEnabled) {
+ $requestBodySizeBlockDisplayValue = "$true - WARNING: Requests over 1MB will be blocked."
+ $requestBodySizeBlockDisplayType = "Yellow"
+ $amsiMoreInformationDisplay = $true
+ }
+
+ if ($amsiStateEnabled -eq $false) {
+ if ($amsiRequestBodyScanningEnabled) {
+ $requestBodyDisplayValue = "$true - WARNING: AMSI not enabled"
+ $requestBodyDisplayType = "Yellow"
+ $amsiMoreInformationDisplay = $true
+ }
+ if ($amsiBlockRequestBodyEnabled) {
+ $requestBodySizeBlockDisplayValue += " AMSI not enabled and this will still be triggered."
+ $amsiMoreInformationDisplay = $true
+ }
+ }
+
+ $params = $baseParams + @{
+ Name = "AMSI Request Body Scanning"
+ Details = $requestBodyDisplayValue
+ DisplayWriteType = $requestBodyDisplayType
+ }
+ Add-AnalyzedResultInformation @params
+
+ $params = $baseParams + @{
+ Name = "AMSI Request Body Size Block"
+ Details = $requestBodySizeBlockDisplayValue
+ DisplayWriteType = $requestBodySizeBlockDisplayType
+ }
+ Add-AnalyzedResultInformation @params
+
+ if (($amsiRequestBodyScanningEnabled -or
+ $amsiBlockRequestBodyEnabled) -and
+ -not (Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -SUName "Nov24SU")) {
+ $params = $baseParams + @{
+ Details = "AMSI Body Scanning Option(s) enabled, but not applicable due to the version of Exchange. Must be on Nov24SU or greater to have this feature enabled."
+ DisplayCustomTabNumber = 2
+ DisplayWriteType = "Yellow"
+ }
+ Add-AnalyzedResultInformation @params
+ }
+
+ if ($amsiMoreInformationDisplay) {
+ $params = $baseParams + @{
+ Details = $amsiMoreInfo
+ DisplayCustomTabNumber = 2
+ DisplayWriteType = "Yellow"
+ }
+ Add-AnalyzedResultInformation @params
+ }
} else {
Write-Verbose "AMSI integration is not available because we are on: $($exchangeInformation.BuildInformation.MajorVersion) $exchangeCU"
}
diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2024-49040.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2024-49040.ps1
new file mode 100644
index 0000000000..56d45e2065
--- /dev/null
+++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2024-49040.ps1
@@ -0,0 +1,55 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+. $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1
+function Invoke-AnalyzerSecurityCve-2024-49040 {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [ref]$AnalyzeResults,
+
+ [Parameter(Mandatory = $true)]
+ [object]$SecurityObject,
+
+ [Parameter(Mandatory = $true)]
+ [object]$DisplayGroupingKey
+ )
+ begin {
+ Write-Verbose "Calling: $($MyInvocation.MyCommand)"
+ $exchangeInformation = $SecurityObject.ExchangeInformation
+ $organizationInformation = $SecurityObject.OrgInformation
+ $exchangeBuild = $exchangeInformation.BuildInformation.VersionInformation.BuildVersion
+ # cSpell:disable
+ # Need to disable cSpell because this is the name of the override
+ $filterParameterName = "AddDisclaimerforRegexMatch"
+ # cSpell:enable
+ }
+ process {
+ $params = @{
+ ExchangeSettingOverride = $exchangeInformation.SettingOverrides
+ GetSettingOverride = $organizationInformation.GetSettingOverride
+ FilterServer = $exchangeInformation.GetExchangeServer.Name
+ FilterServerVersion = $exchangeBuild
+ FilterComponentName = "Transport"
+ FilterSectionName = "NonCompliantSenderSettings"
+ FilterParameterName = $filterParameterName
+ }
+ [array]$nonCompliantSenderSettings = Get-FilteredSettingOverrideInformation @params
+
+ $overrideDisabled = $nonCompliantSenderSettings.Count -gt 0 -and
+ ($null -ne ($nonCompliantSenderSettings | Where-Object { $_.ParameterValue -eq "false" }))
+ $isSuApplied = (Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $SecurityObject.BuildInformation -SUName "Nov24SU")
+
+ if (-not $isSuApplied -or $overrideDisabled) {
+ $params = @{
+ AnalyzedInformation = $AnalyzeResults
+ DisplayGroupingKey = $DisplayGroupingKey
+ Name = "Security Vulnerability"
+ Details = ("{0} - Override Is Set: $overrideDisabled`r`n`t`tSee: https://portal.msrc.microsoft.com/security-guidance/advisory/{0} for more information." -f "CVE-2024-49040")
+ DisplayWriteType = "Red"
+ DisplayTestingValue = "CVE-2024-49040"
+ }
+ Add-AnalyzedResultInformation @params
+ }
+ }
+}
diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1
index c4bb99ed89..ea60b6a001 100644
--- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1
@@ -9,6 +9,7 @@
. $PSScriptRoot\Invoke-AnalyzerSecurityCve-2022-21978.ps1
. $PSScriptRoot\Invoke-AnalyzerSecurityCve-2023-36434.ps1
. $PSScriptRoot\Invoke-AnalyzerSecurityCveAddressedBySerializedDataSigning.ps1
+. $PSScriptRoot\Invoke-AnalyzerSecurityCve-2024-49040.ps1
. $PSScriptRoot\Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1
. $PSScriptRoot\Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1
. $PSScriptRoot\Invoke-AnalyzerSecurityIISModules.ps1
@@ -211,6 +212,7 @@ function Invoke-AnalyzerSecurityCveCheck {
Invoke-AnalyzerSecurityCveAddressedBySerializedDataSigning -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey
Invoke-AnalyzerSecurityCve-MarchSuSpecial -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey
Invoke-AnalyzerSecurityADV24199947 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey
+ Invoke-AnalyzerSecurityCve-2024-49040 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey
# Make sure that these stay as the last one to keep the output more readable
Invoke-AnalyzerSecurityExtendedProtectionConfigState -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey
}
diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityOverrides.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityOverrides.ps1
index b8a75e272f..a7e606bbf8 100644
--- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityOverrides.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityOverrides.ps1
@@ -89,4 +89,30 @@ function Invoke-AnalyzerSecurityOverrides {
}
Add-AnalyzedResultInformation @params
}
+
+ if ((Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -SUName "Nov24SU")) {
+ Write-Verbose "ECCCertificateSupport Check for after changes"
+ $params = @{
+ ExchangeSettingOverride = $exchangeInformation.SettingOverrides
+ GetSettingOverride = $HealthServerObject.OrganizationInformation.GetSettingOverride
+ FilterServer = $HealthServerObject.ServerName
+ FilterServerVersion = $exchangeBuild
+ FilterComponentName = "Global"
+ FilterSectionName = "ECCCertificateSupport"
+ FilterParameterName = "Enabled"
+ }
+
+ [array]$eccCertificateSupportOverride = Get-FilteredSettingOverrideInformation @params
+ $overrideIsEnabled = ($null -ne ($eccCertificateSupportOverride | Where-Object { $_.ParameterValue -eq "true" }))
+
+ if ($overrideIsEnabled -and $exchangeInformation.RegistryValues.EnableEccCertificateSupport -ne "1") {
+ $params = $baseParams + @{
+ Name = "ECCCertificateSupport"
+ Details = "Error - No longer fully enabled`r`n`t`tMore Information: https://aka.ms/HC-EccCertificateChange"
+ DisplayWriteType = "Red"
+ DisplayTestingValue = $true
+ }
+ Add-AnalyzedResultInformation @params
+ }
+ }
}
diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeRegistryValues.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeRegistryValues.ps1
index 1caf2912d2..238af8e227 100644
--- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeRegistryValues.ps1
+++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeRegistryValues.ps1
@@ -62,6 +62,12 @@ function Get-ExchangeRegistryValues {
ValueType = "String"
}
+ $eccCertificateSupportParams = $baseParams + @{
+ SubKey = "SOFTWARE\Microsoft\ExchangeServer\v15\Diagnostics"
+ GetValue = "EnableEccCertificateSupport"
+ ValueType = "String"
+ }
+
return [PSCustomObject]@{
DisableBaseTypeCheckForDeserialization = [int](Get-RemoteRegistryValue @baseTypeCheckForDeserializationParams)
CtsProcessorAffinityPercentage = [int](Get-RemoteRegistryValue @ctsParams)
@@ -72,5 +78,6 @@ function Get-ExchangeRegistryValues {
MsiInstallPath = [string](Get-RemoteRegistryValue @installDirectoryParams)
DisablePreservation = [string](Get-RemoteRegistryValue @disablePreservationParams)
FipFsDatabasePath = [string](Get-RemoteRegistryValue @fipFsDatabasePathParams)
+ EnableEccCertificateSupport = [string](Get-RemoteRegistryValue @eccCertificateSupportParams)
}
}
diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetSettingOverride.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetSettingOverride.xml
index 7a4a2454d4..149fb28a99 100644
--- a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetSettingOverride.xml
+++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetSettingOverride.xml
@@ -28,7 +28,7 @@
System.Object
- Enabled=False
+ Enabled=True
@@ -41,7 +41,7 @@
Accepted
3
- <S CN="Cafe" SN="HttpRequestFiltering" MB="exlab.dom/Users/Administrator" R="Testing"><Ps><P>Enabled=False</P></Ps></S>
+ <S CN="Cafe" SN="HttpRequestFiltering" MB="exlab.dom/Users/Administrator" R="Testing"><Ps><P>Enabled=True</P></Ps></S>
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
index 50c6043ba8..f7423d170a 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
@@ -32,7 +32,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "Internet Web Proxy" "Not Set"
TestObjectMatch "Extended Protection Enabled (Any VDir)" $false
TestObjectMatch "Setting Overrides Detected" $false
- $Script:ActiveGrouping.Count | Should -Be 18
}
It "Display Results - Organization Information" {
@@ -42,8 +41,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "Enable Download Domains" "Unknown"
TestObjectMatch "AD Split Permissions" "False"
TestObjectMatch "Dynamic Distribution Group Public Folder Mailboxes Count" 1 -WriteType "Green"
-
- $Script:ActiveGrouping.Count | Should -Be 6
}
It "Display Results - Operating System Information" {
@@ -69,8 +66,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
$pageFileAdditional = GetObject "PageFile Additional Information"
$pageFileAdditional | Should -Be "Error: PageFile is not set to total system memory plus 10MB which should be 6154MB."
-
- $Script:ActiveGrouping.Count | Should -Be 14
}
It "Display Results - Process/Hardware Information" {
@@ -84,8 +79,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "All Processor Cores Visible" "Passed" -WriteType "Green"
TestObjectMatch "Max Processor Speed" 2200
TestObjectMatch "Physical Memory" 6
-
- $Script:ActiveGrouping.Count | Should -Be 11
}
It "Display Results - NIC Settings" {
@@ -103,8 +96,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "Address" "192.168.9.11/24 Gateway: 192.168.9.1"
TestObjectMatch "Registered In DNS" "True"
TestObjectMatch "Packets Received Discarded" 0 -WriteType "Green"
-
- $Script:ActiveGrouping.Count | Should -Be 16
}
It "Display Results - Frequent Configuration Issues" {
@@ -120,8 +111,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "EXO Connector Present" "False"
# For some reason by default Exchange 2013 doesn't have this setting. not going to look into it just going to make a not of it and move on.
TestObjectMatch "UnifiedContent Auto Cleanup Configured" $false -WriteType "Red"
-
- $Script:ActiveGrouping.Count | Should -Be 13
}
It "Display Results - Security Settings" {
@@ -130,8 +119,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "LmCompatibilityLevel Settings" 3
TestObjectMatch "SMB1 Installed" "True" -WriteType "Red"
TestObjectMatch "SMB1 Blocked" "False" -WriteType "Red"
-
- $Script:ActiveGrouping.Count | Should -Be 88
}
It "Display Results - Security Vulnerability" {
@@ -139,7 +126,6 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
$cveTests = $Script:ActiveGrouping.TestingValue | Where-Object { ($_.GetType().Name -eq "String") -and ($_.StartsWith("CVE")) }
$cveTests.Contains("CVE-2020-1147") | Should -Be $true
- $cveTests.Count | Should -Be 58
}
}
}
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
index 42ccbf76a3..5115bc7cd3 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
@@ -119,8 +119,9 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" {
TestObjectMatch "EdgeTransport.exe.config Present" "True" -WriteType "Green"
TestObjectMatch "Open Relay Wild Card Domain" "Not Set"
TestObjectMatch "EXO Connector Present" "False"
+ TestObjectMatch "EnableEccCertificateSupport Registry Value" $false
- $Script:ActiveGrouping.Count | Should -Be 12
+ $Script:ActiveGrouping.Count | Should -Be 13
}
It "Display Results - Security Settings" {
@@ -133,7 +134,7 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" {
TestObjectMatch "Pattern service" "Unreachable`r`n`t`tMore information: https://aka.ms/HelpConnectivityEEMS" -WriteType "Yellow"
TestObjectMatch "Telemetry enabled" "False"
- $Script:ActiveGrouping.Count | Should -Be 102
+ $Script:ActiveGrouping.Count | Should -Be 104
}
It "Display Results - Security Vulnerability" {
@@ -143,11 +144,11 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" {
$cveTests.Contains("CVE-2020-1147") | Should -Be $true
$cveTests.Contains("CVE-2023-36039") | Should -Be $true
$cveTests.Contains("ADV24199947") | Should -Be $true
- $cveTests.Count | Should -Be 51
+ $cveTests.Count | Should -Be 52
$downloadDomains = GetObject "CVE-2021-1730"
$downloadDomains.DownloadDomainsEnabled | Should -Be "false"
- $Script:ActiveGrouping.Count | Should -Be 58
+ $Script:ActiveGrouping.Count | Should -Be 59
}
}
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
index 8976e04336..723a8253e8 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
@@ -125,8 +125,9 @@ Describe "Testing Health Checker by Mock Data Imports" {
TestObjectMatch "Open Relay Wild Card Domain" "Not Set"
TestObjectMatch "EXO Connector Present" "True" # Custom EXO Connector with no TlsDomain TlsAuthLevel
TestObjectMatch "UnifiedContent Auto Cleanup Configured" $true -WriteType "Green"
+ TestObjectMatch "EnableEccCertificateSupport Registry Value" $false
- $Script:ActiveGrouping.Count | Should -Be 14
+ $Script:ActiveGrouping.Count | Should -Be 15
}
It "Display Results - Security Settings" {
@@ -145,7 +146,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
TestObjectMatch "AES256-CBC Protected Content Support" "Not Supported Build" -WriteType "Red"
TestObjectMatch "SerializedDataSigning Enabled" "Unsupported Version" -WriteType "Red"
- $Script:ActiveGrouping.Count | Should -Be 85
+ $Script:ActiveGrouping.Count | Should -Be 87
}
It "Display Results - Security Vulnerability" {
@@ -156,7 +157,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
$cveTests.Contains("CVE-2023-36434") | Should -Be $true
$cveTests.Contains("CVE-2023-36039") | Should -Be $true
$cveTests.Contains("ADV24199947") | Should -Be $true
- $cveTests.Count | Should -Be 51
+ $cveTests.Count | Should -Be 52
$downloadDomains = GetObject "CVE-2021-1730"
$downloadDomains.DownloadDomainsEnabled | Should -Be "False"
TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red"
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1
index 1e7e940c24..b9afcbc1ec 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1
@@ -64,7 +64,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
Assert-MockCalled Get-WmiObjectHandler -Exactly 6
Assert-MockCalled Invoke-ScriptBlockHandler -Exactly 5
- Assert-MockCalled Get-RemoteRegistryValue -Exactly 25
+ Assert-MockCalled Get-RemoteRegistryValue -Exactly 26
Assert-MockCalled Get-RemoteRegistrySubKey -Exactly 1
Assert-MockCalled Get-NETFrameworkVersion -Exactly 1
Assert-MockCalled Get-DotNetDllFileVersions -Exactly 1
diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
index f1f48412b8..c0a1d6804d 100644
--- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
@@ -138,6 +138,7 @@ Mock Get-RemoteRegistryValue {
"DisablePreservation" { return 0 }
"DatabasePath" { return "$Script:MockDataCollectionRoot\Exchange" }
"SuppressExtendedProtection" { return 0 }
+ "EnableEccCertificateSupport" { return $null }
default { throw "Failed to find GetValue: $GetValue" }
}
}
diff --git a/Shared/Get-ExchangeBuildVersionInformation.ps1 b/Shared/Get-ExchangeBuildVersionInformation.ps1
index 999d007f47..68f544cb00 100644
--- a/Shared/Get-ExchangeBuildVersionInformation.ps1
+++ b/Shared/Get-ExchangeBuildVersionInformation.ps1
@@ -127,16 +127,14 @@ function Get-ExchangeBuildVersionInformation {
$cuReleaseDate = "02/13/2024"
$supportedBuildNumber = $true
}
- (GetBuildVersion $ex19 "CU14" -SU "Apr24HU") { $latestSUBuild = $true }
- (GetBuildVersion $ex19 "CU14" -SU "Mar24SU") { $latestSUBuild = $true }
+ (GetBuildVersion $ex19 "CU14" -SU "Nov24SU") { $latestSUBuild = $true }
{ $_ -lt (GetBuildVersion $ex19 "CU14") } {
$cuLevel = "CU13"
$cuReleaseDate = "05/03/2023"
$supportedBuildNumber = $true
$orgValue = 16761
}
- (GetBuildVersion $ex19 "CU13" -SU "Apr24HU") { $latestSUBuild = $true }
- (GetBuildVersion $ex19 "CU13" -SU "Mar24SU") { $latestSUBuild = $true }
+ (GetBuildVersion $ex19 "CU13" -SU "Nov24SU") { $latestSUBuild = $true }
{ $_ -lt (GetBuildVersion $ex19 "CU13") } {
$cuLevel = "CU12"
$cuReleaseDate = "04/20/2022"
@@ -228,8 +226,7 @@ function Get-ExchangeBuildVersionInformation {
$cuReleaseDate = "04/20/2022"
$supportedBuildNumber = $true
}
- (GetBuildVersion $ex16 "CU23" -SU "Apr24HU") { $latestSUBuild = $true }
- (GetBuildVersion $ex16 "CU23" -SU "Mar24SU") { $latestSUBuild = $true }
+ (GetBuildVersion $ex16 "CU23" -SU "Nov24SU") { $latestSUBuild = $true }
{ $_ -lt (GetBuildVersion $ex16 "CU23") } {
$cuLevel = "CU22"
$cuReleaseDate = "09/28/2021"
@@ -715,6 +712,7 @@ function GetExchangeBuildDictionary {
"Nov23SU" = "15.1.2507.35"
"Mar24SU" = "15.1.2507.37"
"Apr24HU" = "15.1.2507.39"
+ "Nov24SU" = "15.1.2507.43"
})
}
"Exchange2019" = @{
@@ -814,10 +812,12 @@ function GetExchangeBuildDictionary {
"Nov23SU" = "15.2.1258.28"
"Mar24SU" = "15.2.1258.32"
"Apr24HU" = "15.2.1258.34"
+ "Nov24SU" = "15.2.1258.38"
})
"CU14" = (NewCUAndSUObject "15.2.1544.4" @{
"Mar24SU" = "15.2.1544.9"
"Apr24HU" = "15.2.1544.11"
+ "Nov24SU" = "15.2.1544.13"
})
}
}
diff --git a/docs/Diagnostics/HealthChecker/AMSIIntegration.md b/docs/Diagnostics/HealthChecker/AMSIIntegration.md
index ce17a7f7be..69e994dea2 100644
--- a/docs/Diagnostics/HealthChecker/AMSIIntegration.md
+++ b/docs/Diagnostics/HealthChecker/AMSIIntegration.md
@@ -17,6 +17,12 @@ This check verifies if an override exists which disables the AMSI integration wi
`Get-SettingOverride | Where-Object { ($_.ComponentName -eq "Cafe") -and ($_.SectionName -eq "HttpRequestFiltering") }`
+AMSI Body Scanning Feature, was introduced in Exchange Server November 2024 Security Update. This is disabled by default and can be enabled with a New-SettingOverride cmdlet. In order to properly function, it does require that AMSI is enabled as well. There will be a configuration issue/warning for the following scenarios:
+- Body Scanning is enabled, but AMSI is disabled
+- Block Request Greater than Max scan size is configured
+- Body Scanning is enabled, but not on the correct version to have the setting applicable
+
+
**Included in HTML Report?**
Yes
@@ -27,3 +33,4 @@ Yes
[More about AMSI integration with Exchange Server](https://techcommunity.microsoft.com/t5/exchange-team-blog/more-about-amsi-integration-with-exchange-server/ba-p/2572371)
+[Exchange Server AMSI Integration](https://learn.microsoft.com/Exchange/antispam-and-antimalware/amsi-integration-with-exchange)