From 5498c8db3495b3c81a7f46c0c0ced0fd18510cce Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Thu, 28 Sep 2023 15:28:45 -0700 Subject: [PATCH 01/30] Remove old columns, add ExternalSharingMasterId --- .../Get-CalendarDiagnosticObjectsSummary.ps1 | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index 4a91acb644..e759b6f0d6 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -370,7 +370,6 @@ function BuildCSV { 'CleanGlobalObjectId' = $CalLog.CleanGlobalObjectId 'MapiStartTime' = $CalLog.MapiStartTime 'MapiEndTime' = $CalLog.MapiEndTime - 'NormalizedSubject' = $CalLog.NormalizedSubject 'AppointmentRecurring' = $CalLog.AppointmentRecurring 'HasAttachment' = $CalLog.HasAttachment 'IsCancelled' = $CalLog.IsCancelled @@ -381,9 +380,7 @@ function BuildCSV { 'IsException' = $CalLog.IsException 'IsOrganizerProperty' = $CalLog.IsOrganizerProperty 'EventEmailReminderTimer' = $CalLog.EventEmailReminderTimer - 'EstimatedAcceptCount' = $CalLog.EstimatedAcceptCount - 'EstimatedTentativeCount' = $CalLog.EstimatedTentativeCount - 'EstimatedDeclineCount' = $CalLog.EstimatedDeclineCount + 'ExternalSharingMasterId' = $CalLog.ExternalSharingMasterId 'OnlineMeetingConfLink' = $CalLog.OnlineMeetingConfLink 'OnlineMeetingExternalLink' = $CalLog.OnlineMeetingExternalLink 'OnlineMeetingInternalLink' = $CalLog.OnlineMeetingInternalLink @@ -570,21 +567,6 @@ function BuildTimeline { MeetingSummary -Time " " -MeetingChanges $TimeLineText } - if ($CalLog.EstimatedAcceptCount -ne $PreviousCalLog.EstimatedAcceptCount) { - [Array]$TimeLineText = "The Estimated Accept Count changed from [$($PreviousCalLog.EstimatedAcceptCount)] to: [$($CalLog.EstimatedAcceptCount)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.EstimatedTentativeCount -ne $PreviousCalLog.EstimatedTentativeCount) { - [Array]$TimeLineText = "The Estimated Tentative Count changed from [$($PreviousCalLog.EstimatedTentativeCount)] to: [$($CalLog.EstimatedTentativeCount)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.EstimatedDeclineCount -ne $PreviousCalLog.EstimatedDeclineCount) { - [Array]$TimeLineText = "The Estimated Declined Count changed from [$($PreviousCalLog.EstimatedDeclineCount)] to: [$($CalLog.EstimatedDeclineCount)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - if ($CalLog.OnlineMeetingConfLink -ne $PreviousCalLog.OnlineMeetingConfLink) { [Array]$TimeLineText = "The Online Meeting Conference Link changed from [$($PreviousCalLog.OnlineMeetingConfLink)] to: [$($CalLog.OnlineMeetingConfLink)]" MeetingSummary -Time " " -MeetingChanges $TimeLineText From bb2111e10244925bf7cd14804b8d7847e9c2d633 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 4 Oct 2023 20:00:01 -0700 Subject: [PATCH 02/30] Improve AutomateProcessing Error --- Calendar/Get-RBASummary.ps1 | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Calendar/Get-RBASummary.ps1 b/Calendar/Get-RBASummary.ps1 index 2e7f8b6ecc..e2dbc387c0 100644 --- a/Calendar/Get-RBASummary.ps1 +++ b/Calendar/Get-RBASummary.ps1 @@ -48,7 +48,7 @@ function ValidateMailbox { if ($script:Mailbox.ResourceType -eq "Workspace") { $script:Workspace = $true; } - Write-Host -ForegroundColor Green "The mailbox is valid for RBA will work with."; + Write-Host -ForegroundColor Green "The mailbox is valid for RBA will work with." } # Get-Place does not cross forest boundaries so we will get an error here if we are not in the right forest. @@ -57,17 +57,16 @@ function ValidateMailbox { if ($null -eq $script:Place) { Write-Error "Error: Get-Place returned Null for $Identity." - Write-Host -ForegroundColor Red "Make sure you are running from the Correct forest. Get-Place does not cross forest boundaries." + Write-Host -ForegroundColor Red "Make sure you are running from the correct forest. Get-Place does not cross forest boundaries." Write-Error "Exiting Script." - exit + exit; } Write-Host -ForegroundColor Yellow "For more information see https://learn.microsoft.com/en-us/powershell/module/exchange/get-mailbox?view=exchange-ps"; - Write-Host ; + Write-Host; } # Validate that there are not delegate rules that will block RBA functionality -#TODO this fails if you do not have PII access to the mailbox function ValidateInboxRules { Write-Host "Checking for Delegate Rules that will block RBA functionality..." Write-Host -NoNewline "Running : "; Write-Host -ForegroundColor Cyan "Get-InboxRule -mailbox $Identity -IncludeHidden" @@ -80,7 +79,7 @@ function ValidateInboxRules { Write-Host -ForegroundColor Red "Exiting script." exit; } - if ($rules.Name -like "REDACTED-*") { + elseif ($rules.Name -like "REDACTED-*") { Write-Host -ForegroundColor Yellow "Warning: No PII Access to MB so cannot check for Delegate Rules." Write-Host -ForegroundColor Red " --- Inbox Rules needs to be checked manually for any Delegate Rules. --" Write-Host -ForegroundColor Yellow "To gain PII access, Mailbox is located on $($mailbox.Database) on server $($mailbox.ServerName)" @@ -91,6 +90,8 @@ function ValidateInboxRules { Write-Host -ForegroundColor Yellow "Warning: Multiple rules have been found on this resource mailbox. Only the Default Junk Mail rule is expected. Depending on the rules setup, this may block RBA functionality." Write-Host -ForegroundColor Yellow "Warning: Please remove the rule(s) via Remove-InboxRule cmdlet and re-run this script." } + } + else { Write-Host -ForegroundColor Green "Delegate Rules check passes." } } @@ -109,21 +110,22 @@ function GetCalendarProcessing { exit; } - Write-Host -ForegroundColor Yellow "For more information see - https://learn.microsoft.com/en-us/powershell/module/exchange/set-calendarprocessing?view=exchange-ps"; - Write-Host ; - $RbaSettings | Format-List + + Write-Host -ForegroundColor Yellow "For more information on Set-CalendarProcessing see + https://learn.microsoft.com/en-us/powershell/module/exchange/set-calendarprocessing?view=exchange-ps"; + Write-Host; } function EvaluateCalProcessing { if ($RbaSettings.AutomateProcessing -ne "AutoAccept") { - Write-Host -ForegroundColor Red "AutomateProcessing is not set to AutoAccept. RBA will not work as configured. " - Write-Host -ForegroundColor Red "AutomateProcessing is set to"$RbaSettings.AutomateProcessing + Write-Host -ForegroundColor Red "Error: AutomateProcessing is not set to AutoAccept. RBA will not work as configured." + Write-Host -ForegroundColor Red "Error: For RBA to do anything AutomateProcessing must be set to AutoAccept." + Write-Host -ForegroundColor Red "Error: AutomateProcessing is set to $($RbaSettings.AutomateProcessing)." Write-Host -ForegroundColor Yellow "Use 'Set-CalendarProcessing -Identity $Identity -AutomateProcessing AutoAccept' to set AutomateProcessing to AutoAccept." Write-Host -ForegroundColor Red "Exiting script." - exit + exit; } else { Write-Host -ForegroundColor Green "AutomateProcessing is set to AutoAccept. RBA will analyze the meeting request." } @@ -662,9 +664,9 @@ function Write-DashLineBoxColor { ValidateMailbox ValidateInboxRules GetCalendarProcessing +EvaluateCalProcessing ValidateWorkspace ValidateRoomListSettings -EvaluateCalProcessing ProcessingLogic RBACriteria RBAProcessingValidation From 28a778b6093cf95387f048b3a5b6b3012e34b8fc Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Wed, 4 Oct 2023 20:02:59 -0700 Subject: [PATCH 03/30] fix space --- Calendar/Get-RBASummary.ps1 | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Calendar/Get-RBASummary.ps1 b/Calendar/Get-RBASummary.ps1 index e2dbc387c0..fdbfcfbfb4 100644 --- a/Calendar/Get-RBASummary.ps1 +++ b/Calendar/Get-RBASummary.ps1 @@ -78,8 +78,7 @@ function ValidateInboxRules { Write-Host -ForegroundColor Red "$($rules.Name -like "Delegate Rule*")" Write-Host -ForegroundColor Red "Exiting script." exit; - } - elseif ($rules.Name -like "REDACTED-*") { + } elseif ($rules.Name -like "REDACTED-*") { Write-Host -ForegroundColor Yellow "Warning: No PII Access to MB so cannot check for Delegate Rules." Write-Host -ForegroundColor Red " --- Inbox Rules needs to be checked manually for any Delegate Rules. --" Write-Host -ForegroundColor Yellow "To gain PII access, Mailbox is located on $($mailbox.Database) on server $($mailbox.ServerName)" @@ -90,8 +89,7 @@ function ValidateInboxRules { Write-Host -ForegroundColor Yellow "Warning: Multiple rules have been found on this resource mailbox. Only the Default Junk Mail rule is expected. Depending on the rules setup, this may block RBA functionality." Write-Host -ForegroundColor Yellow "Warning: Please remove the rule(s) via Remove-InboxRule cmdlet and re-run this script." } - } - else { + } else { Write-Host -ForegroundColor Green "Delegate Rules check passes." } } @@ -111,7 +109,7 @@ function GetCalendarProcessing { } $RbaSettings | Format-List - + Write-Host -ForegroundColor Yellow "For more information on Set-CalendarProcessing see https://learn.microsoft.com/en-us/powershell/module/exchange/set-calendarprocessing?view=exchange-ps"; Write-Host; From 34211d0b8e24620d6641a3c466d53ec3edc68f9d Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Fri, 6 Oct 2023 17:06:01 +0200 Subject: [PATCH 04/30] Improve detection of Server Core --- .../Get-OperatingSystemBuildInformation.ps1 | 10 +++-- .../Get-ServerOperatingSystemVersion.ps1 | 44 ++++++++++++++----- .../RemoteRegistryValueInstallationType.xml | 3 ++ .../E15/OS/RemoteRegistryValueProductName.xml | 3 ++ .../RemoteRegistryValueInstallationType.xml | 3 ++ .../E16/OS/RemoteRegistryValueProductName.xml | 3 ++ .../RemoteRegistryValueInstallationType.xml | 3 ++ .../E19/OS/RemoteRegistryValueProductName.xml | 3 ++ .../Tests/HealthChecker.E15.Main.Tests.ps1 | 2 +- .../Tests/HealthChecker.E16.Main.Tests.ps1 | 2 +- .../Tests/HealthChecker.E19.Main.Tests.ps1 | 2 +- .../Tests/HealthChecker.MockedCalls.Tests.ps1 | 2 +- ...thCheckerTest.CommonMocks.NotPublished.ps1 | 2 + 13 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueInstallationType.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueProductName.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueInstallationType.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueProductName.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueInstallationType.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueProductName.xml diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 index 79c5d6f773..88b015e43f 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 @@ -14,12 +14,14 @@ function Get-OperatingSystemBuildInformation { process { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $win32_OperatingSystem = Get-WmiObjectCriticalHandler -ComputerName $Server -Class Win32_OperatingSystem -CatchActionFunction ${Function:Invoke-CatchActions} + $serverOsVersionInformation = Get-ServerOperatingSystemVersion -ComputerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} } end { return [PSCustomObject]@{ - BuildVersion = [System.Version]$win32_OperatingSystem.Version - MajorVersion = (Get-ServerOperatingSystemVersion -OsCaption $win32_OperatingSystem.Caption) - FriendlyName = $win32_OperatingSystem.Caption - OperatingSystem = $win32_OperatingSystem + BuildVersion = [System.Version]$win32_OperatingSystem.Version + MajorVersion = $serverOsVersionInformation.MajorVersion + InstallationType = $serverOsVersionInformation.InstallationType + FriendlyName = $serverOsVersionInformation.FriendlyName + OperatingSystem = $win32_OperatingSystem } } } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 index a368df295d..c69176ddff 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 @@ -1,25 +1,43 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -. $PSScriptRoot\..\..\..\..\Shared\Get-WmiObjectHandler.ps1 +. $PSScriptRoot\..\..\..\..\Shared\Get-RemoteRegistryValue.ps1 function Get-ServerOperatingSystemVersion { [CmdletBinding()] - [OutputType("System.String")] + [OutputType("System.Object")] param( - [string]$OsCaption + [string]$ComputerName = $env:COMPUTERNAME, + + [ScriptBlock]$CatchActionFunction ) begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $osReturnValue = [string]::Empty } process { - if ([string]::IsNullOrEmpty($OsCaption)) { - Write-Verbose "Getting the local machine version build number" - $OsCaption = (Get-WmiObjectHandler -Class "Win32_OperatingSystem").Caption + Write-Verbose "Getting the version build information for computer: $ComputerName" + $baseParams = @{ + MachineName = $ComputerName + CatchActionFunction = $CatchActionFunction + } + + # Get ProductName via registry call as this is more accurate when running on Server Core + $productNameParams = $baseParams + @{ + SubKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" + GetValue = "ProductName" } - Write-Verbose "OsCaption: '$OsCaption'" - switch -Wildcard ($OsCaption) { + # Find out if we're running on Server Core to output on the 'Operating System Information' page + $installationTypeParams = $baseParams + @{ + SubKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" + GetValue = "InstallationType" + } + + $osCaption = Get-RemoteRegistryValue @productNameParams + $installationType = Get-RemoteRegistryValue @installationTypeParams + Write-Verbose "OsCaption: '$osCaption' InstallationType: '$installationType'" + + switch -Wildcard ($osCaption) { "*Server 2008 R2*" { $osReturnValue = "Windows2008R2"; break } "*Server 2008*" { $osReturnValue = "Windows2008" } "*Server 2012 R2*" { $osReturnValue = "Windows2012R2"; break } @@ -27,13 +45,15 @@ function Get-ServerOperatingSystemVersion { "*Server 2016*" { $osReturnValue = "Windows2016" } "*Server 2019*" { $osReturnValue = "Windows2019" } "*Server 2022*" { $osReturnValue = "Windows2022" } - "Microsoft Windows Server Standard" { $osReturnValue = "WindowsCore" } - "Microsoft Windows Server Datacenter" { $osReturnValue = "WindowsCore" } default { $osReturnValue = "Unknown" } } } end { - Write-Verbose "Returned: '$osReturnValue'" - return [string]$osReturnValue + Write-Verbose "OsReturnValue: '$osReturnValue'" + return [PSCustomObject]@{ + MajorVersion = $osReturnValue + InstallationType = $installationType + FriendlyName = if ($installationType -eq "Server Core") { "$osCaption ($installationType)" } else { $osCaption } + } } } diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueInstallationType.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueInstallationType.xml new file mode 100644 index 0000000000..86fc33cd49 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueInstallationType.xml @@ -0,0 +1,3 @@ + + Server + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueProductName.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueProductName.xml new file mode 100644 index 0000000000..25f98e2503 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E15/OS/RemoteRegistryValueProductName.xml @@ -0,0 +1,3 @@ + + Windows Server 2012 R2 Datacenter + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueInstallationType.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueInstallationType.xml new file mode 100644 index 0000000000..86fc33cd49 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueInstallationType.xml @@ -0,0 +1,3 @@ + + Server + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueProductName.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueProductName.xml new file mode 100644 index 0000000000..c8ccbd308b --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E16/OS/RemoteRegistryValueProductName.xml @@ -0,0 +1,3 @@ + + Windows Server 2016 Datacenter + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueInstallationType.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueInstallationType.xml new file mode 100644 index 0000000000..c49f628a04 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueInstallationType.xml @@ -0,0 +1,3 @@ + + Server Core + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueProductName.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueProductName.xml new file mode 100644 index 0000000000..b7c8bb6143 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/OS/RemoteRegistryValueProductName.xml @@ -0,0 +1,3 @@ + + Windows Server 2019 Datacenter + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 index ee95e5d159..f5653d395d 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E15.Main.Tests.ps1 @@ -49,7 +49,7 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2013" { It "Display Results - Operating System Information" { SetActiveDisplayGrouping "Operating System Information" - TestObjectMatch "Version" "Microsoft Windows Server 2012 R2 Datacenter" + TestObjectMatch "Version" "Windows Server 2012 R2 Datacenter" TestObjectMatch "Time Zone" "Pacific Standard Time" TestObjectMatch "Dynamic Daylight Time Enabled" "True" TestObjectMatch ".NET Framework" "4.8" -WriteType "Green" diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 index 4e3eb7208e..787c8c6ca5 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 @@ -49,7 +49,7 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" { It "Display Results - Operating System Information" { SetActiveDisplayGrouping "Operating System Information" - TestObjectMatch "Version" "Microsoft Windows Server 2016 Datacenter" + TestObjectMatch "Version" "Windows Server 2016 Datacenter" TestObjectMatch "Time Zone" "Pacific Standard Time" TestObjectMatch "Dynamic Daylight Time Enabled" "True" TestObjectMatch ".NET Framework" "4.8" -WriteType "Green" diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 index fcf3eb9111..a96a635e3d 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 @@ -49,7 +49,7 @@ Describe "Testing Health Checker by Mock Data Imports" { It "Display Results - Operating System Information" { SetActiveDisplayGrouping "Operating System Information" - TestObjectMatch "Version" "Microsoft Windows Server 2019 Datacenter" + TestObjectMatch "Version" "Windows Server 2019 Datacenter (Server Core)" TestObjectMatch "Time Zone" "Pacific Standard Time" TestObjectMatch "Dynamic Daylight Time Enabled" "True" TestObjectMatch ".NET Framework" "4.8" -WriteType "Green" diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 index bb3880fe75..68f8d2193b 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 @@ -60,7 +60,7 @@ Describe "Testing Health Checker by Mock Data Imports" { Assert-MockCalled Get-WmiObjectHandler -Exactly 6 Assert-MockCalled Invoke-ScriptBlockHandler -Exactly 4 - Assert-MockCalled Get-RemoteRegistryValue -Exactly 21 + Assert-MockCalled Get-RemoteRegistryValue -Exactly 23 Assert-MockCalled Get-NETFrameworkVersion -Exactly 1 Assert-MockCalled Get-DotNetDllFileVersions -Exactly 1 Assert-MockCalled Get-NicPnpCapabilitiesSetting -Exactly 1 diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 index 0aa934ab7d..a1ce6f49aa 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 @@ -96,6 +96,8 @@ Mock Get-RemoteRegistryValue { "MinimumConnectionTimeout" { return 0 } "LmCompatibilityLevel" { return $null } "UBR" { return 720 } + "ProductName" { return Import-Clixml "$Script:MockDataCollectionRoot\OS\RemoteRegistryValueProductName.xml" } + "InstallationType" { return Import-Clixml "$Script:MockDataCollectionRoot\OS\RemoteRegistryValueInstallationType.xml" } "DisableCompression" { return 0 } "CtsProcessorAffinityPercentage" { return 0 } "Enabled" { return 0 } From f6e24dd6b386f3695fa2d79c7c4a6d184f437d2a Mon Sep 17 00:00:00 2001 From: iserrano76 Date: Mon, 9 Oct 2023 16:09:38 +0200 Subject: [PATCH 05/30] Include W3wp process in the analysis. --- Diagnostics/AVTester/Test-ExchAVExclusions.ps1 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 index 73e320ccf5..0f75837ebb 100644 --- a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 +++ b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 @@ -373,8 +373,11 @@ Write-SimpleLogFile -string "Testing for AV loaded in processes" -name $LogFile # Test Exchange Processes for unexpected modules $ProcessList = Get-ExchAVExclusionsProcess -ExchangePath $ExchangePath -MsiProductMinor ([byte]$serverExchangeInstallDirectory.MsiProductMinor) +# Include w3wp process in the analysis +$ProcessList += (Join-Path $env:SystemRoot '\System32\inetSrv\W3wp.exe') + # Gather all processes on the computer -$ServerProcess = Get-Process +$ServerProcess = Get-Process | Sort-Object -Property ProcessName # Module allow list $ModuleAllowList = New-Object Collections.Generic.List[string] @@ -391,6 +394,7 @@ $ModuleAllowList.add("ExDbFailureItemApi.dll") $ModuleAllowList.add("Microsoft.Cloud.InstrumentationFramework.Metrics.ni.dll") $ModuleAllowList.add("IfxMetrics.dll") $ModuleAllowList.add("ManagedBlingSigned.dll") +$ModuleAllowList.add("ManagedBlingSigned.ni.dll") $ModuleAllowList.add("l3codecp.acm") $ModuleAllowList.add("System.IdentityModel.Tokens.jwt.ni.dll") # Oracle modules associated with 'Outside In® Technology' @@ -414,6 +418,7 @@ Write-SimpleLogFile -string ("Allow List Module Count: " + $ModuleAllowList.coun $UnexpectedModuleFound = 0 +$showWarning = $false # Gather each process and work thru their module list to remove any known modules. foreach ($process in $ServerProcess) { @@ -438,8 +443,13 @@ foreach ($process in $ServerProcess) { Write-Warning ("Possible AV Modules found in process $($process.ProcessName)") $UnexpectedModuleFound++ foreach ($module in $ProcessModules) { - $OutString = ("[FAIL] - PROCESS: $($process.ProcessName) MODULE: $($module.ModuleName) COMPANY: $($module.Company)") - Write-SimpleLogFile -string $OutString -Name $LogFile + if ( $process.MainModule.ModuleName -eq "W3wp.exe" -and $showWarning -eq $false) { + Write-Warning "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance." + Write-SimpleLogFile -string "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance." -name $LogFile + $showWarning = $true + } + $OutString = ("[FAIL] - PROCESS: $($process.ProcessName) PID($($process.Id)) MODULE: $($module.ModuleName) COMPANY: $($module.Company)`n`t $($module.FileName)") + Write-SimpleLogFile -string $OutString -Name $LogFile -OutHost $OutString | Out-File $OutputProcessPath -Append } } From 753d9209ce50edd1cb908e487c88c87ba3ccf61f Mon Sep 17 00:00:00 2001 From: iserrano76 Date: Mon, 9 Oct 2023 19:16:09 +0200 Subject: [PATCH 06/30] adding clarification and verify dll and ni.dll --- .../AVTester/Test-ExchAVExclusions.ps1 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 index 0f75837ebb..f1095ea445 100644 --- a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 +++ b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 @@ -383,20 +383,19 @@ $ServerProcess = Get-Process | Sort-Object -Property ProcessName $ModuleAllowList = New-Object Collections.Generic.List[string] # cSpell:disable -$ModuleAllowList.add("Google.Protobuf.ni.dll") -$ModuleAllowList.add("Microsoft.RightsManagementServices.Core.ni.dll") -$ModuleAllowList.add("Newtonsoft.Json.ni.dll") -$ModuleAllowList.add("Microsoft.Cloud.InstrumentationFramework.Events.ni.dll") +$ModuleAllowList.add("Google.Protobuf.dll") +$ModuleAllowList.add("Microsoft.RightsManagementServices.Core.dll") +$ModuleAllowList.add("Newtonsoft.Json.dll") +$ModuleAllowList.add("Microsoft.Cloud.InstrumentationFramework.Events.dll") $ModuleAllowList.add("HealthServicePerformance.dll") $ModuleAllowList.add("InterceptCounters.dll") $ModuleAllowList.add("MOMConnectorPerformance.dll") $ModuleAllowList.add("ExDbFailureItemApi.dll") -$ModuleAllowList.add("Microsoft.Cloud.InstrumentationFramework.Metrics.ni.dll") +$ModuleAllowList.add("Microsoft.Cloud.InstrumentationFramework.Metrics.dll") $ModuleAllowList.add("IfxMetrics.dll") $ModuleAllowList.add("ManagedBlingSigned.dll") -$ModuleAllowList.add("ManagedBlingSigned.ni.dll") $ModuleAllowList.add("l3codecp.acm") -$ModuleAllowList.add("System.IdentityModel.Tokens.jwt.ni.dll") +$ModuleAllowList.add("System.IdentityModel.Tokens.jwt.dll") # Oracle modules associated with 'Outside In® Technology' $ModuleAllowList.add("wvcore.dll") $ModuleAllowList.add("sccut.dll") @@ -418,6 +417,10 @@ Write-SimpleLogFile -string ("Allow List Module Count: " + $ModuleAllowList.coun $UnexpectedModuleFound = 0 +"`n####################################################################################################" | Out-File $OutputProcessPath +"$((Get-Date).ToString())" | Out-File $OutputProcessPath -Append +"####################################################################################################" | Out-File $OutputProcessPath -Append + $showWarning = $false # Gather each process and work thru their module list to remove any known modules. foreach ($process in $ServerProcess) { @@ -436,7 +439,7 @@ foreach ($process in $ServerProcess) { # Clear out modules from the allow list foreach ($module in $ModuleAllowList) { - $ProcessModules = $ProcessModules | Where-Object { $_.ModuleName -ne $module } + $ProcessModules = $ProcessModules | Where-Object { $_.ModuleName -ne $module -and $_.ModuleName -ne $($module.Replace(".dll", ".ni.dll")) } } if ($ProcessModules.count -gt 0) { From e40dd69e35238ff00cbae15518d036659cdeb982 Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Mon, 9 Oct 2023 13:45:59 -0700 Subject: [PATCH 07/30] Add NormalizedSubject back and expanded SCN and RT --- Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index e759b6f0d6..5d6a646873 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -29,7 +29,7 @@ param( ) function GetCalendarDiagnosticObjects { - $CustomPropertyNameList = "AppointmentCounterProposal", "AppointmentRecurring", "CalendarItemType", "CalendarProcessed", "ClientIntent", "DisplayAttendeesCc", "DisplayAttendeesTo", "EventEmailReminderTimer", "ExternalSharingMasterId", "FreeBusyStatus", "From", "HasAttachment", "IsAllDayEvent", "IsCancelled", "IsMeeting", "MapiEndTime", "MapiStartTime", "OnlineMeetingConfLink", "OnlineMeetingExternalLink", "OnlineMeetingInternalLink", "SentRepresentingDisplayName", "SentRepresentingEmailAddress"; + $CustomPropertyNameList = "AppointmentCounterProposal", "AppointmentRecurring", "CalendarItemType", "CalendarProcessed", "ClientIntent", "DisplayAttendeesCc", "DisplayAttendeesTo", "EventEmailReminderTimer", "ExternalSharingMasterId", "FreeBusyStatus", "From", "HasAttachment", "IsAllDayEvent", "IsCancelled", "IsMeeting", "MapiEndTime", "MapiStartTime", "NormalizedSubject", "SentRepresentingDisplayName", "SentRepresentingEmailAddress"; if ($Identity -and $Subject -and $MeetingID) { $script:GetCDO = Get-CalendarDiagnosticObjects -Identity $Identity -MeetingID $MeetingID -CustomPropertyNames $CustomPropertyNameList -WarningAction Ignore -MaxResults 2000; } @@ -165,7 +165,7 @@ function BuildCSV { 'IPM.Schedule.Meeting.Resp.Pos' = "RespPos" } - $SCN = @{ + $ShortClientNameProcessor = @{ 'Client=Hub Transport' = "Transport" 'Client=MSExchangeRPC' = "Outlook" 'Lync for Mac' = "LyncMac" @@ -187,7 +187,7 @@ function BuildCSV { 'Client=OutlookService;Outlook-iOS' = "OutlookiOS" } - $RT = @{ + $ResponseTypeOptions = @{ '0' = "None" "1" = "Organizer" '2' = "Tentative" @@ -203,7 +203,7 @@ function BuildCSV { $ItemType = $CalendarItemTypes.($CalLog.ItemClass); $ShortClientName = @(); $script:KeyInput = $CalLog.ClientInfoString; - $ResponseType = $RT.($CalLog.ResponseType.ToString()); + $ResponseType = $ResponseTypeOptions.($CalLog.ResponseType.ToString()); if (!$CalLog.ClientInfoString) { $ShortClientName = "NotFound"; @@ -249,7 +249,7 @@ function BuildCSV { $ShortClientName = "Rest"; } } else { - $ShortClientName = findMatch -PassedHash $SCN; + $ShortClientName = findMatch -PassedHash $ShortClientNameProcessor; } if ($CalLog.ClientInfoString -like "*InternalCalendarSharing*" -and $CalLog.ClientInfoString -like "*OWA*") { @@ -370,6 +370,7 @@ function BuildCSV { 'CleanGlobalObjectId' = $CalLog.CleanGlobalObjectId 'MapiStartTime' = $CalLog.MapiStartTime 'MapiEndTime' = $CalLog.MapiEndTime + 'NormalizedSubject' = $CalLog.NormalizedSubject 'AppointmentRecurring' = $CalLog.AppointmentRecurring 'HasAttachment' = $CalLog.HasAttachment 'IsCancelled' = $CalLog.IsCancelled @@ -381,9 +382,6 @@ function BuildCSV { 'IsOrganizerProperty' = $CalLog.IsOrganizerProperty 'EventEmailReminderTimer' = $CalLog.EventEmailReminderTimer 'ExternalSharingMasterId' = $CalLog.ExternalSharingMasterId - 'OnlineMeetingConfLink' = $CalLog.OnlineMeetingConfLink - 'OnlineMeetingExternalLink' = $CalLog.OnlineMeetingExternalLink - 'OnlineMeetingInternalLink' = $CalLog.OnlineMeetingInternalLink } } $script:Results = $GCDOResults; From a76cba9d5d0dadf8222a5e1b19f4770a5102e84f Mon Sep 17 00:00:00 2001 From: Shane Ferrell Date: Mon, 9 Oct 2023 13:52:18 -0700 Subject: [PATCH 08/30] Found extra use of OnlineMeeting stuff --- .../Get-CalendarDiagnosticObjectsSummary.ps1 | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 index 5d6a646873..5ac0c683b0 100644 --- a/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 +++ b/Calendar/Get-CalendarDiagnosticObjectsSummary.ps1 @@ -565,21 +565,6 @@ function BuildTimeline { MeetingSummary -Time " " -MeetingChanges $TimeLineText } - if ($CalLog.OnlineMeetingConfLink -ne $PreviousCalLog.OnlineMeetingConfLink) { - [Array]$TimeLineText = "The Online Meeting Conference Link changed from [$($PreviousCalLog.OnlineMeetingConfLink)] to: [$($CalLog.OnlineMeetingConfLink)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.OnlineMeetingExternalLink -ne $PreviousCalLog.OnlineMeetingExternalLink) { - [Array]$TimeLineText = "The Online Meeting External Link changed from [$($PreviousCalLog.OnlineMeetingExternalLink)] to: [$($CalLog.OnlineMeetingExternalLink)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - - if ($CalLog.OnlineMeetingInternalLink -ne $PreviousCalLog.OnlineMeetingInternalLink) { - [Array]$TimeLineText = "The Online Meeting Internal Link changed from [$($PreviousCalLog.OnlineMeetingInternalLink)] to: [$($CalLog.OnlineMeetingInternalLink)]" - MeetingSummary -Time " " -MeetingChanges $TimeLineText - } - if ($CalLog.SenderEmailAddress -ne $PreviousCalLog.SenderEmailAddress) { [Array]$TimeLineText = "The Sender Email Address changed from [$($PreviousCalLog.SenderEmailAddress)] to: [$($CalLog.SenderEmailAddress)]" MeetingSummary -Time " " -MeetingChanges $TimeLineText @@ -884,7 +869,7 @@ $UniqueMeetingID = $GlobalObjectId | Select-Object -Unique; if ($UniqueMeetingID.count -gt 1) { $UniqueMeetingID | ForEach-Object { $MeetingID = $_; - $script:GCDO = Get-CalendarDiagnosticObjects -Identity $Identity -MeetingID $MeetingID -CustomPropertyNames AppointmentCounterProposal, AppointmentRecurring, CalendarItemType, CalendarProcessed, ClientIntent, DisplayAttendeesCc, DisplayAttendeesTo, EventEmailReminderTimer, ExternalSharingMasterId, FreeBusyStatus, From, HasAttachment, IsAllDayEvent, IsCancelled, IsMeeting, MapiEndTime, MapiStartTime, OnlineMeetingConfLink, OnlineMeetingExternalLink, OnlineMeetingInternalLink, SentRepresentingDisplayName, SentRepresentingEmailAddress -WarningAction Ignore -MaxResults 2000; + $script:GCDO = Get-CalendarDiagnosticObjects -Identity $Identity -MeetingID $MeetingID -CustomPropertyNames AppointmentCounterProposal, AppointmentRecurring, CalendarItemType, CalendarProcessed, ClientIntent, DisplayAttendeesCc, DisplayAttendeesTo, EventEmailReminderTimer, ExternalSharingMasterId, FreeBusyStatus, From, HasAttachment, IsAllDayEvent, IsCancelled, IsMeeting, MapiEndTime, MapiStartTime, NormalizedSubject, SentRepresentingDisplayName, SentRepresentingEmailAddress -WarningAction Ignore -MaxResults 2000; BuildCSV; BuildTimeline; } From 05cbfdfc84c9b66690dd05dddb566d8279748b7d Mon Sep 17 00:00:00 2001 From: iserrano76 Date: Tue, 10 Oct 2023 13:37:45 +0200 Subject: [PATCH 09/30] rename dlls and change output file --- .../AVTester/Test-ExchAVExclusions.ps1 | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 index f1095ea445..2810462c9e 100644 --- a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 +++ b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 @@ -408,18 +408,15 @@ $ModuleAllowList.add("sccfmt.dll") $ModuleAllowList.add("sccind.dll") $ModuleAllowList.add("sccca.dll") $ModuleAllowList.add("scclo.dll") -$ModuleAllowList.add("SCCOLE2.DLL") -$ModuleAllowList.add("SCCSD.DLL") -$ModuleAllowList.add("SCCXT.DLL") +$ModuleAllowList.add("SCCOLE2.dll") +$ModuleAllowList.add("SCCSD.dll") +$ModuleAllowList.add("SCCXT.dll") # cSpell:enable Write-SimpleLogFile -string ("Allow List Module Count: " + $ModuleAllowList.count) -Name $LogFile $UnexpectedModuleFound = 0 -"`n####################################################################################################" | Out-File $OutputProcessPath -"$((Get-Date).ToString())" | Out-File $OutputProcessPath -Append -"####################################################################################################" | Out-File $OutputProcessPath -Append $showWarning = $false # Gather each process and work thru their module list to remove any known modules. @@ -443,12 +440,19 @@ foreach ($process in $ServerProcess) { } if ($ProcessModules.count -gt 0) { + + if ($UnexpectedModuleFound -eq 0) { + "`n####################################################################################################" | Out-File $OutputProcessPath -Append + "$((Get-Date).ToString())" | Out-File $OutputProcessPath -Append + "####################################################################################################" | Out-File $OutputProcessPath -Append + } + Write-Warning ("Possible AV Modules found in process $($process.ProcessName)") $UnexpectedModuleFound++ foreach ($module in $ProcessModules) { if ( $process.MainModule.ModuleName -eq "W3wp.exe" -and $showWarning -eq $false) { - Write-Warning "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance." - Write-SimpleLogFile -string "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance." -name $LogFile + Write-Warning "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance or functionality." + Write-SimpleLogFile -string "W3wp.exe is not present in the recommended Exclusion list but we found 3rd Party modules on it and could affect Exchange performance or functionality." -name $LogFile $showWarning = $true } $OutString = ("[FAIL] - PROCESS: $($process.ProcessName) PID($($process.Id)) MODULE: $($module.ModuleName) COMPANY: $($module.Company)`n`t $($module.FileName)") @@ -459,6 +463,10 @@ foreach ($process in $ServerProcess) { } } +if ($UnexpectedModuleFound -gt 0) { + "`n####################################################################################################" | Out-File $OutputProcessPath -Append +} + # Final output for process detection if ($UnexpectedModuleFound -gt 0) { Write-SimpleLogFile -string ("Found $($UnexpectedModuleFound) processes with unexpected modules loaded") -Name $LogFile -OutHost From 99436fe5aafee03af0f098242686bd86b5762a06 Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Tue, 10 Oct 2023 13:55:08 +0200 Subject: [PATCH 10/30] Adjustments based on review --- .../Get-ServerOperatingSystemVersion.ps1 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 index c69176ddff..5f456d56a1 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 @@ -13,14 +13,6 @@ function Get-ServerOperatingSystemVersion { begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $osReturnValue = [string]::Empty - } - process { - Write-Verbose "Getting the version build information for computer: $ComputerName" - $baseParams = @{ - MachineName = $ComputerName - CatchActionFunction = $CatchActionFunction - } - # Get ProductName via registry call as this is more accurate when running on Server Core $productNameParams = $baseParams + @{ SubKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" @@ -32,6 +24,13 @@ function Get-ServerOperatingSystemVersion { SubKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" GetValue = "InstallationType" } + } + process { + Write-Verbose "Getting the version build information for computer: $ComputerName" + $baseParams = @{ + MachineName = $ComputerName + CatchActionFunction = $CatchActionFunction + } $osCaption = Get-RemoteRegistryValue @productNameParams $installationType = Get-RemoteRegistryValue @installationTypeParams From a8516906a4022d671d593f74543a7fe1847cc602 Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Tue, 10 Oct 2023 13:57:11 +0200 Subject: [PATCH 11/30] Moved base params to begin --- .../Get-ServerOperatingSystemVersion.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 index 5f456d56a1..156a8d9923 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-ServerOperatingSystemVersion.ps1 @@ -13,6 +13,11 @@ function Get-ServerOperatingSystemVersion { begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $osReturnValue = [string]::Empty + $baseParams = @{ + MachineName = $ComputerName + CatchActionFunction = $CatchActionFunction + } + # Get ProductName via registry call as this is more accurate when running on Server Core $productNameParams = $baseParams + @{ SubKey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" @@ -27,11 +32,6 @@ function Get-ServerOperatingSystemVersion { } process { Write-Verbose "Getting the version build information for computer: $ComputerName" - $baseParams = @{ - MachineName = $ComputerName - CatchActionFunction = $CatchActionFunction - } - $osCaption = Get-RemoteRegistryValue @productNameParams $installationType = Get-RemoteRegistryValue @installationTypeParams Write-Verbose "OsCaption: '$osCaption' InstallationType: '$installationType'" From 0f88a6f86d6ff374d3bfeeab705e20ea398345aa Mon Sep 17 00:00:00 2001 From: iserrano76 Date: Tue, 10 Oct 2023 14:39:32 +0200 Subject: [PATCH 12/30] Removing empty lines --- Diagnostics/AVTester/Test-ExchAVExclusions.ps1 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 index 2810462c9e..5d603aa82b 100644 --- a/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 +++ b/Diagnostics/AVTester/Test-ExchAVExclusions.ps1 @@ -416,9 +416,8 @@ $ModuleAllowList.add("SCCXT.dll") Write-SimpleLogFile -string ("Allow List Module Count: " + $ModuleAllowList.count) -Name $LogFile $UnexpectedModuleFound = 0 - - $showWarning = $false + # Gather each process and work thru their module list to remove any known modules. foreach ($process in $ServerProcess) { @@ -440,13 +439,11 @@ foreach ($process in $ServerProcess) { } if ($ProcessModules.count -gt 0) { - if ($UnexpectedModuleFound -eq 0) { "`n####################################################################################################" | Out-File $OutputProcessPath -Append "$((Get-Date).ToString())" | Out-File $OutputProcessPath -Append "####################################################################################################" | Out-File $OutputProcessPath -Append } - Write-Warning ("Possible AV Modules found in process $($process.ProcessName)") $UnexpectedModuleFound++ foreach ($module in $ProcessModules) { From 273f2418c042bdb772b89797cc9b70677bc6b130 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 4 Oct 2023 12:39:42 -0500 Subject: [PATCH 13/30] only show warning for AES256-CBC if IRM is enabled --- .../Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 | 3 ++- .../Get-OrganizationInformation.ps1 | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index 91a0d196bb..6ea9d2584d 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -340,7 +340,8 @@ function Invoke-AnalyzerSecuritySettings { } if (($aes256CbcInformation.AES256CBCSupportedBuild) -and - ($aes256CbcInformation.ValidAESConfiguration -eq $false)) { + ($aes256CbcInformation.ValidAESConfiguration -eq $false) -and + ($HealthServerObject.OrganizationInformation.GetIrmConfiguration.InternalLicensingEnabled -eq $true)) { $params.Details = ("True" + "`r`n`t`tThis build supports AES256-CBC protected content, but the configuration is not complete. Exchange Server is not able to decrypt" + "`r`n`t`tprotected messages which could impact eDiscovery and Journaling tasks. If you use Rights Management Service (RMS) on-premises," + diff --git a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 index 1d3cb0b7ed..91d0f37789 100644 --- a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 @@ -66,6 +66,13 @@ function Get-OrganizationInformation { $wellKnownSecurityGroups = Get-ExchangeWellKnownSecurityGroups $isSplitADPermissions = Get-ExchangeADSplitPermissionsEnabled -CatchActionFunction ${Function:Invoke-CatchActions} + try { + $getIrmConfiguration = Get-IRMConfiguration -ErrorAction Stop + } catch { + Write-Verbose "Failed to get the IRM Configuration" + Invoke-CatchActions + } + try { $getDdgPublicFolders = @(Get-DynamicDistributionGroup "PublicFolderMailboxes*" -IncludeSystemObjects -ErrorAction "Stop") } catch { @@ -143,6 +150,7 @@ function Get-OrganizationInformation { ADSiteCount = $adSiteCount GetSettingOverride = $getSettingOverride GetDynamicDgPublicFolderMailboxes = $getDdgPublicFolders + GetIrmConfiguration = $getIrmConfiguration } } } From 3e6fd779ea973ef66b1ddd5144530aab292e4e23 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 4 Oct 2023 13:39:27 -0500 Subject: [PATCH 14/30] Update logic for IRM callout. Make Red for InternalLicensingEnabled --- .../Security/Invoke-AnalyzerSecuritySettings.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index 6ea9d2584d..a5c3180cfe 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -339,14 +339,22 @@ function Invoke-AnalyzerSecuritySettings { DisplayWriteType = "Green" } + $irmConfig = $HealthServerObject.OrganizationInformation.GetIrmConfiguration + if (($aes256CbcInformation.AES256CBCSupportedBuild) -and ($aes256CbcInformation.ValidAESConfiguration -eq $false) -and - ($HealthServerObject.OrganizationInformation.GetIrmConfiguration.InternalLicensingEnabled -eq $true)) { + ($irmConfig.InternalLicensingEnabled -eq $true -or + $irmConfig.ExternalLicensingEnabled -eq $true)) { $params.Details = ("True" + "`r`n`t`tThis build supports AES256-CBC protected content, but the configuration is not complete. Exchange Server is not able to decrypt" + "`r`n`t`tprotected messages which could impact eDiscovery and Journaling tasks. If you use Rights Management Service (RMS) on-premises," + "`r`n`t`tplease follow the instructions as outlined in the documentation: https://aka.ms/ExchangeCBCKB") - $params.DisplayWriteType = "Yellow" + + if ($irmConfig.InternalLicensingEnabled -eq $true) { + $params.DisplayWriteType = "Red" + } else { + $params.DisplayWriteType = "Yellow" + } } elseif ($aes256CbcInformation.AES256CBCSupportedBuild -eq $false) { $params.Details = ("False" + "`r`n`t`tThis could lead to scenarios where Exchange Server is no longer able to decrypt protected messages," + From ba9f4a0210b39a39475223620db1e714127fb422 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 10 Oct 2023 10:46:24 -0500 Subject: [PATCH 15/30] Pester testing for AES256-CBC Protected Content Support --- .../Invoke-AnalyzerSecuritySettings.ps1 | 11 ++++++++--- .../E15/Exchange/GetIrmConfiguration.xml | Bin 0 -> 61500 bytes .../E16/Exchange/GetIrmConfiguration.xml | Bin 0 -> 61500 bytes .../E19/Exchange/GetIrmConfiguration.xml | Bin 0 -> 61500 bytes .../Tests/HealthChecker.E19.Main.Tests.ps1 | 1 + ...althCheckerTest.CommonMocks.NotPublished.ps1 | 5 +++++ 6 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/GetIrmConfiguration.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/GetIrmConfiguration.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIrmConfiguration.xml diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index a5c3180cfe..c3cdf80d52 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -333,10 +333,13 @@ function Invoke-AnalyzerSecuritySettings { Add-AnalyzedResultInformation @params # AES256-CBC encryption support check + $sp = "Supported Build" + $vc = "Valid Configuration" $params = $baseParams + @{ - Name = "AES256-CBC Protected Content Support" - Details = $true - DisplayWriteType = "Green" + Name = "AES256-CBC Protected Content Support" + Details = $true + DisplayWriteType = "Green" + DisplayTestingValue = "$sp and $vc" } $irmConfig = $HealthServerObject.OrganizationInformation.GetIrmConfiguration @@ -345,6 +348,7 @@ function Invoke-AnalyzerSecuritySettings { ($aes256CbcInformation.ValidAESConfiguration -eq $false) -and ($irmConfig.InternalLicensingEnabled -eq $true -or $irmConfig.ExternalLicensingEnabled -eq $true)) { + $params.DisplayTestingValue = "$sp and not $vc" $params.Details = ("True" + "`r`n`t`tThis build supports AES256-CBC protected content, but the configuration is not complete. Exchange Server is not able to decrypt" + "`r`n`t`tprotected messages which could impact eDiscovery and Journaling tasks. If you use Rights Management Service (RMS) on-premises," + @@ -356,6 +360,7 @@ function Invoke-AnalyzerSecuritySettings { $params.DisplayWriteType = "Yellow" } } elseif ($aes256CbcInformation.AES256CBCSupportedBuild -eq $false) { + $params.DisplayTestingValue = "Not $sp" $params.Details = ("False" + "`r`n`t`tThis could lead to scenarios where Exchange Server is no longer able to decrypt protected messages," + "`r`n`t`tfor example, when sending rights management protected messages using AES256-CBC encryption algorithm," + diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/GetIrmConfiguration.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/GetIrmConfiguration.xml new file mode 100644 index 0000000000000000000000000000000000000000..67409a13415099185d54acbc67267c069a1018cc GIT binary patch literal 61500 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 literal 0 HcmV?d00001 diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/GetIrmConfiguration.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/GetIrmConfiguration.xml new file mode 100644 index 0000000000000000000000000000000000000000..67409a13415099185d54acbc67267c069a1018cc GIT binary patch literal 61500 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 literal 0 HcmV?d00001 diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIrmConfiguration.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIrmConfiguration.xml new file mode 100644 index 0000000000000000000000000000000000000000..67409a13415099185d54acbc67267c069a1018cc GIT binary patch literal 61500 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 literal 0 HcmV?d00001 diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 index a96a635e3d..ae5aabbe29 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 @@ -136,6 +136,7 @@ Describe "Testing Health Checker by Mock Data Imports" { TestObjectMatch "AMSI Enabled" "True" -WriteType "Green" TestObjectMatch "Strict Mode disabled" "False" -WriteType "Green" TestObjectMatch "BaseTypeCheckForDeserialization disabled" "False" -WriteType "Green" + TestObjectMatch "AES256-CBC Protected Content Support" "Not Supported Build" -WriteType "Red" $Script:ActiveGrouping.Count | Should -Be 79 } diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 index a1ce6f49aa..1152adda3e 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 @@ -256,6 +256,11 @@ function Get-OrganizationConfig { function Get-DynamicDistributionGroup { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetDynamicDistributionGroupPfMailboxes.xml" } + +function Get-IRMConfiguration { + return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetIrmConfiguration.xml" +} + # virtual directory cmdlets to return null till we do actual checks against the vDirs. function Get-ActiveSyncVirtualDirectory { return $null } From 206408cccaad89c36d5fda50ef0d90d96c5fbc4c Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 29 Aug 2023 16:23:52 -0500 Subject: [PATCH 16/30] Switch OAB Default Web Site to Allow for EP --- Shared/Get-ExtendedProtectionConfiguration.ps1 | 3 ++- docs/Security/Extended-Protection.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Shared/Get-ExtendedProtectionConfiguration.ps1 b/Shared/Get-ExtendedProtectionConfiguration.ps1 index 807fe41fbe..2f393e1efd 100644 --- a/Shared/Get-ExtendedProtectionConfiguration.ps1 +++ b/Shared/Get-ExtendedProtectionConfiguration.ps1 @@ -252,7 +252,8 @@ function Get-ExtendedProtectionConfiguration { (NewVirtualDirMatchingEntry "ECP" -WebSite $default, $backend -ExtendedProtection "Require", "Require") (NewVirtualDirMatchingEntry "EWS" -WebSite $default, $backend -ExtendedProtection "Allow", "Require") (NewVirtualDirMatchingEntry "Microsoft-Server-ActiveSync" -WebSite $default, $backend -ExtendedProtection "Allow", "Require") - (NewVirtualDirMatchingEntry "OAB" -WebSite $default, $backend -ExtendedProtection "Require", "Require") + # This was changed due to Outlook for Mac not being able to do download the OAB. + (NewVirtualDirMatchingEntry "OAB" -WebSite $default, $backend -ExtendedProtection "Allow", "Require") (NewVirtualDirMatchingEntry "Powershell" -WebSite $default, $backend -ExtendedProtection "Require", "Require" -SslFlags "SslNegotiateCert", "Ssl,Ssl128,SslNegotiateCert") (NewVirtualDirMatchingEntry "OWA" -WebSite $default, $backend -ExtendedProtection "Require", "Require") (NewVirtualDirMatchingEntry "RPC" -WebSite $default, $backend -ExtendedProtection "Require", "Require") diff --git a/docs/Security/Extended-Protection.md b/docs/Security/Extended-Protection.md index 9e6b25e06c..fd0da69946 100644 --- a/docs/Security/Extended-Protection.md +++ b/docs/Security/Extended-Protection.md @@ -165,7 +165,7 @@ Enabling Extended Protection involves making many changes on all Exchange server | Default Website | EWS | Accept (UI) /Allow (Script) | Ssl,Ssl128 | | Default Website | MAPI | Required | Ssl,Ssl128 | | Default Website | Microsoft-Server-ActiveSync | Accept (UI) /Allow (Script) | Ssl,Ssl128 | -| Default Website | OAB | Required | Ssl,Ssl128 | +| Default Website | OAB | Accept (UI) /Allow (Script) | Ssl,Ssl128 | | Default Website | OWA | Required | Ssl,Ssl128 | | Default Website | PowerShell | Required | SslNegotiateCert | | Default Website | RPC | Required | Ssl,Ssl128 | From 22ab19ec5afd68b5a0e072ca717c11df105a330b Mon Sep 17 00:00:00 2001 From: David Paulson Date: Mon, 25 Sep 2023 13:49:36 -0500 Subject: [PATCH 17/30] Update pester testing to have OAB Default Web set to Allow This is to pass the current pipeline, but still need to update the logic for security purpose --- Shared/Get-ExtendedProtectionConfiguration.ps1 | 8 +++++++- .../Data/E15_Configured_Both_ApplicationHost.config | 2 +- .../Data/E15_Configured_Cas_ApplicationHost.config | 2 +- .../Data/E16_Configured_ApplicationHost.config | 2 +- .../Data/E16_Configured_IPFilter_ApplicationHost.config | 2 +- .../Data/E19_Configured_ApplicationHost.config | 2 +- .../Data/E19_Configured_IPFilter_ApplicationHost.config | 2 +- .../Get-ExtendedProtectionConfiguration.Tests.ps1 | 3 ++- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Shared/Get-ExtendedProtectionConfiguration.ps1 b/Shared/Get-ExtendedProtectionConfiguration.ps1 index 2f393e1efd..be83ccec97 100644 --- a/Shared/Get-ExtendedProtectionConfiguration.ps1 +++ b/Shared/Get-ExtendedProtectionConfiguration.ps1 @@ -357,12 +357,18 @@ function Get-ExtendedProtectionConfiguration { $extendedProtectionList.Add([PSCustomObject]@{ VirtualDirectoryName = $virtualDirectoryName Configuration = $extendedConfiguration + # The current Extended Protection configuration set on the server ExtendedProtection = $extendedConfiguration.ExtendedProtection + # The Supported Extended Protection is to verify that we have set the current Extended Protection + # setting value to the Expected Extended Protection Value SupportedExtendedProtection = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection + # The supported/expected Extended Protection Configuration value that we should be set to (based off the build of Exchange) ExpectedExtendedConfiguration = $expectedExtendedConfiguration + # Properly Secured is determined if we have a value equal to or greater than the ExpectedExtendedConfiguration value + # However, if we have a value greater than the expected, this could mean that we might run into a known set of issues. + ProperlySecuredConfiguration = $properlySecuredConfiguration MitigationEnabled = ($extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false") MitigationSupported = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) - ProperlySecuredConfiguration = $properlySecuredConfiguration ExpectedSslFlags = $matchEntry.SslFlags SslFlagsSetCorrectly = $sslFlagsToSet.Split(",").Count -eq $currentSetFlags.Count SslFlagsToSet = $sslFlagsToSet diff --git a/Shared/Tests/ExtendedProtection/Data/E15_Configured_Both_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E15_Configured_Both_ApplicationHost.config index eafef52b6c..4875f1dad4 100644 --- a/Shared/Tests/ExtendedProtection/Data/E15_Configured_Both_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E15_Configured_Both_ApplicationHost.config @@ -2324,7 +2324,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Data/E15_Configured_Cas_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E15_Configured_Cas_ApplicationHost.config index 2b1487228a..5a9d733d17 100644 --- a/Shared/Tests/ExtendedProtection/Data/E15_Configured_Cas_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E15_Configured_Cas_ApplicationHost.config @@ -1545,7 +1545,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Data/E16_Configured_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E16_Configured_ApplicationHost.config index 1cd4ffe707..c302795f23 100644 --- a/Shared/Tests/ExtendedProtection/Data/E16_Configured_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E16_Configured_ApplicationHost.config @@ -2317,7 +2317,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Data/E16_Configured_IPFilter_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E16_Configured_IPFilter_ApplicationHost.config index 99de2088d0..9012ac75b3 100644 --- a/Shared/Tests/ExtendedProtection/Data/E16_Configured_IPFilter_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E16_Configured_IPFilter_ApplicationHost.config @@ -2323,7 +2323,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Data/E19_Configured_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E19_Configured_ApplicationHost.config index 0b1ba1c940..1f75710577 100644 --- a/Shared/Tests/ExtendedProtection/Data/E19_Configured_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E19_Configured_ApplicationHost.config @@ -2318,7 +2318,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Data/E19_Configured_IPFilter_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E19_Configured_IPFilter_ApplicationHost.config index a39084f284..d4b3ef5c94 100644 --- a/Shared/Tests/ExtendedProtection/Data/E19_Configured_IPFilter_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E19_Configured_IPFilter_ApplicationHost.config @@ -2324,7 +2324,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 index 3f4ff561e7..b4d6e3d3ab 100644 --- a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 +++ b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 @@ -80,9 +80,10 @@ BeforeAll { $allow = $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | Where-Object { $_.ExtendedProtection -eq "Allow" } $null -ne $allow | Should -Be $true - $allow.Count | Should -Be 2 + $allow.Count | Should -Be 3 # Should be the below settings $allow.configuration.NodePath.Contains("Default Web Site/EWS") | Should -Be $true $allow.configuration.NodePath.Contains("Default Web Site/Microsoft-Server-ActiveSync") | Should -Be $true + $allow.configuration.NodePath.Contains("Default Web Site/OAB") | Should -Be $true } if (-not $SkipAutoDiscover) { From 0ecbe72d9a9220024b378f955b45e9fdc366eb95 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 26 Sep 2023 17:20:59 -0500 Subject: [PATCH 18/30] Updated Properly Secure and Supported Logic for EP Properly Secure is now if we are at the recommended value or higher. Supported Logic is going to be at the recommended value or lower as it is a supported scenario, just not secure --- ...rSecurityExtendedProtectionConfigState.ps1 | 11 ++-- .../ExchangeExtendedProtectionManagement.ps1 | 3 +- .../Get-ExtendedProtectionConfiguration.ps1 | 51 +++++++++++++++---- ...-ExtendedProtectionConfiguration.Tests.ps1 | 18 +++---- 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 index 1b43b18752..b4f70b6d35 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 @@ -88,7 +88,8 @@ function Invoke-AnalyzerSecurityExtendedProtectionConfigState { $vDirArray[0] = $vDirArray[1] Value = $entry.ExtendedProtection SupportedValue = if ($entry.MitigationSupported -and $entry.MitigationEnabled) { "None" } else { $entry.ExpectedExtendedConfiguration } - ConfigSupported = $entry.ProperlySecuredConfiguration + ConfigSupported = $entry.SupportedExtendedProtection + ConfigSecure = $entry.ProperlySecuredConfiguration RequireSSL = "$($ssl.RequireSSL) $(if($ssl.Ssl128Bit) { "(128-bit)" })".Trim() ClientCertificate = $ssl.ClientCertificate IPFilterEnabled = $entry.MitigationEnabled @@ -108,13 +109,17 @@ function Invoke-AnalyzerSecurityExtendedProtectionConfigState { if ($p -eq "ConfigSupported") { if ($o.$p -ne $true) { "Red" - } else { - "Green" } } elseif ($p -eq "IPFilterEnabled") { if ($o.$p -eq $true) { "Green" } + } elseif ($p -eq "ConfigSecure") { + if ($o.$p -ne $true) { + "Red" + } else { + "Green" + } } } diff --git a/Security/src/ExchangeExtendedProtectionManagement/ExchangeExtendedProtectionManagement.ps1 b/Security/src/ExchangeExtendedProtectionManagement/ExchangeExtendedProtectionManagement.ps1 index edfc3c6486..a2b97ec714 100644 --- a/Security/src/ExchangeExtendedProtectionManagement/ExchangeExtendedProtectionManagement.ps1 +++ b/Security/src/ExchangeExtendedProtectionManagement/ExchangeExtendedProtectionManagement.ps1 @@ -312,7 +312,8 @@ begin { $vDirArray[0] = $vDirArray[1] Value = $entry.ExtendedProtection SupportedValue = if ($entry.MitigationSupported -and $entry.MitigationEnabled) { "None" } else { $entry.ExpectedExtendedConfiguration } - ConfigSupported = $entry.ProperlySecuredConfiguration + ConfigSupported = $entry.SupportedExtendedProtection + ConfigSecure = $entry.ProperlySecuredConfiguration RequireSSL = "$($ssl.RequireSSL) $(if($ssl.Ssl128Bit) { "(128-bit)" })".Trim() ClientCertificate = $ssl.ClientCertificate IPFilterEnabled = $entry.MitigationEnabled diff --git a/Shared/Get-ExtendedProtectionConfiguration.ps1 b/Shared/Get-ExtendedProtectionConfiguration.ps1 index be83ccec97..89628e4881 100644 --- a/Shared/Get-ExtendedProtectionConfiguration.ps1 +++ b/Shared/Get-ExtendedProtectionConfiguration.ps1 @@ -339,34 +339,63 @@ function Get-ExtendedProtectionConfiguration { $expectedExtendedConfiguration = if ($supportedVersion) { $matchEntry.ExtendedProtection } else { "None" } $virtualDirectoryName = "$($matchEntry.WebSite)/$($matchEntry.VirtualDirectory)" - # Properly Secured Configuration is only a concern if Required is the Expected value - # If the Expected value is None or Allow, you can have it configured however you would like and from a security standpoint, it shouldn't be a concern. - # For a mitigation scenario, like EWS BE, Required is the Expected value. Therefore, on those directories, we need to verify that IP filtering is set if not set to Require. - if ($expectedExtendedConfiguration -eq "Require") { - $properlySecuredConfiguration = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection + # Supported Configuration is when the current value of Extended Protection is less than our expected extended protection value. + # While this isn't secure as we would like, it is still a supported state that should work. + $supportedExtendedConfiguration = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection + + if ($supportedExtendedConfiguration) { + Write-Verbose "The EP value set to the expected value." + } else { + Write-Verbose "We are expecting a value of '$expectedExtendedConfiguration' but the current value is '$($extendedConfiguration.ExtendedProtection)'" - if ($properlySecuredConfiguration -eq $false) { - # Only care about virtual directories that we allow mitigation for - $properlySecuredConfiguration = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) -and - $extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false" + if ($expectedExtendedConfiguration -eq "Require" -or + ($expectedExtendedConfiguration -eq "Allow" -and + $extendedConfiguration.ExtendedProtection -eq "None")) { + $supportedExtendedConfiguration = $true + Write-Verbose "This is still supported because it is lower than what we recommended." + } else { + Write-Verbose "This is not supported because you are higher than the recommended value and will likely cause problems." } + } + + # Properly Secured Configuration is when the current Extended Protection value is equal to or greater than the Expected Extended Protection Configuration. + # If the Expected value is Allow, you can have the value set to Allow or Required and it will not be a security risk. However, if set to None, that is a security concern. + # For a mitigation scenario, like EWS BE, Required is the Expected value. Therefore, on those directories, we need to verify that IP filtering is set if not set to Require. + $properlySecuredConfiguration = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection + + if ($properlySecuredConfiguration) { + Write-Verbose "We are 'properly' secure because we have EP set to the expected EP configuration value: $($expectedExtendedConfiguration)" + } elseif ($expectedExtendedConfiguration -eq "Require") { + Write-Verbose "Checking to see if we have mitigations enabled for the supported vDirs" + # Only care about virtual directories that we allow mitigation for + $properlySecuredConfiguration = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) -and + $extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false" + } elseif ($expectedExtendedConfiguration -eq "Allow") { + Write-Verbose "Checking to see if Extended Protection is set to 'Require' to still be considered secure" + $properlySecuredConfiguration = $extendedConfiguration.ExtendedProtection -eq "Require" } else { + Write-Verbose "Recommended EP setting is 'None' means you can have it higher, but you might run into other issues. But you are 'secure'." $properlySecuredConfiguration = $true } + Write-Verbose "Properly Secure Configuration value: $properlySecuredConfiguration" + $extendedProtectionList.Add([PSCustomObject]@{ VirtualDirectoryName = $virtualDirectoryName Configuration = $extendedConfiguration # The current Extended Protection configuration set on the server ExtendedProtection = $extendedConfiguration.ExtendedProtection - # The Supported Extended Protection is to verify that we have set the current Extended Protection + # The Recommended Extended Protection is to verify that we have set the current Extended Protection # setting value to the Expected Extended Protection Value - SupportedExtendedProtection = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection + RecommendedExtendedProtection = $expectedExtendedConfiguration -eq $extendedConfiguration.ExtendedProtection # The supported/expected Extended Protection Configuration value that we should be set to (based off the build of Exchange) ExpectedExtendedConfiguration = $expectedExtendedConfiguration # Properly Secured is determined if we have a value equal to or greater than the ExpectedExtendedConfiguration value # However, if we have a value greater than the expected, this could mean that we might run into a known set of issues. ProperlySecuredConfiguration = $properlySecuredConfiguration + # The Supported Extended Protection is a value that is equal to or lower than the Expected Extended Protection configuration. + # While this is not the best security setting, it is lower and shouldn't cause a connectivity issue and should still be supported. + SupportedExtendedProtection = $supportedExtendedConfiguration MitigationEnabled = ($extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false") MitigationSupported = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) ExpectedSslFlags = $matchEntry.SslFlags diff --git a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 index b4d6e3d3ab..d9acc10785 100644 --- a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 +++ b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 @@ -45,6 +45,9 @@ BeforeAll { $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | Where-Object { $_.SupportedExtendedProtection -eq $false } | Should -Be $null + $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | + Where-Object { $_.ProperlySecuredConfiguration -eq $false } | + Should -Be $null } function TestSupportedConfiguredExtendedProtection { @@ -66,15 +69,12 @@ BeforeAll { ($TestingExtendedProtectionResults.ExtendedProtectionConfiguration | Where-Object { $_.ExpectedExtendedConfiguration -ne "None" }).count | Should -Be $ExpectedExtendedProtectionNoneCount - if ($IPFilterEnabled -eq $false) { - $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | - Where-Object { $_.SupportedExtendedProtection -eq $false } | - Should -Be $null - } else { - ($TestingExtendedProtectionResults.ExtendedProtectionConfiguration | - Where-Object { $_.SupportedExtendedProtection -eq $false }).Count | - Should -Be 1 - } + $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | + Where-Object { $_.SupportedExtendedProtection -eq $false } | + Should -Be $null + $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | + Where-Object { $_.ProperlySecuredConfiguration -eq $false } | + Should -Be $null # Special configs if (-not $SkipAllow) { $allow = $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | From ff06ce00346dc2bba26dd88734e9d7a4e477bec0 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 27 Sep 2023 15:24:01 -0500 Subject: [PATCH 19/30] Unsupported scenarios flagged in Health Checker for Extended Protection even when secured. --- .../Invoke-AnalyzerExchangeInformation.ps1 | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index ccbad70674..97ab55100b 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -376,6 +376,33 @@ function Invoke-AnalyzerExchangeInformation { Details = $exchangeInformation.ExtendedProtectionConfig.ExtendedProtectionConfigured } Add-AnalyzedResultInformation @params + + # If any directory has a higher than expected configuration, we need to throw a warning + # This will be detected by SupportedExtendedProtection being set to false, as we are set higher than expected/recommended value you will likely run into issues of some kind + $notSupportedExtendedProtectionDirectories = $exchangeInformation.ExtendedProtectionConfig.ExtendedProtectionConfiguration | + Where-Object { $_.SupportedExtendedProtection -eq $false } + + if ($null -ne $notSupportedExtendedProtectionDirectories) { + foreach ($entry in $notSupportedExtendedProtectionDirectories) { + $expectedValue = if ($entry.MitigationSupported -and $entry.MitigationEnabled) { "None" } else { $entry.ExpectedExtendedConfiguration } + $params = $baseParams + @{ + Details = "$($entry.VirtualDirectoryName) - Current Value: '$($entry.ExtendedProtection)' Expected Value: '$expectedValue'" + DisplayWriteType = "Yellow" + DisplayCustomTabNumber = 2 + } + Add-AnalyzedResultInformation @params + } + + $params = $baseParams + @{ + Details = "`r`n`t`tThe current Extended Protection settings may cause issues with some clients types on $(if(@($notSupportedExtendedProtectionDirectories).Count -eq 1) { "this protocol."} else { "these protocols."})" + + "`r`n`t`tIt is recommended to set the EP setting to the recommended value if you are having issues with that protocol." + + "`r`n`t`tMore Information: https://aka.ms/ExchangeEPDoc" + DisplayWriteType = "Yellow" + } + Add-AnalyzedResultInformation @params + } else { + Write-Verbose "All virtual directories are supported for the Extended Protection value." + } } if ($null -ne $exchangeInformation.SettingOverrides) { From 9d1c720e64f113b0d0abdacc6f5d9bdd26f2d74f Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 28 Sep 2023 13:10:32 -0500 Subject: [PATCH 20/30] Created pester testing regarding mixed configuration of supported, recommended, and secured values --- .../E19_MisConfigured_ApplicationHost.config | 2 +- ...-ExtendedProtectionConfiguration.Tests.ps1 | 83 +++++++++++++++++-- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/Shared/Tests/ExtendedProtection/Data/E19_MisConfigured_ApplicationHost.config b/Shared/Tests/ExtendedProtection/Data/E19_MisConfigured_ApplicationHost.config index 5a843d3002..5c75321633 100644 --- a/Shared/Tests/ExtendedProtection/Data/E19_MisConfigured_ApplicationHost.config +++ b/Shared/Tests/ExtendedProtection/Data/E19_MisConfigured_ApplicationHost.config @@ -1984,7 +1984,7 @@ - + diff --git a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 index d9acc10785..249b01bc98 100644 --- a/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 +++ b/Shared/Tests/ExtendedProtection/Get-ExtendedProtectionConfiguration.Tests.ps1 @@ -55,6 +55,8 @@ BeforeAll { [object]$TestingExtendedProtectionResults, [int]$ExtendedProtectionNoneCount = 21, [int]$ExpectedExtendedProtectionNoneCount = 21, + [int]$NotSupportedExtendedProtectionCount = 0, + [int]$NotProperlySecureConfigurationCount = 0, [bool]$SkipAllow = $false, [bool]$SkipAutoDiscover = $false, [bool]$IPFilterEnabled = $false, @@ -69,12 +71,12 @@ BeforeAll { ($TestingExtendedProtectionResults.ExtendedProtectionConfiguration | Where-Object { $_.ExpectedExtendedConfiguration -ne "None" }).count | Should -Be $ExpectedExtendedProtectionNoneCount - $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | - Where-Object { $_.SupportedExtendedProtection -eq $false } | - Should -Be $null - $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | - Where-Object { $_.ProperlySecuredConfiguration -eq $false } | - Should -Be $null + ($TestingExtendedProtectionResults.ExtendedProtectionConfiguration | + Where-Object { $_.SupportedExtendedProtection -eq $false }).Count | + Should -Be $NotSupportedExtendedProtectionCount + ($TestingExtendedProtectionResults.ExtendedProtectionConfiguration | + Where-Object { $_.ProperlySecuredConfiguration -eq $false }).Count | + Should -Be $NotProperlySecureConfigurationCount # Special configs if (-not $SkipAllow) { $allow = $TestingExtendedProtectionResults.ExtendedProtectionConfiguration | @@ -291,6 +293,75 @@ Describe "Testing Get-ExtendedProtectionConfiguration.ps1" { } } + Context "Mix of Extended Protection Settings" { + It "Exchange 2019 Misconfigured" { + $mockParams = @{ + ComputerName = $Server + ExSetupVersion = "15.2.1118.29" + ApplicationHostConfig = $E19_MisConfigured_ApplicationHost + } + $results = (Get-ExtendedProtectionConfiguration @mockParams) + + $insecureNoneVirtualDirectories = @("Default Web Site/ECP", "Exchange Back End/ECP", "Exchange Back End/Powershell") + # OAB is not supported due to recent changes because of Outlook for Mac. However, if you don't have OL for Mac, you can have it set to require and be fine. + $notSupportedVirtualDirectories = @("Default Web Site/Microsoft-Server-ActiveSync", "Default Web Site/OAB") + $insecureConfigurationVirtualDirectories = $insecureNoneVirtualDirectories + @("Default Web Site/OWA") + + $params = @{ + TestingExtendedProtectionResults = $results + # Due to the lower settings on the insecure None Virtual Directories + ExtendedProtectionNoneCount = (21 - $insecureNoneVirtualDirectories.Count) + # FE EAS set to Require and the old setting of FE OAB being set to Require + NotSupportedExtendedProtectionCount = $notSupportedVirtualDirectories.Count + # Lower settings of FE/BE ECP vDir and Exchange Back End/PowerShell + NotProperlySecureConfigurationCount = $insecureConfigurationVirtualDirectories.Count + # skip checking over the allow sections because we don't have all the default value there in this configuration + SkipAllow = $true + # skip over AutoD because we have more None values in this configuration + SkipAutoDiscover = $true + } + TestSupportedConfiguredExtendedProtection @params + + # manually review the differences + $extendedProtectionNoneResults = $results.ExtendedProtectionConfiguration | + Where-Object { $_.ExtendedProtection -eq "None" } + $extendedProtectionNoneResults.Count | Should -Be ($insecureNoneVirtualDirectories.Count + 2) + # All None EP values should be supported even though not secure for some + $extendedProtectionNoneResults | + Where-Object { $_.SupportedExtendedProtection -eq $false } | + Should -Be $null + ($extendedProtectionNoneResults | + Where-Object { $_.RecommendedExtendedProtection -eq $true }).Count | + Should -Be 2 # two values for Autodiscover + $extendedProtectionNoneResults.VirtualDirectoryName.Contains("Default Web Site/Autodiscover") | Should -Be $true + $extendedProtectionNoneResults.VirtualDirectoryName.Contains("Exchange Back End/Autodiscover") | Should -Be $true + $insecureNoneVirtualDirectories | + ForEach-Object { $extendedProtectionNoneResults.VirtualDirectoryName.Contains($_) | Should -Be $true } + + $notSupportedResults = $results.ExtendedProtectionConfiguration | + Where-Object { $_.SupportedExtendedProtection -eq $false } + $notSupportedResults.Count | Should -Be $notSupportedVirtualDirectories.Count + # even though we don't support these configuration, they are secure (overly secure) + $notSupportedResults | + Where-Object { $_.ProperlySecuredConfiguration -eq $false } | + Should -Be $null + $notSupportedResults | + Where-Object { $_.RecommendedExtendedProtection -eq $true } | + Should -Be $null + $notSupportedVirtualDirectories | + ForEach-Object { $notSupportedResults.VirtualDirectoryName.Contains($_) | Should -Be $true } + + $notProperlySecureResults = $results.ExtendedProtectionConfiguration | + Where-Object { $_.ProperlySecuredConfiguration -eq $false } + $notProperlySecureResults | + Where-Object { $_.RecommendedExtendedProtection -eq $true } | + Should -Be $null + $notProperlySecureResults.Count | Should -Be $insecureConfigurationVirtualDirectories.Count + $insecureConfigurationVirtualDirectories | + ForEach-Object { $notProperlySecureResults.VirtualDirectoryName.Contains($_) | Should -Be $true } + } + } + Context "Supported/Unsupported Versions Tests" { BeforeAll { function TestVersionSupportedOnly { From a38e6da27e18bb8ba40a8ce5e2b233fea793b1ec Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 28 Sep 2023 13:51:28 -0500 Subject: [PATCH 21/30] Add pester testing for HC not supported scenario --- .../Analyzer/Invoke-AnalyzerExchangeInformation.ps1 | 2 ++ .../HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 | 1 + 2 files changed, 3 insertions(+) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index 97ab55100b..f625d9ceac 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -389,6 +389,8 @@ function Invoke-AnalyzerExchangeInformation { Details = "$($entry.VirtualDirectoryName) - Current Value: '$($entry.ExtendedProtection)' Expected Value: '$expectedValue'" DisplayWriteType = "Yellow" DisplayCustomTabNumber = 2 + TestingName = "EP - $($entry.VirtualDirectoryName)" + DisplayTestingValue = ($entry.ExtendedProtection) } Add-AnalyzedResultInformation @params } diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 index bc073bf785..a0223373de 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 @@ -287,6 +287,7 @@ Describe "Testing Health Checker by Mock Data Imports" { It "Extended Protection Enabled" { SetActiveDisplayGrouping "Exchange Information" TestObjectMatch "Extended Protection Enabled (Any VDir)" $true + TestObjectMatch "EP - Default Web Site/OAB" "Require" -WriteType "Yellow" } It "Number of Processors" { From 1f201bf6779eb071a93f61c971575628e0d417e5 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 28 Sep 2023 14:07:38 -0500 Subject: [PATCH 22/30] Use -contains for the mitigationSupportedVDirs variable instead of Contains() and ToLower() --- Shared/Get-ExtendedProtectionConfiguration.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Shared/Get-ExtendedProtectionConfiguration.ps1 b/Shared/Get-ExtendedProtectionConfiguration.ps1 index 89628e4881..7d4657c76f 100644 --- a/Shared/Get-ExtendedProtectionConfiguration.ps1 +++ b/Shared/Get-ExtendedProtectionConfiguration.ps1 @@ -294,7 +294,7 @@ function Get-ExtendedProtectionConfiguration { # Add all vDirs for which the IP filtering mitigation is supported $mitigationSupportedVDirs = $MyInvocation.MyCommand.Parameters["SiteVDirLocations"].Attributes | Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] } | - ForEach-Object { return $_.ValidValues.ToLower() } + ForEach-Object { return $_.ValidValues } Write-Verbose "Supported mitigated virtual directories: $([string]::Join(",", $mitigationSupportedVDirs))" } process { @@ -368,7 +368,7 @@ function Get-ExtendedProtectionConfiguration { } elseif ($expectedExtendedConfiguration -eq "Require") { Write-Verbose "Checking to see if we have mitigations enabled for the supported vDirs" # Only care about virtual directories that we allow mitigation for - $properlySecuredConfiguration = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) -and + $properlySecuredConfiguration = $mitigationSupportedVDirs -contains $virtualDirectoryName -and $extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false" } elseif ($expectedExtendedConfiguration -eq "Allow") { Write-Verbose "Checking to see if Extended Protection is set to 'Require' to still be considered secure" @@ -397,7 +397,7 @@ function Get-ExtendedProtectionConfiguration { # While this is not the best security setting, it is lower and shouldn't cause a connectivity issue and should still be supported. SupportedExtendedProtection = $supportedExtendedConfiguration MitigationEnabled = ($extendedConfiguration.MitigationSettings.AllowUnlisted -eq "false") - MitigationSupported = $mitigationSupportedVDirs.Contains($virtualDirectoryName.ToLower()) + MitigationSupported = $mitigationSupportedVDirs -contains $virtualDirectoryName ExpectedSslFlags = $matchEntry.SslFlags SslFlagsSetCorrectly = $sslFlagsToSet.Split(",").Count -eq $currentSetFlags.Count SslFlagsToSet = $sslFlagsToSet From 88c4236989466b3ca1ee7b7dd43f3c880d720523 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 28 Sep 2023 14:48:48 -0500 Subject: [PATCH 23/30] updated extended protection doc to have note about OAB update --- docs/Security/Extended-Protection.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/Security/Extended-Protection.md b/docs/Security/Extended-Protection.md index fd0da69946..705a9090c2 100644 --- a/docs/Security/Extended-Protection.md +++ b/docs/Security/Extended-Protection.md @@ -183,6 +183,10 @@ Enabling Extended Protection involves making many changes on all Exchange server | Exchange Backend | MAPI/emsmdb | Required | Ssl,Ssl128 | | Exchange Backend | MAPI/nspi | Required | Ssl,Ssl128 | +!!! warning "Note" + + After initial release, we have updated `Default Website/OAB` to be `Accept/Allow` instead of `Required`. This is because of Outlook for Mac clients not being able to download the OAB any longer with the `Required` setting. + SSL offloading for Outlook Anywhere is enabled by default and must be disabled for extended protection by following the steps shown [here](https://docs.microsoft.com/powershell/module/exchange/set-outlookanywhere?view=exchange-ps#example-3). ### Enabling Extended Protection using the script From 327f06bb97ee523e0cd7694ab79dd5ece64223bd Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Thu, 5 Oct 2023 10:47:18 +0200 Subject: [PATCH 24/30] CVE-2023-36434 (TokenCacheModule) work --- .../Invoke-AnalyzerIISInformation.ps1 | 23 ++++++ .../Invoke-AnalyzerSecurityCve-2023-21709.ps1 | 48 ------------ .../Invoke-AnalyzerSecurityCve-2023-36434.ps1 | 76 +++++++++++++++++++ .../Invoke-AnalyzerSecurityCveCheck.ps1 | 4 +- .../Get-ExchangeServerIISSettings.ps1 | 23 ++++-- .../IIS/GetVersionInformationCachTokn.xml | 42 ++++++++++ .../IIS/GetVersionInformationCachTokn.xml | 42 ++++++++++ .../IIS/GetVersionInformationCachTokn.xml | 42 ++++++++++ .../Tests/HealthChecker.MockedCalls.Tests.ps1 | 2 +- ...thCheckerTest.CommonMocks.NotPublished.ps1 | 1 + 10 files changed, 246 insertions(+), 57 deletions(-) delete mode 100644 Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-21709.ps1 create mode 100644 Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/IIS/GetVersionInformationCachTokn.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/IIS/GetVersionInformationCachTokn.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachTokn.xml diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 index 633de9afec..4300da0d1e 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 @@ -171,4 +171,27 @@ function Invoke-AnalyzerIISInformation { } Add-AnalyzedResultInformation @params } + + ######################## + # IIS Module Information + ######################## + + Write-Verbose "Working on IIS Module information" + + # If TokenCacheModule is not loaded, we highlight that it could be added back again as Windows provided a fix to address CVE-2023-36434 (previously tracked as CVE-2023-21709) + if ($exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -notcontains "TokenCacheModule") { + Write-Verbose "TokenCacheModule wasn't detected (vulnerability mitigated) and as a result, system is not vulnerable to CVE-2023-21709 / CVE-2023-36434" + + $params = $baseParams + @{ + Name = "TokenCacheModule loaded" + Details = ("$false + `r`t`tThe module wasn't found and as a result, CVE-2023-36434 (previously tracked as CVE-2023-21709) is mitigated. Windows has released a Security Update that addresses the vulnerability. + `r`t`tIt should be installed on all Exchange servers and then, the TokenCacheModule can be added back to IIS (by running .\CVE-2023-21709.ps1 -Rollback). + `r`t`tMore Information: https://aka.ms/CVE-2023-21709ScriptDoc" + ) + DisplayWriteType = "Yellow" + AddHtmlDetailRow = $false + } + Add-AnalyzedResultInformation @params + } } diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-21709.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-21709.ps1 deleted file mode 100644 index 1f936ceff1..0000000000 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-21709.ps1 +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -. $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 -function Invoke-AnalyzerSecurityCve-2023-21709 { - [CmdletBinding()] - param( - [Parameter(Mandatory = $true)] - [ref]$AnalyzeResults, - - [Parameter(Mandatory = $true)] - [object]$SecurityObject, - - [Parameter(Mandatory = $true)] - [object]$DisplayGroupingKey - ) - - Write-Verbose "Calling: $($MyInvocation.MyCommand)" - - <# - Description: Check for CVE-2023-21709 vulnerability - Affected Exchange versions: 2016, 2019 - Fix: Remove TokenCacheModule from IIS - Workaround: N/A - #> - - if ($SecurityObject.IsEdgeServer -eq $false) { - Write-Verbose "Testing CVE: CVE-2023-21709" - - if ($SecurityObject.ExchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -contains "TokenCacheModule") { - Write-Verbose "TokenCacheModule detected - system is vulnerable to CVE-2023-21709 vulnerability" - $params = @{ - AnalyzedInformation = $AnalyzeResults - DisplayGroupingKey = $DisplayGroupingKey - Name = "Security Vulnerability" - Details = ("{0}`r`n`t`tSee: https://portal.msrc.microsoft.com/security-guidance/advisory/{0} for more information." -f "CVE-2023-21709") - DisplayWriteType = "Red" - DisplayTestingValue = "CVE-2023-21709" - AddHtmlDetailRow = $false - } - Add-AnalyzedResultInformation @params - } else { - Write-Verbose "TokenCacheModule wasn't detected and as a result, system is not vulnerable to CVE-2023-21709 vulnerability" - } - } else { - Write-Verbose "Edge Server Role is not affected by this vulnerability as it has no IIS installed" - } -} diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 new file mode 100644 index 0000000000..e97eb21b21 --- /dev/null +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 @@ -0,0 +1,76 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +function Invoke-AnalyzerSecurityCve-2023-36434 { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ref]$AnalyzeResults, + + [Parameter(Mandatory = $true)] + [object]$SecurityObject, + + [Parameter(Mandatory = $true)] + [object]$DisplayGroupingKey + ) + + <# + Description: Check for CVE-2023-36434 vulnerability (previously tracked as CVE-2023-21709) + Affected Exchange versions: 2016, 2019 + Fix: Install October 2023 Windows Security Update + Workaround: Remove TokenCacheModule from IIS by running the CVE-2023-21709.ps1 script + #> + + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $tokenCacheModuleVersionInformation = $SecurityObject.ExchangeInformation.IISSettings.IISTokenCacheModuleInformation + $tokenCacheFixedVersionNumber = $null + $tokenCacheVersionGreaterOrEqual = $false + } + process { + if ($SecurityObject.IsEdgeServer -eq $false) { + Write-Verbose "Testing CVE: CVE-2023-21709 / CVE-2023-36434" + + if ($SecurityObject.ExchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -contains "TokenCacheModule") { + Write-Verbose "TokenCacheModule detected - system could be vulnerable to CVE-2023-21709 / CVE-2023-36434 vulnerability" + + if ($null -ne $tokenCacheModuleVersionInformation) { + Write-Verbose "TokenCacheModule build information found - performing build analysis now..." + switch ($tokenCacheModuleVersionInformation.FileBuildPart) { + 9200 { $tokenCacheFixedVersionNumber = "8.0.9200.24514"; break } # Windows Server 2012 + 9600 { $tokenCacheFixedVersionNumber = "8.5.9600.21613"; break } # Windows Server 2012 R2 + 14393 { $tokenCacheFixedVersionNumber = "10.0.14393.6343"; break } # Windows Server 2016 + 17763 { $tokenCacheFixedVersionNumber = "10.0.17763.4968"; break } # Windows Server 2019 + 20348 { $tokenCacheFixedVersionNumber = "10.0.20348.2029"; break } # Windows Server 2022 + default { Write-Verbose "No fixed TokenCacheModule version available for Windows OS build: $($tokenCacheModuleVersionInformation.FileBuildPart)" } + } + + if ($null -ne $tokenCacheFixedVersionNumber) { + Write-Verbose "Build: $($tokenCacheModuleVersionInformation.FileBuildPart) found - testing against version: $tokenCacheFixedVersionNumber" + $tokenCacheVersionGreaterOrEqual = ([system.version]$tokenCacheModuleVersionInformation.ProductVersion -ge $tokenCacheFixedVersionNumber) + Write-Verbose "Version: $($tokenCacheModuleVersionInformation.ProductVersion) is greater or equal the expected version? $tokenCacheVersionGreaterOrEqual" + } + } else { + Write-Verbose "We were unable to query TokenCacheModule build information - as the module is loaded, we're assuming that it's vulnerable" + } + + if (($tokenCacheVersionGreaterOrEqual -eq $false) -or + ($null -eq $tokenCacheModuleVersionInformation)) { + $params = @{ + AnalyzedInformation = $AnalyzeResults + DisplayGroupingKey = $DisplayGroupingKey + Name = "Security Vulnerability" + Details = ("{0}`r`n`t`tSee: https://portal.msrc.microsoft.com/security-guidance/advisory/{0} for more information." -f "CVE-2023-36434") + DisplayWriteType = "Red" + DisplayTestingValue = "CVE-2023-36434" + AddHtmlDetailRow = $false + } + Add-AnalyzedResultInformation @params + } + } + } else { + Write-Verbose "Edge Server Role is not affected by this vulnerability as it has no IIS installed" + } + } +} diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 index 3e2de31382..24f648d7e6 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 @@ -6,7 +6,7 @@ . $PSScriptRoot\Invoke-AnalyzerSecurityCve-2021-1730.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityCve-2021-34470.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityCve-2022-21978.ps1 -. $PSScriptRoot\Invoke-AnalyzerSecurityCve-2023-21709.ps1 +. $PSScriptRoot\Invoke-AnalyzerSecurityCve-2023-36434.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityIISModules.ps1 @@ -202,7 +202,7 @@ function Invoke-AnalyzerSecurityCveCheck { Invoke-AnalyzerSecurityCve-2021-1730 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey Invoke-AnalyzerSecurityCve-2021-34470 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey Invoke-AnalyzerSecurityCve-2022-21978 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey - Invoke-AnalyzerSecurityCve-2023-21709 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey + Invoke-AnalyzerSecurityCve-2023-36434 -AnalyzeResults $AnalyzeResults -SecurityObject $securityObject -DisplayGroupingKey $DisplayGroupingKey Invoke-AnalyzerSecurityCve-MarchSuSpecial -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/DataCollection/ExchangeInformation/IISInformation/Get-ExchangeServerIISSettings.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/IISInformation/Get-ExchangeServerIISSettings.ps1 index 95dcec21a0..414e7c8540 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/IISInformation/Get-ExchangeServerIISSettings.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/IISInformation/Get-ExchangeServerIISSettings.ps1 @@ -39,6 +39,16 @@ function Get-ExchangeServerIISSettings { $webSite = Invoke-ScriptBlockHandler @params -ScriptBlock ${Function:Get-IISWebSite} -ArgumentList (, $exchangeWebSites) -ScriptBlockDescription "Get-IISWebSite" $webApplication = Invoke-ScriptBlockHandler @params -ScriptBlock ${Function:Get-IISWebApplication} -ScriptBlockDescription "Get-IISWebApplication" + # Get the TokenCacheModule build information as we need it to perform version testing + Write-Verbose "Trying to query TokenCacheModule version information" + $tokenCacheModuleParams = @{ + ComputerName = $Server + ScriptBlockDescription = "Get TokenCacheModule version information" + ScriptBlock = { [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$env:windir\System32\inetsrv\cachtokn.dll") } + CatchActionFunction = ${Function:Invoke-CatchActions} + } + $tokenCacheModuleVersionInformation = Invoke-ScriptBlockHandler @tokenCacheModuleParams + # Get the shared web configuration files $sharedWebConfigPaths = @($webApplication.ConfigurationFileInfo.LinkedConfigurationFilePath | Select-Object -Unique) $sharedWebConfig = $null @@ -97,12 +107,13 @@ function Get-ExchangeServerIISSettings { } } end { return [PSCustomObject]@{ - ApplicationHostConfig = $applicationHostConfig - IISModulesInformation = $iisModulesInformation - IISConfigurationSettings = $iisConfigurationSettings - IISWebSite = $webSite - IISWebApplication = $webApplication - IISSharedWebConfig = $sharedWebConfig + ApplicationHostConfig = $applicationHostConfig + IISModulesInformation = $iisModulesInformation + IISTokenCacheModuleInformation = $tokenCacheModuleVersionInformation + IISConfigurationSettings = $iisConfigurationSettings + IISWebSite = $webSite + IISWebApplication = $webApplication + IISSharedWebConfig = $sharedWebConfig } } } diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/IIS/GetVersionInformationCachTokn.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/IIS/GetVersionInformationCachTokn.xml new file mode 100644 index 0000000000..87d79fd8e9 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E15/Exchange/IIS/GetVersionInformationCachTokn.xml @@ -0,0 +1,42 @@ + + + + System.Diagnostics.FileVersionInfo + System.Object + + File: C:\windows\System32\inetsrv\cachtokn.dll_x000D__x000A_InternalName: cachtokn.dll_x000D__x000A_OriginalFilename: cachtokn.dll_x000D__x000A_FileVersion: 8.5.9600.0 (rs1_release.160715-1616)_x000D__x000A_FileDescription: token cache provider_x000D__x000A_Product: Internet Information Services_x000D__x000A_ProductVersion: 8.5.9600.0_x000D__x000A_Debug: False_x000D__x000A_Patched: False_x000D__x000A_PreRelease: False_x000D__x000A_PrivateBuild: False_x000D__x000A_SpecialBuild: False_x000D__x000A_Language: Language Neutral_x000D__x000A_ + + + Microsoft Corporation + 9600 + token cache provider + 8 + 5 + C:\windows\System32\inetsrv\cachtokn.dll + 0 + 8.5.9600.0 (rs1_release.160715-1616) + cachtokn.dll + false + false + false + false + false + Language Neutral + © Microsoft Corporation. All rights reserved. + + cachtokn.dll + + 9600 + 8 + 5 + Internet Information Services + 0 + 8.5.9600.0 + + + + 8.5.9600.0 + 8.5.9600.0 + + + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/IIS/GetVersionInformationCachTokn.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/IIS/GetVersionInformationCachTokn.xml new file mode 100644 index 0000000000..f77441e269 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E16/Exchange/IIS/GetVersionInformationCachTokn.xml @@ -0,0 +1,42 @@ + + + + System.Diagnostics.FileVersionInfo + System.Object + + File: C:\windows\System32\inetsrv\cachtokn.dll_x000D__x000A_InternalName: cachtokn.dll_x000D__x000A_OriginalFilename: cachtokn.dll_x000D__x000A_FileVersion: 10.0.14393.0 (rs1_release.160715-1616)_x000D__x000A_FileDescription: token cache provider_x000D__x000A_Product: Internet Information Services_x000D__x000A_ProductVersion: 10.0.14393.0_x000D__x000A_Debug: False_x000D__x000A_Patched: False_x000D__x000A_PreRelease: False_x000D__x000A_PrivateBuild: False_x000D__x000A_SpecialBuild: False_x000D__x000A_Language: Language Neutral_x000D__x000A_ + + + Microsoft Corporation + 14393 + token cache provider + 10 + 0 + C:\windows\System32\inetsrv\cachtokn.dll + 0 + 10.0.14393.0 (rs1_release.160715-1616) + cachtokn.dll + false + false + false + false + false + Language Neutral + © Microsoft Corporation. All rights reserved. + + cachtokn.dll + + 14393 + 10 + 0 + Internet Information Services + 0 + 10.0.14393.0 + + + + 10.0.14393.0 + 10.0.14393.0 + + + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachTokn.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachTokn.xml new file mode 100644 index 0000000000..69f60efe23 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachTokn.xml @@ -0,0 +1,42 @@ + + + + System.Diagnostics.FileVersionInfo + System.Object + + File: C:\windows\System32\inetsrv\cachtokn.dll_x000D__x000A_InternalName: cachtokn.dll_x000D__x000A_OriginalFilename: cachtokn.dll_x000D__x000A_FileVersion: 10.0.17763.0 (rs1_release.160715-1616)_x000D__x000A_FileDescription: token cache provider_x000D__x000A_Product: Internet Information Services_x000D__x000A_ProductVersion: 10.0.17763.0_x000D__x000A_Debug: False_x000D__x000A_Patched: False_x000D__x000A_PreRelease: False_x000D__x000A_PrivateBuild: False_x000D__x000A_SpecialBuild: False_x000D__x000A_Language: Language Neutral_x000D__x000A_ + + + Microsoft Corporation + 17763 + token cache provider + 10 + 0 + C:\windows\System32\inetsrv\cachtokn.dll + 0 + 10.0.17763.0 (rs1_release.160715-1616) + cachtokn.dll + false + false + false + false + false + Language Neutral + © Microsoft Corporation. All rights reserved. + + cachtokn.dll + + 17763 + 10 + 0 + Internet Information Services + 0 + 10.0.17763.0 + + + + 10.0.17763.0 + 10.0.17763.0 + + + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 index 68f8d2193b..7479679732 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 @@ -59,7 +59,7 @@ Describe "Testing Health Checker by Mock Data Imports" { # Assert-MockCalled Invoke-CatchActions -Exactly 1 Assert-MockCalled Get-WmiObjectHandler -Exactly 6 - Assert-MockCalled Invoke-ScriptBlockHandler -Exactly 4 + Assert-MockCalled Invoke-ScriptBlockHandler -Exactly 5 Assert-MockCalled Get-RemoteRegistryValue -Exactly 23 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 1152adda3e..fc9762b45b 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 @@ -29,6 +29,7 @@ Mock Get-WmiObjectHandler { Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Trying to get the System.Environment ProcessorCount" } -MockWith { return 4 } Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting Current Time Zone" } -MockWith { return "Pacific Standard Time" } Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Test EEMS pattern service connectivity" } -MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\WebRequest_GetExchangeMitigations.xml" } +Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Get TokenCacheModule version information" } -MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetVersionInformationCachTokn.xml" } # Handle IIS collection of files Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost.config" -Raw } From 1d171b2142c884d0f5090d03f44d670a342d2cac Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Thu, 5 Oct 2023 12:56:57 +0200 Subject: [PATCH 25/30] October 2023 SU information and vulnerabilities --- .../Security/Invoke-AnalyzerSecurityCveCheck.ps1 | 1 + .../Tests/HealthChecker.E16.Main.Tests.ps1 | 4 ++-- .../Tests/HealthChecker.E19.Main.Tests.ps1 | 2 +- Shared/Get-ExchangeBuildVersionInformation.ps1 | 12 ++++++------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 index 24f648d7e6..63906d8879 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 @@ -129,6 +129,7 @@ function Invoke-AnalyzerSecurityCveCheck { "Mar23SU" = (@(NewCveEntry ("CVE-2023-21707") $ex131619)) "Jun23SU" = (NewCveEntry @("CVE-2023-28310", "CVE-2023-32031") @($ex2016, $ex2019)) "Aug23SU" = (NewCveEntry @("CVE-2023-38181", "CVE-2023-38182", "CVE-2023-38185", "CVE-2023-35368", "CVE-2023-35388", "CVE-2023-36777", "CVE-2023-36757", "CVE-2023-36756", "CVE-2023-36745", "CVE-2023-36744") @($ex2016, $ex2019)) + "Oct23SU" = (NewCveEntry @("CVE-2023-36778") @($ex2016, $ex2019)) } # Need to organize the list so oldest CVEs come out first. diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 index 787c8c6ca5..348d179ff8 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 @@ -140,11 +140,11 @@ Describe "Testing Health Checker by Mock Data Imports - Exchange 2016" { $cveTests = GetObject "Security Vulnerability" $cveTests.Contains("CVE-2020-1147") | Should -Be $true - $cveTests.Count | Should -Be 44 + $cveTests.Count | Should -Be 45 $downloadDomains = GetObject "CVE-2021-1730" $downloadDomains.DownloadDomainsEnabled | Should -Be "false" - $Script:ActiveGrouping.Count | Should -Be 51 + $Script:ActiveGrouping.Count | Should -Be 52 } } diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 index ae5aabbe29..b8b1d4516c 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 @@ -146,7 +146,7 @@ Describe "Testing Health Checker by Mock Data Imports" { $cveTests = GetObject "Security Vulnerability" $cveTests.Contains("CVE-2020-1147") | Should -Be $true - $cveTests.Count | Should -Be 44 + $cveTests.Count | Should -Be 45 $downloadDomains = GetObject "CVE-2021-1730" $downloadDomains.DownloadDomainsEnabled | Should -Be "False" TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red" diff --git a/Shared/Get-ExchangeBuildVersionInformation.ps1 b/Shared/Get-ExchangeBuildVersionInformation.ps1 index 4aa68a9d92..7dba8a6010 100644 --- a/Shared/Get-ExchangeBuildVersionInformation.ps1 +++ b/Shared/Get-ExchangeBuildVersionInformation.ps1 @@ -127,16 +127,14 @@ function Get-ExchangeBuildVersionInformation { $cuReleaseDate = "05/03/2023" $supportedBuildNumber = $true } - (GetBuildVersion $ex19 "CU13" -SU "Aug23SUv2") { $latestSUBuild = $true } - (GetBuildVersion $ex19 "CU13" -SU "Aug23SU") { $latestSUBuild = $true } + (GetBuildVersion $ex19 "CU13" -SU "Oct23SU") { $latestSUBuild = $true } { $_ -lt (GetBuildVersion $ex19 "CU13") } { $cuLevel = "CU12" $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true $orgValue = 16760 } - (GetBuildVersion $ex19 "CU12" -SU "Aug23SUv2") { $latestSUBuild = $true } - (GetBuildVersion $ex19 "CU12" -SU "Aug23SU") { $latestSUBuild = $true } + (GetBuildVersion $ex19 "CU12" -SU "Oct23SU") { $latestSUBuild = $true } { $_ -lt (GetBuildVersion $ex19 "CU12") } { $cuLevel = "CU11" $cuReleaseDate = "09/28/2021" @@ -223,8 +221,7 @@ function Get-ExchangeBuildVersionInformation { $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true } - (GetBuildVersion $ex16 "CU23" -SU "Aug23SUv2") { $latestSUBuild = $true } - (GetBuildVersion $ex16 "CU23" -SU "Aug23SU") { $latestSUBuild = $true } + (GetBuildVersion $ex16 "CU23" -SU "Oct23SU") { $latestSUBuild = $true } { $_ -lt (GetBuildVersion $ex16 "CU23") } { $cuLevel = "CU22" $cuReleaseDate = "09/28/2021" @@ -706,6 +703,7 @@ function GetExchangeBuildDictionary { "Jun23SU" = "15.1.2507.27" "Aug23SU" = "15.1.2507.31" "Aug23SUv2" = "15.1.2507.32" + "Oct23SU" = "15.1.2507.34" }) } "Exchange2019" = @{ @@ -794,11 +792,13 @@ function GetExchangeBuildDictionary { "Jun23SU" = "15.2.1118.30" "Aug23SU" = "15.2.1118.36" "Aug23SUv2" = "15.2.1118.37" + "Oct23SU" = "15.2.1118.39" }) "CU13" = (NewCUAndSUObject "15.2.1258.12" @{ "Jun23SU" = "15.2.1258.16" "Aug23SU" = "15.2.1258.23" "Aug23SUv2" = "15.2.1258.25" + "Oct23SU" = "15.2.1258.27" }) } } From 934ca80ab30e67d7e63a8bfbfa56ad78acce1036 Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Fri, 6 Oct 2023 14:05:11 +0200 Subject: [PATCH 26/30] TokenCacheModule unit tests added --- .../GetIISModulesNoTokenCacheModule.xml | 667 ++++++++++++++++++ .../GetVersionInformationCachToknPatched.xml | 42 ++ .../HealthChecker.E19.Scenarios2.Tests.ps1 | 51 ++ 3 files changed, 760 insertions(+) create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIISModulesNoTokenCacheModule.xml create mode 100644 Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachToknPatched.xml diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIISModulesNoTokenCacheModule.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIISModulesNoTokenCacheModule.xml new file mode 100644 index 0000000000..a84159aa57 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/GetIISModulesNoTokenCacheModule.xml @@ -0,0 +1,667 @@ + + + + System.Management.Automation.PSCustomObject + System.Object + + + true + true + true + + + System.Object[] + System.Array + System.Object + + + + + + HttpLoggingModule + C:\Windows\System32\inetsrv\loghttp.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + System.Management.Automation.SignatureStatus + System.Enum + System.ValueType + System.Object + + Valid + 0 + + true + + + + + + + + UriCacheModule + C:\Windows\System32\inetsrv\cachuri.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + FileCacheModule + C:\Windows\System32\inetsrv\cachfile.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + HttpCacheModule + C:\Windows\System32\inetsrv\cachhttp.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + StaticCompressionModule + C:\Windows\System32\inetsrv\compstat.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + DefaultDocumentModule + C:\Windows\System32\inetsrv\defdoc.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + DirectoryListingModule + C:\Windows\System32\inetsrv\dirlist.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + ProtocolSupportModule + C:\Windows\System32\inetsrv\protsup.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + HttpRedirectionModule + C:\Windows\System32\inetsrv\redirect.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + StaticFileModule + C:\Windows\System32\inetsrv\static.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + AnonymousAuthenticationModule + C:\Windows\System32\inetsrv\authanon.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + CustomErrorModule + C:\Windows\System32\inetsrv\custerr.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + TracingModule + C:\Windows\System32\inetsrv\iisetw.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + FailedRequestsTracingModule + C:\Windows\System32\inetsrv\iisfreb.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + RequestMonitorModule + C:\Windows\System32\inetsrv\iisreqs.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + IsapiModule + C:\Windows\System32\inetsrv\isapi.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + RequestFilteringModule + C:\Windows\System32\inetsrv\modrqflt.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + IsapiFilterModule + C:\Windows\System32\inetsrv\filter.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + ManagedEngineV4.0_32bit + C:\Windows\Microsoft.NET\Framework\v4.0.30319\webengine4.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + ManagedEngineV4.0_64bit + C:\Windows\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + ConfigurationValidationModule + C:\Windows\System32\inetsrv\validcfg.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + BasicAuthenticationModule + C:\Windows\System32\inetsrv\authbas.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + WindowsAuthenticationModule + C:\Windows\System32\inetsrv\authsspi.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + DynamicCompressionModule + C:\Windows\System32\inetsrv\compdyn.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + CertificateMappingAuthenticationModule + C:\Windows\System32\inetsrv\authcert.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + DigestAuthenticationModule + C:\Windows\System32\inetsrv\authmd5.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + PasswordExpiryModule + C:\Windows\system32\rpcproxy\rpcproxy.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + kerbauth + F:\Program Files\Microsoft\Exchange\Bin\kerbauth.dll + true + + + + CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + WSMan + C:\Windows\system32\wsmsvc.dll + true + + + + CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + exppw + F:\Program Files\Microsoft\Exchange\ClientAccess\Owa\auth\exppw.dll + true + + + + CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + cafe_exppw + F:\Program Files\Microsoft\Exchange\FrontEnd\HttpProxy\bin\exppw.dll + true + + + + CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + RewriteModule + C:\Windows\system32\inetsrv\rewrite.dll + true + + + + CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US + + + Valid + 0 + + true + + + + + + + + + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachToknPatched.xml b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachToknPatched.xml new file mode 100644 index 0000000000..ed18d5cd98 --- /dev/null +++ b/Diagnostics/HealthChecker/Tests/DataCollection/E19/Exchange/IIS/GetVersionInformationCachToknPatched.xml @@ -0,0 +1,42 @@ + + + + System.Diagnostics.FileVersionInfo + System.Object + + File: C:\windows\System32\inetsrv\cachtokn.dll_x000D__x000A_InternalName: cachtokn.dll_x000D__x000A_OriginalFilename: cachtokn.dll_x000D__x000A_FileVersion: 10.0.17763.4968 (rs1_release.160715-1616)_x000D__x000A_FileDescription: token cache provider_x000D__x000A_Product: Internet Information Services_x000D__x000A_ProductVersion: 10.0.17763.4968_x000D__x000A_Debug: False_x000D__x000A_Patched: False_x000D__x000A_PreRelease: False_x000D__x000A_PrivateBuild: False_x000D__x000A_SpecialBuild: False_x000D__x000A_Language: Language Neutral_x000D__x000A_ + + + Microsoft Corporation + 17763 + token cache provider + 10 + 0 + C:\windows\System32\inetsrv\cachtokn.dll + 4968 + 10.0.17763.4968 (rs1_release.160715-1616) + cachtokn.dll + false + false + false + false + false + Language Neutral + © Microsoft Corporation. All rights reserved. + + cachtokn.dll + + 17763 + 10 + 0 + Internet Information Services + 4968 + 10.0.17763.4968 + + + + 10.0.17763.4968 + 10.0.17763.4968 + + + \ No newline at end of file diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 index 1c53d33f47..d0ae085d9c 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 @@ -175,4 +175,55 @@ Describe "Exchange 2019 Scenarios testing 2" { $multiPageFileWarning | Should -Be $true } } + + Context "Scenario 6" { + + It "TokenCacheModule loaded and vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { + + # We show the CVE entry as the system is vulnerable + SetActiveDisplayGrouping "Security Vulnerability" + $cveEntries = GetObject "Security Vulnerability" + $cveEntries.Contains("CVE-2023-36434") | Should -Be $true + + # We don't show the TokenCacheModule warning as the module is loaded + SetActiveDisplayGrouping "Exchange IIS Information" + $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" + $tokenCacheModuleInformation | Should -Be $null + } + + It "TokenCacheModule is loaded and cachtokn.dll is patched and not vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { + Mock Invoke-ScriptBlockHandler -ParameterFilter { + $ScriptBlockDescription -eq "Get TokenCacheModule version information" + } -MockWith { + return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetVersionInformationCachToknPatched.xml" + } + SetDefaultRunOfHealthChecker "Debug_TokenCacheModule_Loaded_And_Patched_Scenario6_Results.xml" + + # We don't show the CVE entry as cachtokn.dll is not vulnerable (build equal or greater than what we expect) + SetActiveDisplayGrouping "Security Vulnerability" + $cveEntries = GetObject "Security Vulnerability" + $cveEntries.Contains("CVE-2023-36434") | Should -Be $false + + # We don't show the TokenCacheModule warning as the module is loaded + SetActiveDisplayGrouping "Exchange IIS Information" + $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" + $tokenCacheModuleInformation | Should -Be $null + } + + It "TokenCacheModule not loaded and as a result, not vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { + Mock Get-IISModules { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetIISModulesNoTokenCacheModule.xml" } + SetDefaultRunOfHealthChecker "Debug_TokenCacheModule_Not_Loaded_Scenario6_Results.xml" + + # We don't show the CVE entry as the module is not loaded and so, the system is not vulnerable + SetActiveDisplayGrouping "Security Vulnerability" + $cveEntries = GetObject "Security Vulnerability" + $cveEntries.Contains("CVE-2023-36434") | Should -Be $false + + # We show the TokenCacheModule warning as the recommendation is to install the Windows SU and afterwards, adding the module back + SetActiveDisplayGrouping "Exchange IIS Information" + $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" + $tokenCacheModuleInformation | Should -Not -Be $null + $tokenCacheModuleInformation.Contains("False") | Should -Be $true + } + } } From c4ac05510515fa8b0be78eda92467bb9e68696ba Mon Sep 17 00:00:00 2001 From: David Paulson Date: Mon, 9 Oct 2023 08:32:18 -0500 Subject: [PATCH 27/30] Improved pester test results/speed and fixed minor code issues --- .../Invoke-AnalyzerIISInformation.ps1 | 13 +++-- .../Invoke-AnalyzerSecurityCve-2023-36434.ps1 | 3 +- .../Tests/HealthChecker.E19.Main.Tests.ps1 | 22 +++++++- .../HealthChecker.E19.Scenarios.Tests.ps1 | 9 ++++ .../HealthChecker.E19.Scenarios2.Tests.ps1 | 51 ------------------- 5 files changed, 39 insertions(+), 59 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 index 4300da0d1e..64223eaa03 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 @@ -179,18 +179,21 @@ function Invoke-AnalyzerIISInformation { Write-Verbose "Working on IIS Module information" # If TokenCacheModule is not loaded, we highlight that it could be added back again as Windows provided a fix to address CVE-2023-36434 (previously tracked as CVE-2023-21709) - if ($exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -notcontains "TokenCacheModule") { + if ($null -eq $exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name) { + Write-Verbose "Module List is null, unable to provide accurate check for this." + } elseif ($exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -notcontains "TokenCacheModule") { Write-Verbose "TokenCacheModule wasn't detected (vulnerability mitigated) and as a result, system is not vulnerable to CVE-2023-21709 / CVE-2023-36434" $params = $baseParams + @{ - Name = "TokenCacheModule loaded" - Details = ("$false + Name = "TokenCacheModule loaded" + Details = ("$false `r`t`tThe module wasn't found and as a result, CVE-2023-36434 (previously tracked as CVE-2023-21709) is mitigated. Windows has released a Security Update that addresses the vulnerability. `r`t`tIt should be installed on all Exchange servers and then, the TokenCacheModule can be added back to IIS (by running .\CVE-2023-21709.ps1 -Rollback). `r`t`tMore Information: https://aka.ms/CVE-2023-21709ScriptDoc" ) - DisplayWriteType = "Yellow" - AddHtmlDetailRow = $false + DisplayWriteType = "Yellow" + AddHtmlDetailRow = $false + DisplayTestingValue = $true } Add-AnalyzedResultInformation @params } diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 index e97eb21b21..18ae2f51dd 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 @@ -55,8 +55,7 @@ function Invoke-AnalyzerSecurityCve-2023-36434 { Write-Verbose "We were unable to query TokenCacheModule build information - as the module is loaded, we're assuming that it's vulnerable" } - if (($tokenCacheVersionGreaterOrEqual -eq $false) -or - ($null -eq $tokenCacheModuleVersionInformation)) { + if ($tokenCacheVersionGreaterOrEqual -eq $false) { $params = @{ AnalyzedInformation = $AnalyzeResults DisplayGroupingKey = $DisplayGroupingKey diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 index b8b1d4516c..dfd87bd7c0 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 @@ -146,12 +146,19 @@ Describe "Testing Health Checker by Mock Data Imports" { $cveTests = GetObject "Security Vulnerability" $cveTests.Contains("CVE-2020-1147") | Should -Be $true + $cveTests.Contains("CVE-2023-36434") | Should -Be $true $cveTests.Count | Should -Be 45 $downloadDomains = GetObject "CVE-2021-1730" $downloadDomains.DownloadDomainsEnabled | Should -Be "False" TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red" TestObjectMatch "Extended Protection Vulnerable Details" "Your Exchange server is at risk. Install the latest SU and enable Extended Protection" -WriteType "Red" } + + It "Display Results - Exchange IIS Information" { + SetActiveDisplayGrouping "Exchange IIS Information" + $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" + $tokenCacheModuleInformation | Should -Be $null # null because we are loaded and only display if we aren't loaded. + } } Context "Basic Exchange 2019 CU11 Testing Physical" { @@ -168,6 +175,7 @@ Describe "Testing Health Checker by Mock Data Imports" { Mock Get-WebConfigFile -ParameterFilter { $PSPath -eq "IIS:\Sites\Default Web Site" } -MockWith { return [PSCustomObject]@{ FullName = "$Script:MockDataCollectionRoot\Exchange\IIS\DefaultWebSite_web2.config" } } Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw } Mock Get-DynamicDistributionGroup { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetDynamicDistributionGroupPfMailboxes1.xml" } + Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Get TokenCacheModule version information" } -MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetVersionInformationCachToknPatched.xml" } SetDefaultRunOfHealthChecker "Debug_Physical_Results.xml" } @@ -232,11 +240,23 @@ Describe "Testing Health Checker by Mock Data Imports" { TestObjectMatch "SerializedDataSigning Enabled" "False" -WriteType "Yellow" } - It "Extended Protection" { + It "Display Results - Security Vulnerability" { SetActiveDisplayGrouping "Security Vulnerability" + + $cveEntries = GetObject "Security Vulnerability" + $cveEntries.Contains("CVE-2023-36434") | Should -Be $false # false because loaded module with greater than patch value. + } + + It "Extended Protection" { TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red" TestObjectMatch "Extended Protection Vulnerable Details" "Extended Protection isn't configured as expected" -WriteType "Red" } + + It "Display Results - Exchange IIS Information" { + SetActiveDisplayGrouping "Exchange IIS Information" + $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" + $tokenCacheModuleInformation | Should -Be $null # null because we are loaded + } } Context "Testing Throws" { diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 index a0223373de..3b6d070d9d 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 @@ -42,6 +42,7 @@ Describe "Testing Health Checker by Mock Data Imports" { Mock Get-WebConfigFile -ParameterFilter { $PSPath -eq "IIS:\Sites\Default Web Site/ecp" } -MockWith { return [PSCustomObject]@{ FullName = "$Script:MockDataCollectionRoot\Exchange\IIS\DefaultWebSite_web.config" } } Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost1.config" -Raw } Mock Get-ExchangeDiagnosticInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetExchangeDiagnosticInfo1.xml" } + Mock Get-IISModules { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetIISModulesNoTokenCacheModule.xml" } Mock Get-Service { param( [string]$ComputerName, @@ -186,6 +187,14 @@ Describe "Testing Health Checker by Mock Data Imports" { TestObjectMatch "Pattern service" "200 - Reachable" TestObjectMatch "Telemetry enabled" "False" } + + It "CVE-2023-36434 Test - Module Not loaded" { + SetActiveDisplayGrouping "Security Vulnerability" + $cveEntries = GetObject "Security Vulnerability" + $cveEntries.Contains("CVE-2023-36434") | Should -Be $false # false because it isn't loaded. + SetActiveDisplayGrouping "Exchange IIS Information" + TestObjectMatch "TokenCacheModule loaded" $true -WriteType "Yellow" + } } Context "Checking Scenarios 2" { diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 index d0ae085d9c..1c53d33f47 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios2.Tests.ps1 @@ -175,55 +175,4 @@ Describe "Exchange 2019 Scenarios testing 2" { $multiPageFileWarning | Should -Be $true } } - - Context "Scenario 6" { - - It "TokenCacheModule loaded and vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { - - # We show the CVE entry as the system is vulnerable - SetActiveDisplayGrouping "Security Vulnerability" - $cveEntries = GetObject "Security Vulnerability" - $cveEntries.Contains("CVE-2023-36434") | Should -Be $true - - # We don't show the TokenCacheModule warning as the module is loaded - SetActiveDisplayGrouping "Exchange IIS Information" - $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" - $tokenCacheModuleInformation | Should -Be $null - } - - It "TokenCacheModule is loaded and cachtokn.dll is patched and not vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { - Mock Invoke-ScriptBlockHandler -ParameterFilter { - $ScriptBlockDescription -eq "Get TokenCacheModule version information" - } -MockWith { - return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetVersionInformationCachToknPatched.xml" - } - SetDefaultRunOfHealthChecker "Debug_TokenCacheModule_Loaded_And_Patched_Scenario6_Results.xml" - - # We don't show the CVE entry as cachtokn.dll is not vulnerable (build equal or greater than what we expect) - SetActiveDisplayGrouping "Security Vulnerability" - $cveEntries = GetObject "Security Vulnerability" - $cveEntries.Contains("CVE-2023-36434") | Should -Be $false - - # We don't show the TokenCacheModule warning as the module is loaded - SetActiveDisplayGrouping "Exchange IIS Information" - $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" - $tokenCacheModuleInformation | Should -Be $null - } - - It "TokenCacheModule not loaded and as a result, not vulnerable to CVE-2023-36434 (previously CVE-2023-21709)" { - Mock Get-IISModules { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetIISModulesNoTokenCacheModule.xml" } - SetDefaultRunOfHealthChecker "Debug_TokenCacheModule_Not_Loaded_Scenario6_Results.xml" - - # We don't show the CVE entry as the module is not loaded and so, the system is not vulnerable - SetActiveDisplayGrouping "Security Vulnerability" - $cveEntries = GetObject "Security Vulnerability" - $cveEntries.Contains("CVE-2023-36434") | Should -Be $false - - # We show the TokenCacheModule warning as the recommendation is to install the Windows SU and afterwards, adding the module back - SetActiveDisplayGrouping "Exchange IIS Information" - $tokenCacheModuleInformation = GetObject "TokenCacheModule loaded" - $tokenCacheModuleInformation | Should -Not -Be $null - $tokenCacheModuleInformation.Contains("False") | Should -Be $true - } - } } From a10b1771d0d38003f2b56549c62338b23efbc521 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 10 Oct 2023 10:43:41 -0500 Subject: [PATCH 28/30] Update wording about the two CVEs for TokenModule --- .../HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 | 4 ++-- .../Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 index 64223eaa03..a9f6391992 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 @@ -178,7 +178,7 @@ function Invoke-AnalyzerIISInformation { Write-Verbose "Working on IIS Module information" - # If TokenCacheModule is not loaded, we highlight that it could be added back again as Windows provided a fix to address CVE-2023-36434 (previously tracked as CVE-2023-21709) + # If TokenCacheModule is not loaded, we highlight that it could be added back again as Windows provided a fix to address CVE-2023-36434 (also tracked as CVE-2023-21709) if ($null -eq $exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name) { Write-Verbose "Module List is null, unable to provide accurate check for this." } elseif ($exchangeInformation.IISSettings.IISModulesInformation.ModuleList.Name -notcontains "TokenCacheModule") { @@ -187,7 +187,7 @@ function Invoke-AnalyzerIISInformation { $params = $baseParams + @{ Name = "TokenCacheModule loaded" Details = ("$false - `r`t`tThe module wasn't found and as a result, CVE-2023-36434 (previously tracked as CVE-2023-21709) is mitigated. Windows has released a Security Update that addresses the vulnerability. + `r`t`tThe module wasn't found and as a result, CVE-2023-21709 and CVE-2023-36434 are mitigated. Windows has released a Security Update that addresses the vulnerability. `r`t`tIt should be installed on all Exchange servers and then, the TokenCacheModule can be added back to IIS (by running .\CVE-2023-21709.ps1 -Rollback). `r`t`tMore Information: https://aka.ms/CVE-2023-21709ScriptDoc" ) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 index 18ae2f51dd..9618e2bbf6 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2023-36434.ps1 @@ -16,7 +16,7 @@ function Invoke-AnalyzerSecurityCve-2023-36434 { ) <# - Description: Check for CVE-2023-36434 vulnerability (previously tracked as CVE-2023-21709) + Description: Check for CVE-2023-36434 vulnerability (also tracked as CVE-2023-21709) Affected Exchange versions: 2016, 2019 Fix: Install October 2023 Windows Security Update Workaround: Remove TokenCacheModule from IIS by running the CVE-2023-21709.ps1 script From 942404347fb827b59a273e0499a4342d67e12c04 Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Fri, 6 Oct 2023 15:01:41 +0200 Subject: [PATCH 29/30] CVE-2023-21709 update to reflect October 23 SU --- Security/src/CVE-2023-21709/CVE-2023-21709.ps1 | 9 +++++---- docs/Security/CVE-2023-21709.md | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 b/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 index d68c738502..dd04763f9c 100644 --- a/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 +++ b/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 @@ -125,12 +125,13 @@ begin { try { $iisAppPoolWording = "Note that each Exchange server's IIS Application Pool will be restarted after either applying the setting change or restore action." - $vulnerabilityMoreInformationWording = "More information about the vulnerability can be found here: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-21709." + $vulnerabilityMoreInformationWording = "More information about the vulnerability can be found here: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-36434." if (-not($Rollback)) { $params = @{ Message = "Display Warning about TokenCacheModule removal operation" - Target = "Removal of TokenCacheModule from IIS is recommended for security reasons. " + - "Removal of this module might have performance impact during first logon after cache is removed for OWA/ECP and Exchange Active Sync clients. " + + Target = "Removal of TokenCacheModule from IIS can be done to mitigate CVE-2023-36434 (previously CVE-2023-21709) vulnerability. " + + "The recommended solution to address CVE-2023-36434 is to install the Windows Server October 2023 Security Update." + + "`r`nRemoval of this module might have performance impact during first logon after cache is removed for OWA/ECP and Exchange Active Sync clients. " + "$iisAppPoolWording" + "`r`n$vulnerabilityMoreInformationWording" + "`r`nDo you want to proceed?" @@ -139,7 +140,7 @@ begin { } else { $params = @{ Message = "Display Warning about TokenCacheModule rollback operation" - Target = "TokenCacheModule will be restored in IIS. This makes the system vulnerable to the CVE-2023-21709 vulnerability again. " + + Target = "TokenCacheModule will be restored in IIS. This makes the system vulnerable to the CVE-2023-36434 (previously CVE-2023-21709) again if the Windows Server October 2023 Windows Security Update was not installed before. " + "$iisAppPoolWording" + "`r`n$vulnerabilityMoreInformationWording" + "`r`nDo you want to proceed?" diff --git a/docs/Security/CVE-2023-21709.md b/docs/Security/CVE-2023-21709.md index f2ca964f14..e2f903abe6 100644 --- a/docs/Security/CVE-2023-21709.md +++ b/docs/Security/CVE-2023-21709.md @@ -2,7 +2,12 @@ Download the latest release: [CVE-2023-21709.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/CVE-2023-21709.ps1) -The `CVE-2023-21709.ps1` script can be used to address the Exchange Server vulnerability `CVE-2023-21709` by removing the `TokenCacheModule` from IIS. It can also be used to restore a previously removed `TokenCacheModule`. +!!! warning "Note" + + Microsoft has released the Windows Server October 2023 Security Update (SU) to address the TokenCacheModule vulnerability. + While the script can still be used to mitigate the vulnerability, the recommended solution is to install the Windows Server October 2023 SU instead. The update and more information can be found here: [CVE-2023-36434](https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-36434) + +The `CVE-2023-21709.ps1` script can be used to mitigate the Exchange Server vulnerability `CVE-2023-36434` (previously `CVE-2023-21709`) by removing the `TokenCacheModule` from IIS. It can also be used to restore a previously removed `TokenCacheModule`. The script allows you to explicitly specify a subset of Exchange servers on which the `TokenCacheModule` should be removed or restored. It's also possible to exclude a subset of Exchange servers from the operation performed by the script. ## Requirements From c379bbac563d2cb27230e52187e301b63506486a Mon Sep 17 00:00:00 2001 From: Lukas Sassl Date: Mon, 9 Oct 2023 17:55:09 +0200 Subject: [PATCH 30/30] Wording adjusted --- Security/src/CVE-2023-21709/CVE-2023-21709.ps1 | 6 +++--- docs/Security/CVE-2023-21709.md | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 b/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 index dd04763f9c..5a53e88c31 100644 --- a/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 +++ b/Security/src/CVE-2023-21709/CVE-2023-21709.ps1 @@ -129,8 +129,8 @@ begin { if (-not($Rollback)) { $params = @{ Message = "Display Warning about TokenCacheModule removal operation" - Target = "Removal of TokenCacheModule from IIS can be done to mitigate CVE-2023-36434 (previously CVE-2023-21709) vulnerability. " + - "The recommended solution to address CVE-2023-36434 is to install the Windows Server October 2023 Security Update." + + Target = "Removal of TokenCacheModule from IIS can be done to mitigate CVE-2023-21709 and CVE-2023-36434 vulnerability. " + + "The recommended solution to address those is to install the Windows Server October 2023 security update (or later)." + "`r`nRemoval of this module might have performance impact during first logon after cache is removed for OWA/ECP and Exchange Active Sync clients. " + "$iisAppPoolWording" + "`r`n$vulnerabilityMoreInformationWording" + @@ -140,7 +140,7 @@ begin { } else { $params = @{ Message = "Display Warning about TokenCacheModule rollback operation" - Target = "TokenCacheModule will be restored in IIS. This makes the system vulnerable to the CVE-2023-36434 (previously CVE-2023-21709) again if the Windows Server October 2023 Windows Security Update was not installed before. " + + Target = "TokenCacheModule will be restored in IIS. This makes the system vulnerable to the CVE-2023-21709 and CVE-2023-36434 again if the Windows Server October 2023 security update (or later) was not installed before. " + "$iisAppPoolWording" + "`r`n$vulnerabilityMoreInformationWording" + "`r`nDo you want to proceed?" diff --git a/docs/Security/CVE-2023-21709.md b/docs/Security/CVE-2023-21709.md index e2f903abe6..750bdc90bb 100644 --- a/docs/Security/CVE-2023-21709.md +++ b/docs/Security/CVE-2023-21709.md @@ -4,10 +4,15 @@ Download the latest release: [CVE-2023-21709.ps1](https://github.com/microsoft/C !!! warning "Note" - Microsoft has released the Windows Server October 2023 Security Update (SU) to address the TokenCacheModule vulnerability. - While the script can still be used to mitigate the vulnerability, the recommended solution is to install the Windows Server October 2023 SU instead. The update and more information can be found here: [CVE-2023-36434](https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-36434) + Microsoft has released the Windows Server October 2023 security update to address the TokenCacheModule vulnerability. + While the script can still be used to mitigate the vulnerability, the recommended solution is to install the Windows Server October 2023 (or later) security update instead. The update and more information can be found here: [CVE-2023-36434](https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-36434) + +The `CVE-2023-21709.ps1` script can be used to mitigate the `CVE-2023-21709` and `CVE-2023-36434` vulnerability by removing the `TokenCacheModule` from IIS. It can also be used to restore a previously removed `TokenCacheModule`. + +!!! warning "Note" + + The script doesn't perform any check if the Windows Server October 2023 (or later) security update has been installed before restoring the TokenCacheModule. Make sure to install the update before restoring the module. -The `CVE-2023-21709.ps1` script can be used to mitigate the Exchange Server vulnerability `CVE-2023-36434` (previously `CVE-2023-21709`) by removing the `TokenCacheModule` from IIS. It can also be used to restore a previously removed `TokenCacheModule`. The script allows you to explicitly specify a subset of Exchange servers on which the `TokenCacheModule` should be removed or restored. It's also possible to exclude a subset of Exchange servers from the operation performed by the script. ## Requirements