diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
index c0045e99c1..eb3af3147d 100644
--- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
+++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1
@@ -348,4 +348,48 @@ function Invoke-AnalyzerFrequentConfigurationIssues {
}
Add-AnalyzedResultInformation @params
}
+
+ $edgeKey = $exchangeInformation.ApplicationConfigFileStatus.Keys | Where-Object { $_ -like "*\EdgeTransport.exe.config" }
+ $antiMalwareKey = $exchangeInformation.FileContentInformation.Keys | Where-Object { $_ -like "*\Monitoring\Config\AntiMalware.xml" }
+
+ if ($null -ne $edgeKey -and
+ $null -ne $antiMalwareKey -and
+ $exchangeInformation.ApplicationConfigFileStatus[$edgeKey].Present -and
+ $exchangeInformation.FileContentInformation[$antiMalwareKey].Present) {
+ $params = $baseParams + @{
+ Name = "UnifiedContent Auto Cleanup Configured"
+ Details = "Unknown"
+ DisplayWriteType = "Red"
+ }
+ try {
+ $temporaryStoragePath = (([xml]$exchangeInformation.ApplicationConfigFileStatus[$edgeKey].Content).configuration.appSettings.add |
+ Where-Object { $_.key -eq "TemporaryStoragePath" }).value
+ $edgeKeySuccessful = $true
+ $cleanupFolderResponderFolderPaths = (([xml]$exchangeInformation.FileContentInformation[$antiMalwareKey].Content).Definition.MaintenanceDefinition.ExtensionAttributes.CleanupFolderResponderFolderPaths)
+ $cleanupPathsExists = $cleanupFolderResponderFolderPaths -like "*$temporaryStoragePath\UnifiedContent*"
+
+ if ($cleanupPathsExists) {
+ $params.DisplayWriteType = "Green"
+ }
+
+ $params.Details = $cleanupPathsExists
+ Add-AnalyzedResultInformation @params
+
+ if ($cleanupPathsExists -eq $false) {
+ $params = $baseParams + @{
+ Details = "More Information: https://aka.ms/HC-UnifiedContentCleanup"
+ DisplayWriteType = "Yellow"
+ DisplayCustomTabNumber = 2
+ }
+ Add-AnalyzedResultInformation @params
+ }
+ } catch {
+ if ($edgeKeySuccessful) {
+ $params.Details = "AntiMalware.xml Invalid Config Format"
+ } else {
+ $params.Details = "Error - EdgeTransport.exe.config Invalid Config Format"
+ }
+ Add-AnalyzedResultInformation @params
+ }
+ }
}
diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1
index 802f254bda..b510737207 100644
--- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1
+++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1
@@ -115,7 +115,8 @@ function Get-ExchangeInformation {
$configParams = @{
ComputerName = $Server
FileLocation = @("$([System.IO.Path]::Combine($serverExchangeBinDirectory, "EdgeTransport.exe.config"))",
- "$([System.IO.Path]::Combine($serverExchangeBinDirectory, "Search\Ceres\Runtime\1.0\noderunner.exe.config"))")
+ "$([System.IO.Path]::Combine($serverExchangeBinDirectory, "Search\Ceres\Runtime\1.0\noderunner.exe.config"))",
+ "$([System.IO.Path]::Combine($serverExchangeBinDirectory, "Monitoring\Config\AntiMalware.xml"))")
}
if ($getExchangeServer.IsEdgeServer -eq $false -and
@@ -203,7 +204,7 @@ function Get-ExchangeInformation {
CatchActionFunction = ${Function:Invoke-CatchActions}
ScriptBlock = {
[PSCustomObject]@{
- LocalGroupMember = (Get-LocalGroupMember -SID "S-1-5-32-544" -ErrorAction Stop)
+ LocalGroupMember = (Get-LocalGroupMember -SID "S-1-5-32-544" -ErrorAction Stop)
ADGroupMembership = (Get-ADPrincipalGroupMembership (Get-ADComputer $env:COMPUTERNAME).DistinguishedName)
}
}
diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/Antimalware.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/Antimalware.xml
new file mode 100644
index 0000000000..30e5a30bfb
--- /dev/null
+++ b/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/Antimalware.xml
@@ -0,0 +1,938 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/Antimalware.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/Antimalware.xml
new file mode 100644
index 0000000000..1d317cdca8
--- /dev/null
+++ b/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/Antimalware.xml
@@ -0,0 +1,839 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware.xml
new file mode 100644
index 0000000000..1d317cdca8
--- /dev/null
+++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware.xml
@@ -0,0 +1,839 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware1.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware1.xml
new file mode 100644
index 0000000000..9f1c192029
--- /dev/null
+++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/Antimalware1.xml
@@ -0,0 +1,839 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
index 65cea5fe84..773c257bb4 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1
@@ -118,8 +118,10 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" {
TestObjectMatch "EdgeTransport.exe.config Present" "True" -WriteType "Green"
TestObjectMatch "Open Relay Wild Card Domain" "Not Set"
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 11
+ $Script:ActiveGrouping.Count | Should -Be 13
}
It "Display Results - Security Settings" {
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
index af9567a0f5..7671d4231f 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1
@@ -120,7 +120,7 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" {
TestObjectMatch "Open Relay Wild Card Domain" "Not Set"
TestObjectMatch "EXO Connector Present" "False"
- $Script:ActiveGrouping.Count | Should -Be 11
+ $Script:ActiveGrouping.Count | Should -Be 12
}
It "Display Results - Security Settings" {
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
index 286a394c8d..6d0f18c372 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1
@@ -121,8 +121,9 @@ Describe "Testing Health Checker by Mock Data Imports" {
TestObjectMatch "NodeRunner.exe memory limit" "0 MB" -WriteType "Green"
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"
- $Script:ActiveGrouping.Count | Should -Be 13
+ $Script:ActiveGrouping.Count | Should -Be 14
}
It "Display Results - Security Settings" {
diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1
index d59130c0e1..68a194c346 100644
--- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1
@@ -318,6 +318,10 @@ Describe "Testing Health Checker by Mock Data Imports" {
TestObjectMatch "EdgeTransport.exe.config Invalid Config Format" $true -WriteType "Red"
}
+ It "EdgeTransport.exe.config invalid config for UnifiedContent" {
+ TestObjectMatch "UnifiedContent Auto Cleanup Configured" "Error - EdgeTransport.exe.config Invalid Config Format" -WriteType "Red"
+ }
+
It "TLS Settings" {
SetActiveDisplayGrouping "Security Settings"
TestObjectMatch "TLS 1.0" "Misconfigured" -WriteType "Red"
@@ -369,6 +373,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
-MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Hardware\Physical_Win32_Processor1.xml" }
Mock Get-ExSetupFileVersionInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\ExSetup1.xml" }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw -Encoding UTF8 }
+ Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Monitoring\Config\AntiMalware.xml" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\AntiMalware1.xml" -Raw -Encoding UTF8 }
SetDefaultRunOfHealthChecker "Debug_Scenario3_Physical_Results.xml"
}
@@ -408,6 +413,11 @@ Describe "Testing Health Checker by Mock Data Imports" {
TestObjectMatch "HighPerformanceSet" $false -WriteType "Red"
}
+ It "UnifiedContent Auto Update" {
+ SetActiveDisplayGrouping "Frequent Configuration Issues"
+ TestObjectMatch "UnifiedContent Auto Cleanup Configured" $false -WriteType "Red"
+ }
+
It "Extended Protection" {
SetActiveDisplayGrouping "Security Vulnerability"
TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red"
diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
index 2c61effa31..2b7bf49d4f 100644
--- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
+++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1
@@ -59,11 +59,13 @@ Mock Test-Path -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange
Mock Test-Path -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\SharedWebConfig.config" } -MockWith { return $true }
Mock Test-Path -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\EdgeTransport.exe.config" } -MockWith { return $true }
Mock Test-Path -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Runtime\1.0\noderunner.exe.config" } -MockWith { return $true }
+Mock Test-Path -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Monitoring\Config\AntiMalware.xml" } -MockWith { return $true }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\SharedWebConfig.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\DefaultWebSite_SharedWebConfig.config" -Raw -Encoding UTF8 }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\SharedWebConfig.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\ExchangeBackEnd_SharedWebConfig.config" -Raw -Encoding UTF8 }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\EdgeTransport.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\EdgeTransport.exe.config" -Raw -Encoding UTF8 }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Runtime\1.0\noderunner.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\noderunner.exe.config" -Raw -Encoding UTF8 }
+Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Monitoring\Config\AntiMalware.xml" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\AntiMalware.xml" -Raw -Encoding UTF8 }
function Get-WebApplication { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetWebApplication.xml" }
diff --git a/docs/Diagnostics/HealthChecker/UnifiedContentCleanup.md b/docs/Diagnostics/HealthChecker/UnifiedContentCleanup.md
new file mode 100644
index 0000000000..d6a2b5e8cc
--- /dev/null
+++ b/docs/Diagnostics/HealthChecker/UnifiedContentCleanup.md
@@ -0,0 +1,13 @@
+# UnifiedContent Automatic Cleanup
+
+Within Exchange Monitoring, we have a probe that will attempt to clear out the old temp data that is generated from EdgeTransport.exe process. However, this probe definition is defined in the `%ExchangeInstallPath%\Bin\Monitoring\Config\AntiMalware.xml` with a hardcoded path options to look. By default, we are only looking at `"D:\ExchangeTemp\TransportCts\UnifiedContent;C:\Windows\Temp\UnifiedContent;C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\data\Temp\UnifiedContent"`. Therefore, if Exchange is not installed in at `C:\Program Files\Microsoft\Exchange Server\V15\` or if the `TemporaryStoragePath` of the `EdgeTransport.exe.config` value is anything other than `C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\data\Temp` the probe will not work as intended to clean up the data files.
+
+The only way to get the probe to automatically clean up the temp files is to add the correct location to the `%ExchangeInstallPath%\Bin\Monitoring\Config\AntiMalware.xml` file.
+
+**Included in HTML Report?**
+
+Yes
+
+**Additional resources:**
+
+[Exchange UnifiedContent folder fills up the drive](https://learn.microsoft.com/en-us/exchange/troubleshoot/administration/unifiedcontent-folder-fills-up-drive)
diff --git a/mkdocs.yml b/mkdocs.yml
index dce6bec2f2..955fc0e0e0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -70,6 +70,7 @@ nav:
- HCScheduledTask: Diagnostics/HealthChecker/RunHCViaSchedTask.md
- ADSiteCount: Diagnostics/HealthChecker/ADSiteCount.md
- ExchangeComputerMembership: Diagnostics/HealthChecker/ExchangeComputerMembership.md
+ - UnifiedContentCleanup: Diagnostics/HealthChecker/UnifiedContentCleanup.md
- ManagedAvailabilityTroubleshooter: Diagnostics/ManagedAvailabilityTroubleshooter.md
- Test-ExchAVExclusions: Diagnostics/Test-ExchAVExclusions.md
- Hybrid: