From 94734dea7ba5089e796e46f82b00d01efae23217 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 09:09:58 -0600 Subject: [PATCH 01/33] Rename Get-TimeZoneInformationRegistrySettings --- ...nformationRegistrySettings.ps1 => Get-TimeZoneInformation.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Diagnostics/HealthChecker/DataCollection/ServerInformation/{Get-TimeZoneInformationRegistrySettings.ps1 => Get-TimeZoneInformation.ps1} (100%) diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformationRegistrySettings.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 similarity index 100% rename from Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformationRegistrySettings.ps1 rename to Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 From 91cf46b216f4faebd3fa48447880d657940a2785 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 09:43:33 -0600 Subject: [PATCH 02/33] Removed OS Class from HC --- .../Analyzer/Invoke-AnalyzerEngine.ps1 | 2 +- ...ke-AnalyzerFrequentConfigurationIssues.ps1 | 2 +- .../Get-HealthCheckerExchangeServer.ps1 | 13 +- .../Get-CredentialGuardEnabled.ps1 | 23 ---- .../Get-NETFrameworkInformation.ps1 | 31 +++++ .../Get-NetworkingInformation.ps1 | 36 ++++++ .../Get-OperatingSystemBuildInformation.ps1 | 25 ++++ .../Get-OperatingSystemInformation.ps1 | 115 +++++++----------- .../Get-OperatingSystemRegistryValues.ps1 | 6 + .../Get-PowerPlanSetting.ps1 | 37 ++++++ .../Get-TimeZoneInformation.ps1 | 27 +++- Diagnostics/HealthChecker/Helpers/Class.ps1 | 93 +------------- 12 files changed, 207 insertions(+), 203 deletions(-) delete mode 100644 Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-CredentialGuardEnabled.ps1 create mode 100644 Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NETFrameworkInformation.ps1 create mode 100644 Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 create mode 100644 Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 create mode 100644 Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-PowerPlanSetting.ps1 diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 index 5dd128cf6b..a1370d4e16 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 @@ -16,7 +16,7 @@ . $PSScriptRoot\Security\Invoke-AnalyzerSecurityVulnerability.ps1 function Invoke-AnalyzerEngine { param( - [HealthChecker.HealthCheckerExchangeServer]$HealthServerObject + [object]$HealthServerObject ) Write-Verbose "Calling: $($MyInvocation.MyCommand)" diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 index 8aaf2d367d..59f096ff4b 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 @@ -106,7 +106,7 @@ function Invoke-AnalyzerFrequentConfigurationIssues { } Add-AnalyzedResultInformation @params - $displayValue = $osInformation.CredentialGuardEnabled + $displayValue = $osInformation.RegistryValues.CredentialGuard -ne 0 $displayWriteType = "Grey" if ($osInformation.CredentialGuardEnabled) { diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 index d8c94ebc79..6f4451737a 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 @@ -23,17 +23,10 @@ function Get-HealthCheckerExchangeServer { $HealthExSvrObj.OSInformation = Get-OperatingSystemInformation -Server $ServerName $HealthExSvrObj.ExchangeInformation = Get-ExchangeInformation -Server $ServerName -OSMajorVersion $HealthExSvrObj.OSInformation.BuildInformation.MajorVersion -PassedOrganizationInformation $PassedOrganizationInformation - if ($HealthExSvrObj.ExchangeInformation.BuildInformation.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2013) { - $netFrameworkVersion = Get-NETFrameworkVersion -MachineName $ServerName -CatchActionFunction ${Function:Invoke-CatchActions} - $HealthExSvrObj.OSInformation.NETFramework.FriendlyName = $netFrameworkVersion.FriendlyName - $HealthExSvrObj.OSInformation.NETFramework.RegistryValue = $netFrameworkVersion.RegistryValue - $HealthExSvrObj.OSInformation.NETFramework.NetMajorVersion = $netFrameworkVersion.MinimumValue - $HealthExSvrObj.OSInformation.NETFramework.FileInformation = Get-DotNetDllFileVersions -ComputerName $ServerName -FileNames @("System.Data.dll", "System.Configuration.dll") -CatchActionFunction ${Function:Invoke-CatchActions} - - if ($netFrameworkVersion.MinimumValue -eq $HealthExSvrObj.ExchangeInformation.NETFramework.MaxSupportedVersion) { - $HealthExSvrObj.ExchangeInformation.NETFramework.OnRecommendedVersion = $true - } + if ($HealthExSvrObj.OSInformation.NETFramework.MajorVersion -eq $HealthExSvrObj.ExchangeInformation.NETFramework.MaxSupportedVersion) { + $HealthExSvrObj.ExchangeInformation.NETFramework.OnRecommendedVersion = $true } + $HealthExSvrObj.HealthCheckerVersion = $BuildVersion $HealthExSvrObj.GenerationTime = [DateTime]::Now Write-Verbose "Finished building health Exchange Server Object for server: $ServerName" diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-CredentialGuardEnabled.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-CredentialGuardEnabled.ps1 deleted file mode 100644 index bf724c4fe1..0000000000 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-CredentialGuardEnabled.ps1 +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -. $PSScriptRoot\..\..\..\..\Shared\Get-RemoteRegistryValue.ps1 -function Get-CredentialGuardEnabled { - param( - [Parameter(Mandatory = $true)] - [string]$Server - ) - - Write-Verbose "Calling: $($MyInvocation.MyCommand)" - $registryValue = Get-RemoteRegistryValue -MachineName $Server ` - -SubKey "SYSTEM\CurrentControlSet\Control\LSA" ` - -GetValue "LsaCfgFlags" ` - -CatchActionFunction ${Function:Invoke-CatchActions} - - if ($null -ne $registryValue -and - $registryValue -ne 0) { - return $true - } - - return $false -} diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NETFrameworkInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NETFrameworkInformation.ps1 new file mode 100644 index 0000000000..7065383106 --- /dev/null +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NETFrameworkInformation.ps1 @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\Get-DotNetDllFileVersions.ps1 +. $PSScriptRoot\..\..\..\..\Shared\ErrorMonitorFunctions.ps1 +. $PSScriptRoot\..\..\..\..\Shared\Get-NETFrameworkVersion.ps1 + +function Get-NETFrameworkInformation { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Server + ) + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $params = @{ + ComputerName = $Server + FileNames = @("System.Data.dll", "System.Configuration.dll") + CatchActionFunction = ${Function:Invoke-CatchActions} + } + $fileInformation = Get-DotNetDllFileVersions @params + $netFramework = Get-NETFrameworkVersion -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + } end { + return [PSCustomObject]@{ + MajorVersion = $netFramework.MinimumValue + RegistryValue = $netFramework.RegistryValue + FriendlyName = $netFramework.FriendlyName + FileInformation = $fileInformation + } + } +} diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 new file mode 100644 index 0000000000..4fdc8d5ac3 --- /dev/null +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 @@ -0,0 +1,36 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\Get-AllNicInformation.ps1 +. $PSScriptRoot\Get-HttpProxySetting.ps1 +. $PSScriptRoot\..\..\Helpers\PerformanceCountersFunctions.ps1 + +function Get-NetworkingInformation { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Server + ) + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $ipv6DisabledOnNICs = $false + } process { + $httpProxy = Get-HttpProxySetting -Server $Server + $packetsReceivedDiscarded = (Get-LocalizedCounterSamples -MachineName $Server -Counter "\Network Interface(*)\Packets Received Discarded") + $networkAdapters = @(Get-AllNicInformation -ComputerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} -ComputerFQDN $ServerFQDN) + + foreach ($adapter in $networkAdapters) { + if (-not ($adapter.IPv6Enabled)) { + $ipv6DisabledOnNICs = $true + break + } + } + } end { + return [PSCustomObject]@{ + HttpProxy = $httpProxy + PacketsReceivedDiscarded = $packetsReceivedDiscarded + NetworkAdapters = $networkAdapters + IPv6DisabledOnNICs = $ipv6DisabledOnNICs + } + } +} diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 new file mode 100644 index 0000000000..4f5502af59 --- /dev/null +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 @@ -0,0 +1,25 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\..\..\..\..\Shared\ErrorMonitorFunctions.ps1 +. $PSScriptRoot\Get-ServerOperatingSystemVersion.ps1 +. $PSScriptRoot\Get-WmiObjectCriticalHandler.ps1 + +function Get-OperatingSystemBuildInformation { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Server + ) + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $win32_OperatingSystem = Get-WmiObjectCriticalHandler -ComputerName $Server -Class Win32_OperatingSystem -CatchActionFunction ${Function:Invoke-CatchActions} + } end { + return [PSCustomObject]@{ + VersionBuild = $win32_OperatingSystem.Version + MajorVersion = (Get-ServerOperatingSystemVersion -OsCaption $win32_OperatingSystem.Caption) + FriendlyName = $win32_OperatingSystem.Caption + OperatingSystem = $win32_OperatingSystem + } + } +} diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 index 45a4263ad7..0bb7fa8444 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 @@ -1,92 +1,65 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -. $PSScriptRoot\..\..\..\..\Shared\Get-RemoteRegistryValue.ps1 . $PSScriptRoot\..\..\..\..\Shared\Get-ServerRebootPending.ps1 . $PSScriptRoot\..\..\..\..\Shared\VisualCRedistributableVersionFunctions.ps1 -. $PSScriptRoot\..\..\..\..\Shared\Invoke-ScriptBlockHandler.ps1 . $PSScriptRoot\..\..\..\..\Shared\TLS\Get-AllTlsSettings.ps1 . $PSScriptRoot\Get-AllNicInformation.ps1 -. $PSScriptRoot\Get-CredentialGuardEnabled.ps1 -. $PSScriptRoot\Get-HttpProxySetting.ps1 +. $PSScriptRoot\Get-NETFrameworkInformation.ps1 +. $PSScriptRoot\Get-NetworkingInformation.ps1 +. $PSScriptRoot\Get-OperatingSystemBuildInformation.ps1 . $PSScriptRoot\Get-OperatingSystemRegistryValues.ps1 . $PSScriptRoot\Get-PageFileInformation.ps1 -. $PSScriptRoot\Get-ServerOperatingSystemVersion.ps1 +. $PSScriptRoot\Get-PowerPlanSetting.ps1 . $PSScriptRoot\Get-Smb1ServerSettings.ps1 -. $PSScriptRoot\Get-TimeZoneInformationRegistrySettings.ps1 -. $PSScriptRoot\Get-WmiObjectCriticalHandler.ps1 -. $PSScriptRoot\Get-WmiObjectHandler.ps1 -. $PSScriptRoot\..\..\Helpers\PerformanceCountersFunctions.ps1 +. $PSScriptRoot\Get-TimeZoneInformation.ps1 + function Get-OperatingSystemInformation { param( [Parameter(Mandatory = $true)] [string]$Server ) - Write-Verbose "Calling: $($MyInvocation.MyCommand)" - - [HealthChecker.OperatingSystemInformation]$osInformation = New-Object HealthChecker.OperatingSystemInformation - $win32_OperatingSystem = Get-WmiObjectCriticalHandler -ComputerName $Server -Class Win32_OperatingSystem -CatchActionFunction ${Function:Invoke-CatchActions} - $win32_PowerPlan = Get-WmiObjectHandler -ComputerName $Server -Class Win32_PowerPlan -Namespace 'root\ciMv2\power' -Filter "isActive='true'" -CatchActionFunction ${Function:Invoke-CatchActions} - $currentDateTime = Get-Date - $lastBootUpTime = [Management.ManagementDateTimeConverter]::ToDateTime($win32_OperatingSystem.LastBootUpTime) - $osInformation.BuildInformation.VersionBuild = $win32_OperatingSystem.Version - $osInformation.BuildInformation.MajorVersion = (Get-ServerOperatingSystemVersion -OsCaption $win32_OperatingSystem.Caption) - $osInformation.BuildInformation.FriendlyName = $win32_OperatingSystem.Caption - $osInformation.BuildInformation.OperatingSystem = $win32_OperatingSystem - $osInformation.ServerBootUp.Days = ($currentDateTime - $lastBootUpTime).Days - $osInformation.ServerBootUp.Hours = ($currentDateTime - $lastBootUpTime).Hours - $osInformation.ServerBootUp.Minutes = ($currentDateTime - $lastBootUpTime).Minutes - $osInformation.ServerBootUp.Seconds = ($currentDateTime - $lastBootUpTime).Seconds - - if ($null -ne $win32_PowerPlan) { - - if ($win32_PowerPlan.InstanceID -eq "Microsoft:PowerPlan\{8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}") { - Write-Verbose "High Performance Power Plan is set to true" - $osInformation.PowerPlan.HighPerformanceSet = $true - } else { Write-Verbose "High Performance Power Plan is NOT set to true" } - $osInformation.PowerPlan.PowerPlanSetting = $win32_PowerPlan.ElementName - } else { - Write-Verbose "Power Plan Information could not be read" - $osInformation.PowerPlan.PowerPlanSetting = "N/A" - } - $osInformation.PowerPlan.PowerPlan = $win32_PowerPlan - $osInformation.PageFile = Get-PageFileInformation -Server $Server - $osInformation.NetworkInformation.NetworkAdapters = (Get-AllNicInformation -ComputerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} -ComputerFQDN $ServerFQDN) - foreach ($adapter in $osInformation.NetworkInformation.NetworkAdapters) { + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" - if (!$adapter.IPv6Enabled) { - $osInformation.NetworkInformation.IPv6DisabledOnNICs = $true - break + $buildInformation = Get-OperatingSystemBuildInformation -Server $Server + $currentDateTime = Get-Date + $lastBootUpTime = [Management.ManagementDateTimeConverter]::ToDateTime($buildInformation.OperatingSystem.LastBootUpTime) + $serverBootUp = [PSCustomObject]@{ + Days = ($currentDateTime - $lastBootUpTime).Days + Hours = ($currentDateTime - $lastBootUpTime).Hours + Minutes = ($currentDateTime - $lastBootUpTime).Minutes + Seconds = ($currentDateTime - $lastBootUpTime).Seconds } - } - - $osInformation.NetworkInformation.HttpProxy = Get-HttpProxySetting -Server $Server - $osInformation.InstalledUpdates.HotFixes = (Get-HotFix -ComputerName $Server -ErrorAction SilentlyContinue) #old school check still valid and faster and a failsafe - $counterSamples = (Get-LocalizedCounterSamples -MachineName $Server -Counter "\Network Interface(*)\Packets Received Discarded") - if ($null -ne $counterSamples) { - $osInformation.NetworkInformation.PacketsReceivedDiscarded = $counterSamples + $powerPlan = Get-PowerPlanSetting -Server $Server + $pageFile = Get-PageFileInformation -Server $Server + $networkInformation = Get-NetworkingInformation -Server $Server + $hotFixes = (Get-HotFix -ComputerName $Server -ErrorAction SilentlyContinue) #old school check still valid and faster and a failsafe + $serverPendingReboot = (Get-ServerRebootPending -ServerName $Server -CatchActionFunction ${Function:Invoke-CatchActions}) + $timeZoneInformation = Get-TimeZoneInformation -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $tlsSettings = Get-AllTlsSettings -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $vcRedistributable = Get-VisualCRedistributableInstalledVersion -ComputerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $smb1ServerSettings = Get-Smb1ServerSettings -ServerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $registryValues = Get-OperatingSystemRegistryValues -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $netFrameworkInformation = Get-NETFrameworkInformation -Server $Server + } end { + Write-Verbose "Exiting: $($MyInvocation.MyCommand)" + return [PSCustomObject]@{ + BuildInformation = $buildInformation + NetworkInformation = $networkInformation + PowerPlan = $powerPlan + PageFile = $pageFile + ServerPendingReboot = $serverPendingReboot + TimeZone = $timeZoneInformation + TLSSettings = $tlsSettings + ServerBootUp = $serverBootUp + VcRedistributable = $vcRedistributable + RegistryValues = $registryValues + Smb1ServerSettings = $smb1ServerSettings + HotFixes = $hotFixes + NETFramework = $netFrameworkInformation + } } - - $osInformation.ServerPendingReboot = (Get-ServerRebootPending -ServerName $Server -CatchActionFunction ${Function:Invoke-CatchActions}) - $timeZoneInformation = Get-TimeZoneInformationRegistrySettings -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - $osInformation.TimeZone.DynamicDaylightTimeDisabled = $timeZoneInformation.DynamicDaylightTimeDisabled - $osInformation.TimeZone.TimeZoneKeyName = $timeZoneInformation.TimeZoneKeyName - $osInformation.TimeZone.StandardStart = $timeZoneInformation.StandardStart - $osInformation.TimeZone.DaylightStart = $timeZoneInformation.DaylightStart - $osInformation.TimeZone.DstIssueDetected = $timeZoneInformation.DstIssueDetected - $osInformation.TimeZone.ActionsToTake = $timeZoneInformation.ActionsToTake - $osInformation.TimeZone.CurrentTimeZone = Invoke-ScriptBlockHandler -ComputerName $Server ` - -ScriptBlock { ([System.TimeZone]::CurrentTimeZone).StandardName } ` - -ScriptBlockDescription "Getting Current Time Zone" ` - -CatchActionFunction ${Function:Invoke-CatchActions} - $osInformation.TLSSettings = Get-AllTlsSettings -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - $osInformation.VcRedistributable = Get-VisualCRedistributableInstalledVersion -ComputerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - $osInformation.CredentialGuardEnabled = Get-CredentialGuardEnabled -Server $Server - $osInformation.Smb1ServerSettings = Get-Smb1ServerSettings -ServerName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - $osInformation.RegistryValues = Get-OperatingSystemRegistryValues -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - - Write-Verbose "Exiting: $($MyInvocation.MyCommand)" - return $osInformation } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemRegistryValues.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemRegistryValues.ps1 index 10cd54348c..1dce20acdb 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemRegistryValues.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemRegistryValues.ps1 @@ -53,6 +53,11 @@ function Get-OperatingSystemRegistryValues { ValueType = "DWord" } + $credGuardParams = $baseParams + @{ + SubKey = "SYSTEM\CurrentControlSet\Control\LSA" + GetValue = "LsaCfgFlags" + } + $lmCompParams = $baseParams + @{ SubKey = "SYSTEM\CurrentControlSet\Control\Lsa" GetValue = "LmCompatibilityLevel" @@ -71,5 +76,6 @@ function Get-OperatingSystemRegistryValues { RpcMinConnectionTimeout = [int](Get-RemoteRegistryValue @rpcMinParams) AllowInsecureRenegoServers = [int](Get-RemoteRegistryValue @renegoServersParams) AllowInsecureRenegoClients = [int](Get-RemoteRegistryValue @renegoClientsParams) + CredentialGuard = [int](Get-RemoteRegistryValue @credGuardParams) } } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-PowerPlanSetting.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-PowerPlanSetting.ps1 new file mode 100644 index 0000000000..f6943f9900 --- /dev/null +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-PowerPlanSetting.ps1 @@ -0,0 +1,37 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\..\..\..\..\Shared\ErrorMonitorFunctions.ps1 +. $PSScriptRoot\Get-WmiObjectCriticalHandler.ps1 + +function Get-PowerPlanSetting { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$Server + ) + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $highPerformanceSet = $false + $powerPlanSetting = [string]::Empty + $win32_PowerPlan = Get-WmiObjectHandler -ComputerName $Server -Class Win32_PowerPlan -Namespace 'root\ciMv2\power' -Filter "isActive='true'" -CatchActionFunction ${Function:Invoke-CatchActions} + + if ($null -ne $win32_PowerPlan) { + + if ($win32_PowerPlan.InstanceID -eq "Microsoft:PowerPlan\{8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}") { + Write-Verbose "High Performance Power Plan is set to true" + $highPerformanceSet = $true + } else { Write-Verbose "High Performance Power Plan is NOT set to true" } + $powerPlanSetting = $win32_PowerPlan.ElementName + } else { + Write-Verbose "Power Plan Information could not be read" + $powerPlanSetting = "N/A" + } + } end { + return [PSCustomObject]@{ + HighPerformanceSet = $highPerformanceSet + PowerPlanSetting = $powerPlanSetting + PowerPlan = $win32_PowerPlan + } + } +} diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 index 6f7f5c901d..820ddafd45 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 @@ -2,7 +2,8 @@ # Licensed under the MIT License. . $PSScriptRoot\..\..\..\..\Shared\Get-RemoteRegistryValue.ps1 -function Get-TimeZoneInformationRegistrySettings { +. $PSScriptRoot\..\..\..\..\Shared\Invoke-ScriptBlockHandler.ps1 +function Get-TimeZoneInformation { [CmdletBinding()] param( [string]$MachineName = $env:COMPUTERNAME, @@ -10,15 +11,19 @@ function Get-TimeZoneInformationRegistrySettings { ) begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" - $timeZoneInformationSubKey = "SYSTEM\CurrentControlSet\Control\TimeZoneInformation" $actionsToTake = @() $dstIssueDetected = $false + $registryParams = @{ + MachineName = $MachineName + SubKey = "SYSTEM\CurrentControlSet\Control\TimeZoneInformation" + CatchActionFunction = $CatchActionFunction + } } process { - $dynamicDaylightTimeDisabled = Get-RemoteRegistryValue -MachineName $MachineName -SubKey $timeZoneInformationSubKey -GetValue "DynamicDaylightTimeDisabled" -CatchActionFunction $CatchActionFunction - $timeZoneKeyName = Get-RemoteRegistryValue -MachineName $MachineName -SubKey $timeZoneInformationSubKey -GetValue "TimeZoneKeyName" -CatchActionFunction $CatchActionFunction - $standardStart = Get-RemoteRegistryValue -MachineName $MachineName -SubKey $timeZoneInformationSubKey -GetValue "StandardStart" -CatchActionFunction $CatchActionFunction - $daylightStart = Get-RemoteRegistryValue -MachineName $MachineName -SubKey $timeZoneInformationSubKey -GetValue "DaylightStart" -CatchActionFunction $CatchActionFunction + $dynamicDaylightTimeDisabled = Get-RemoteRegistryValue @registryParams -GetValue "DynamicDaylightTimeDisabled" + $timeZoneKeyName = Get-RemoteRegistryValue @registryParams -GetValue "TimeZoneKeyName" + $standardStart = Get-RemoteRegistryValue @registryParams -GetValue "StandardStart" + $daylightStart = Get-RemoteRegistryValue @registryParams -GetValue "DaylightStart" if ([string]::IsNullOrEmpty($timeZoneKeyName)) { Write-Verbose "TimeZoneKeyName is null or empty. Action should be taken to address this." @@ -39,6 +44,15 @@ function Get-TimeZoneInformationRegistrySettings { Write-Verbose "Daylight savings auto adjustment is disabled." $actionsToTake += "Warning: DynamicDaylightTimeDisabled is set, Windows can not properly detect any DST rule changes in your time zone." } + + $params = @{ + ComputerName = $Server + ScriptBlock = { ([System.TimeZone]::CurrentTimeZone).StandardName } + ScriptBlockDescription = "Getting Current Time Zone" + CatchActionFunction = $CatchActionFunction + } + + $currentTimeZone = Invoke-ScriptBlockHandler @params } end { return [PSCustomObject]@{ @@ -48,6 +62,7 @@ function Get-TimeZoneInformationRegistrySettings { DaylightStart = $daylightStart DstIssueDetected = $dstIssueDetected ActionsToTake = $actionsToTake + CurrentTimeZone = $currentTimeZone } } } diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index 6f94972713..3fae3f5f7e 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -10,7 +10,7 @@ using System.Collections; { public string ServerName; //String of the server that we are working with public HardwareInformation HardwareInformation; // Hardware Object Information - public OperatingSystemInformation OSInformation; // OS Version Object Information + public object OSInformation; // OS Version Object Information public ExchangeInformation ExchangeInformation; //Detailed Exchange Information public OrganizationInformation OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. public string HealthCheckerVersion; //To determine the version of the script on the object. @@ -144,95 +144,6 @@ using System.Collections; } // End ExchangeInformation - // OperatingSystemInformation - public class OperatingSystemInformation - { - public OSBuildInformation BuildInformation = new OSBuildInformation(); // contains build information - public NetworkInformation NetworkInformation = new NetworkInformation(); //stores network information and settings - public PowerPlanInformation PowerPlan = new PowerPlanInformation(); //stores the power plan information - public object PageFile; //stores the page file information - public object ServerPendingReboot; // determine if server is pending a reboot. - public TimeZoneInformation TimeZone = new TimeZoneInformation(); //stores time zone information - public object TLSSettings; // stores the TLS settings on the server. - public InstalledUpdatesInformation InstalledUpdates = new InstalledUpdatesInformation(); //store the install update - public ServerBootUpInformation ServerBootUp = new ServerBootUpInformation(); // stores the server boot up time information - public System.Array VcRedistributable; //stores the Visual C++ Redistributable - public OSNetFrameworkInformation NETFramework = new OSNetFrameworkInformation(); //stores OS Net Framework - public bool CredentialGuardEnabled; - public object RegistryValues; // stores generic registry values - public object Smb1ServerSettings; - } - - public class OSBuildInformation - { - public OSServerVersion MajorVersion; //OS Major Version - public string VersionBuild; //hold the build number - public string FriendlyName; //string holder of the Windows Server friendly name - public object OperatingSystem; // holds Win32_OperatingSystem - } - - public class NetworkInformation - { - public object HttpProxy; // holds the setting for HttpProxy if one is set. - public object PacketsReceivedDiscarded; //hold all the packets received discarded on the server. - public bool IPv6DisabledOnNICs; //value that determines if we have IPv6 disabled on some NICs or not. - public System.Array NetworkAdapters; //stores all the NICs on the servers. - public string PnPCapabilities; //Value from PnPCapabilities registry - public bool SleepyNicDisabled; //If the NIC can be in power saver mode by the OS. - } - - public class PowerPlanInformation - { - public bool HighPerformanceSet; // If the power plan is High Performance - public string PowerPlanSetting; //value for the power plan that is set - public object PowerPlan; //object to store the power plan information - } - - public class TimeZoneInformation - { - public string CurrentTimeZone; //stores the value for the current time zone of the server. - public int DynamicDaylightTimeDisabled; // the registry value for DynamicDaylightTimeDisabled. - public string TimeZoneKeyName; // the registry value TimeZoneKeyName. - public string StandardStart; // the registry value for StandardStart. - public string DaylightStart; // the registry value for DaylightStart. - public bool DstIssueDetected; // Determines if there is a high chance of an issue. - public System.Array ActionsToTake; //array of verbiage of the issues detected. - } - - public class ServerRebootInformation - { - public bool PendingFileRenameOperations; //bool "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\" item PendingFileRenameOperations. - public object SccmReboot; // object to store CimMethod for class name CCM_ClientUtilities - public bool SccmRebootPending; // SccmReboot has either PendingReboot or IsHardRebootPending is set to true. - public bool ComponentBasedServicingPendingReboot; // bool HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending - public bool AutoUpdatePendingReboot; // bool HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired - public bool PendingReboot; // bool if reboot types are set to true - public bool UpdateExeVolatile; // bool HKLM:\Software\Microsoft\Updates\UpdateExeVolatile\Flags - } - - public class InstalledUpdatesInformation - { - public System.Array HotFixes; //array to keep all the hot fixes of the server - public System.Array HotFixInfo; //object to store hotfix information - public System.Array InstalledUpdates; //store the install updates - } - - public class ServerBootUpInformation - { - public string Days; - public string Hours; - public string Minutes; - public string Seconds; - } - - public class OSNetFrameworkInformation - { - public NetMajorVersion NetMajorVersion; //NetMajorVersion value - public string FriendlyName; //string of the friendly name - public int RegistryValue; //store the registry value - public Hashtable FileInformation; //stores Get-Item information for .NET Framework - } - //enum for the OSServerVersion that we are public enum OSServerVersion { @@ -365,7 +276,7 @@ using System.Collections; public class AnalyzedInformation { - public HealthCheckerExchangeServer HealthCheckerExchangeServer; + public object HealthCheckerExchangeServer; public Hashtable HtmlServerValues = new Hashtable(); public Hashtable DisplayResults = new Hashtable(); } From 3518945ddf36637a2a6f38ecc6de9bad4355ad07 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 15:17:55 -0600 Subject: [PATCH 03/33] Removed Hardward Class from HC --- .../Get-HardwareInformation.ps1 | 60 ++++++++----------- Diagnostics/HealthChecker/Helpers/Class.ps1 | 30 +--------- 2 files changed, 26 insertions(+), 64 deletions(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 index 47b9b09926..4762ec063f 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 @@ -11,43 +11,33 @@ function Get-HardwareInformation { [string]$Server ) - Write-Verbose "Calling: $($MyInvocation.MyCommand)" + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" - [HealthChecker.HardwareInformation]$hardware_obj = New-Object HealthChecker.HardwareInformation - $system = Get-WmiObjectCriticalHandler -ComputerName $Server -Class "Win32_ComputerSystem" -CatchActionFunction ${Function:Invoke-CatchActions} - $hardware_obj.MemoryInformation = Get-WmiObjectHandler -ComputerName $Server -Class "Win32_PhysicalMemory" -CatchActionFunction ${Function:Invoke-CatchActions} + $system = Get-WmiObjectCriticalHandler -ComputerName $Server -Class "Win32_ComputerSystem" -CatchActionFunction ${Function:Invoke-CatchActions} + $physicalMemory = Get-WmiObjectHandler -ComputerName $Server -Class "Win32_PhysicalMemory" -CatchActionFunction ${Function:Invoke-CatchActions} + $processorInformation = Get-ProcessorInformation -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $totalMemory = 0 - if ($null -eq $hardware_obj.MemoryInformation) { - Write-Verbose "Using memory from Win32_ComputerSystem class instead. This may cause memory calculation issues." - $hardware_obj.TotalMemory = $system.TotalPhysicalMemory - } else { - foreach ($memory in $hardware_obj.MemoryInformation) { - $hardware_obj.TotalMemory += $memory.Capacity + if ($null -eq $physicalMemory) { + Write-Verbose "Using memory from Win32_ComputerSystem class instead. This may cause memory calculation issues." + $totalMemory = $system.TotalPhysicalMemory + } else { + foreach ($memory in $physicalMemory) { + $totalMemory += $memory.Capacity + } + } + } end { + Write-Verbose "Exiting: $($MyInvocation.MyCommand)" + return [PSCustomObject]@{ + Manufacturer = $system.Manufacturer + ServerType = (Get-ServerType -ServerType $system.Manufacturer) + AutoPageFile = $system.AutomaticManagedPagefile + Model = $system.Model + System = $system + Processor = $processorInformation + TotalMemory = $totalMemory + MemoryInformation = $physicalMemory } } - $hardware_obj.Manufacturer = $system.Manufacturer - $hardware_obj.System = $system - $hardware_obj.AutoPageFile = $system.AutomaticManagedPagefile - $hardware_obj.ServerType = (Get-ServerType -ServerType $system.Manufacturer) - $processorInformation = Get-ProcessorInformation -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - - #Need to do it this way because of Windows 2012R2 - $processor = New-Object HealthChecker.ProcessorInformation - $processor.Name = $processorInformation.Name - $processor.NumberOfPhysicalCores = $processorInformation.NumberOfPhysicalCores - $processor.NumberOfLogicalCores = $processorInformation.NumberOfLogicalCores - $processor.NumberOfProcessors = $processorInformation.NumberOfProcessors - $processor.MaxMegacyclesPerCore = $processorInformation.MaxMegacyclesPerCore - $processor.CurrentMegacyclesPerCore = $processorInformation.CurrentMegacyclesPerCore - $processor.ProcessorIsThrottled = $processorInformation.ProcessorIsThrottled - $processor.DifferentProcessorsDetected = $processorInformation.DifferentProcessorsDetected - $processor.DifferentProcessorCoreCountDetected = $processorInformation.DifferentProcessorCoreCountDetected - $processor.EnvironmentProcessorCount = $processorInformation.EnvironmentProcessorCount - $processor.ProcessorClassObject = $processorInformation.ProcessorClassObject - - $hardware_obj.Processor = $processor - $hardware_obj.Model = $system.Model - - Write-Verbose "Exiting: $($MyInvocation.MyCommand)" - return $hardware_obj } diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index 3fae3f5f7e..5019cd966e 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -9,7 +9,7 @@ using System.Collections; public class HealthCheckerExchangeServer { public string ServerName; //String of the server that we are working with - public HardwareInformation HardwareInformation; // Hardware Object Information + public object HardwareInformation; // Hardware Object Information public object OSInformation; // OS Version Object Information public ExchangeInformation ExchangeInformation; //Detailed Exchange Information public OrganizationInformation OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. @@ -177,19 +177,6 @@ using System.Collections; } // End OperatingSystemInformation - // HardwareInformation - public class HardwareInformation - { - public string Manufacturer; //String to display the hardware information - public ServerType ServerType; //Enum to determine if the hardware is VMware, HyperV, Physical, or Unknown - public System.Array MemoryInformation; //Detailed information about the installed memory - public UInt64 TotalMemory; //Stores the total memory cooked value - public object System; //object to store the system information that we have collected - public ProcessorInformation Processor; //Detailed processor Information - public bool AutoPageFile; //True/False if we are using a page file that is being automatically set - public string Model; //string to display Model - } - //enum for the type of computer that we are public enum ServerType { @@ -200,21 +187,6 @@ using System.Collections; Unknown } - public class ProcessorInformation - { - public string Name; //String of the processor name - public int NumberOfPhysicalCores; //Number of Physical cores that we have - public int NumberOfLogicalCores; //Number of Logical cores that we have presented to the os - public int NumberOfProcessors; //Total number of processors that we have in the system - public int MaxMegacyclesPerCore; //Max speed that we can get out of the cores - public int CurrentMegacyclesPerCore; //Current speed that we are using the cores at - public bool ProcessorIsThrottled; //True/False if we are throttling our processor - public bool DifferentProcessorsDetected; //true/false to detect if we have different processor types detected - public bool DifferentProcessorCoreCountDetected; //detect if there are a different number of core counts per Processor CPU socket - public int EnvironmentProcessorCount; //[system.environment]::ProcessorCount - public object ProcessorClassObject; // object to store the processor information - } - //HTML & display classes public class HtmlServerValues { From 32f3d99ad895f42fe5968b574b610f5e6e8b1da5 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 15:27:22 -0600 Subject: [PATCH 04/33] Stash current pester changes --- .../Tests/HealthChecker.E19.Scenarios.Tests.ps1 | 1 - .../Tests/HealthChecker.MockedCalls.Tests.ps1 | 3 +-- .../Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 | 7 ++----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 index c714e4f0e0..5f93147f24 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 @@ -16,7 +16,6 @@ Describe "Testing Health Checker by Mock Data Imports" { BeforeAll { Mock Get-RemoteRegistryValue -ParameterFilter { $GetValue -eq "KeepAliveTime" } -MockWith { return 0 } Mock Get-RemoteRegistryValue -ParameterFilter { $GetValue -eq "CtsProcessorAffinityPercentage" } -MockWith { return 10 } - Mock Get-CredentialGuardEnabled -MockWith { return $true } Mock Get-ExchangeApplicationConfigurationFileValidation { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetExchangeApplicationConfigurationFileValidation1.xml" } Mock Get-ServerRebootPending { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetServerRebootPending1.xml" } Mock Get-AllTlsSettings { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetAllTlsSettings1.xml" } diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 index b9d0069025..6db16657a3 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 @@ -65,9 +65,8 @@ Describe "Testing Health Checker by Mock Data Imports" { Assert-MockCalled Get-HotFix -Exactly 1 Assert-MockCalled Get-LocalizedCounterSamples -Exactly 1 Assert-MockCalled Get-ServerRebootPending -Exactly 1 - Assert-MockCalled Get-TimeZoneInformationRegistrySettings -Exactly 1 + Assert-MockCalled Get-TimeZoneInformation -Exactly 1 Assert-MockCalled Get-AllTlsSettings -Exactly 1 - Assert-MockCalled Get-CredentialGuardEnabled -Exactly 1 Assert-MockCalled Get-Smb1ServerSettings -Exactly 1 Assert-MockCalled Get-ExchangeAppPoolsInformation -Exactly 1 Assert-MockCalled Get-ExchangeApplicationConfigurationFileValidation -Exactly 1 diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 index e5608f56f3..130257655e 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 @@ -55,6 +55,7 @@ Mock Get-RemoteRegistryValue { "AllowInsecureRenegoClients" { return 0 } "AllowInsecureRenegoServers" { return 0 } "EnableSerializationDataSigning" { return 0 } + "LsaCfgFlags" { return 0 } default { throw "Failed to find GetValue: $GetValue" } } } @@ -102,7 +103,7 @@ Mock Get-ServerRebootPending { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetServerRebootPending.xml" } -Mock Get-TimeZoneInformationRegistrySettings { +Mock Get-TimeZoneInformation { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetTimeZoneInformationRegistrySettings.xml" } @@ -114,10 +115,6 @@ Mock Get-VisualCRedistributableInstalledVersion { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetVisualCRedistributableInstalledVersion.xml" } -Mock Get-CredentialGuardEnabled { - return $false -} - Mock Get-Smb1ServerSettings { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetSmb1ServerSettings.xml" } From 76b0658fd8671b5e0a8c110dd9162ccf11fb8eed Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 17:06:21 -0600 Subject: [PATCH 05/33] Fix issue in frequent config issues --- .../Invoke-AnalyzerFrequentConfigurationIssues.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 index 59f096ff4b..9eebe4db56 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 @@ -106,18 +106,18 @@ function Invoke-AnalyzerFrequentConfigurationIssues { } Add-AnalyzedResultInformation @params - $displayValue = $osInformation.RegistryValues.CredentialGuard -ne 0 + $credentialGuardValue = $osInformation.RegistryValues.CredentialGuard -ne 0 $displayWriteType = "Grey" - if ($osInformation.CredentialGuardEnabled) { - $displayValue = "{0} `r`n`t`tError: Credential Guard is not supported on an Exchange Server. This can cause a performance hit on the server." -f $osInformation.CredentialGuardEnabled + if ($credentialGuardValue) { + $displayValue = "{0} `r`n`t`tError: Credential Guard is not supported on an Exchange Server. This can cause a performance hit on the server." -f $credentialGuardValue $displayWriteType = "Red" } $params = $baseParams + @{ Name = "Credential Guard Enabled" Details = $displayValue - DisplayTestingValue = $osInformation.CredentialGuardEnabled + DisplayTestingValue = $credentialGuardValue DisplayWriteType = $displayWriteType } Add-AnalyzedResultInformation @params From e5c34398eed4ef1b95e828b1a5bab952d2241b0d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 17:06:49 -0600 Subject: [PATCH 06/33] fix issue in Cve check --- .../Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 index 8244633131..1ddbee73f3 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 @@ -23,7 +23,7 @@ function Invoke-AnalyzerSecurityCve-2020-1147 { #Workaround: N/A $dllFileBuildPartToCheckAgainst = 3630 - if ($SecurityObject.OsInformation.NETFramework.NetMajorVersion -eq [HealthChecker.NetMajorVersion]::Net4d8) { + if ($SecurityObject.OsInformation.NETFramework.MajorVersion -eq [HealthChecker.NetMajorVersion]::Net4d8) { $dllFileBuildPartToCheckAgainst = 4190 } From f34819a26bd8c2460d2f42d8e65602e36542f3d9 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 17:07:30 -0600 Subject: [PATCH 07/33] Resolve pester testing changes --- .../Tests/HealthChecker.E19.Scenarios.Tests.ps1 | 1 + .../Tests/HealthChecker.MockedCalls.Tests.ps1 | 3 +-- .../Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 index 5f93147f24..0dc8da5de2 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Scenarios.Tests.ps1 @@ -16,6 +16,7 @@ Describe "Testing Health Checker by Mock Data Imports" { BeforeAll { Mock Get-RemoteRegistryValue -ParameterFilter { $GetValue -eq "KeepAliveTime" } -MockWith { return 0 } Mock Get-RemoteRegistryValue -ParameterFilter { $GetValue -eq "CtsProcessorAffinityPercentage" } -MockWith { return 10 } + Mock Get-RemoteRegistryValue -ParameterFilter { $GetValue -eq "LsaCfgFlags" } -MockWith { return 1 } Mock Get-ExchangeApplicationConfigurationFileValidation { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetExchangeApplicationConfigurationFileValidation1.xml" } Mock Get-ServerRebootPending { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetServerRebootPending1.xml" } Mock Get-AllTlsSettings { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetAllTlsSettings1.xml" } diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 index 6db16657a3..5e6292159f 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.MockedCalls.Tests.ps1 @@ -55,7 +55,7 @@ Describe "Testing Health Checker by Mock Data Imports" { Assert-MockCalled Get-WmiObjectHandler -Exactly 6 Assert-MockCalled Invoke-ScriptBlockHandler -Exactly 7 - Assert-MockCalled Get-RemoteRegistryValue -Exactly 14 + Assert-MockCalled Get-RemoteRegistryValue -Exactly 19 Assert-MockCalled Get-NETFrameworkVersion -Exactly 1 Assert-MockCalled Get-DotNetDllFileVersions -Exactly 1 Assert-MockCalled Get-NicPnpCapabilitiesSetting -Exactly 1 @@ -65,7 +65,6 @@ Describe "Testing Health Checker by Mock Data Imports" { Assert-MockCalled Get-HotFix -Exactly 1 Assert-MockCalled Get-LocalizedCounterSamples -Exactly 1 Assert-MockCalled Get-ServerRebootPending -Exactly 1 - Assert-MockCalled Get-TimeZoneInformation -Exactly 1 Assert-MockCalled Get-AllTlsSettings -Exactly 1 Assert-MockCalled Get-Smb1ServerSettings -Exactly 1 Assert-MockCalled Get-ExchangeAppPoolsInformation -Exactly 1 diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 index 130257655e..11f04e30c7 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTest.CommonMocks.NotPublished.ps1 @@ -56,6 +56,10 @@ Mock Get-RemoteRegistryValue { "AllowInsecureRenegoServers" { return 0 } "EnableSerializationDataSigning" { return 0 } "LsaCfgFlags" { return 0 } + "DynamicDaylightTimeDisabled" { return 0 } + "TimeZoneKeyName" { return "Pacific Standard Time" } + "StandardStart" { return @(0, 0, 11, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0) } + "DaylightStart" { return @(0, 0, 3, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0) } default { throw "Failed to find GetValue: $GetValue" } } } @@ -103,10 +107,6 @@ Mock Get-ServerRebootPending { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetServerRebootPending.xml" } -Mock Get-TimeZoneInformation { - return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetTimeZoneInformationRegistrySettings.xml" -} - Mock Get-AllTlsSettings { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetAllTlsSettings.xml" } From b76b24899defca8f00f7c5c70d50d1ef30aa1aff Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 18 Jan 2023 18:15:25 -0600 Subject: [PATCH 08/33] Remove Organization Information Class from HC --- .../Get-OrganizationInformation.ps1 | 67 +++++++++++++------ Diagnostics/HealthChecker/Helpers/Class.ps1 | 20 +----- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 index e3bd28a6a5..4e9f298163 100644 --- a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 @@ -15,11 +15,21 @@ function Get-OrganizationInformation { ) begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" - [HealthChecker.OrganizationInformation]$orgInfo = New-Object -TypeName HealthChecker.OrganizationInformation + $organizationConfig = $null + $domainsAclPermissions = $null + $wellKnownSecurityGroups = $null + $adSchemaInformation = $null + $getHybridConfiguration = $null + $enableDownloadDomains = $null + $wildCardAcceptedDomain = $null + $mapiHttpEnabled = $false + $securityResults = $null + $isSplitADPermissions = $false + $adSiteCount = 0 + $getSettingOverride = $null } process { try { $organizationConfig = Get-OrganizationConfig -ErrorAction Stop - $orgInfo.GetOrganizationConfig = $organizationConfig } catch { Write-Yellow "Failed to run Get-OrganizationConfig." Invoke-CatchActions @@ -28,34 +38,34 @@ function Get-OrganizationInformation { # Pull out information from OrganizationConfig # This is done incase Get-OrganizationConfig and we set a true boolean value of false if ($null -ne $organizationConfig) { - $orgInfo.MapiHttpEnabled = $organizationConfig.MapiHttpEnabled + $mapiHttpEnabled = $organizationConfig.MapiHttpEnabled # Enabled Download Domains will not be there if running EMS from Exchange 2013. # By default, EnableDownloadDomains is set to Unknown in case this is run on 2013 server. if ($null -ne $organizationConfig.EnableDownloadDomains) { - $orgInfo.EnableDownloadDomains = $organizationConfig.EnableDownloadDomains + $enableDownloadDomains = $organizationConfig.EnableDownloadDomains } else { Write-Verbose "No EnableDownloadDomains detected on Get-OrganizationConfig" - $orgInfo.EnableDownloadDomains = "Unknown" + $enableDownloadDomains = "Unknown" } } else { Write-Verbose "MAPI HTTP Enabled and Download Domains Enabled results not accurate" } try { - $orgInfo.WildCardAcceptedDomain = Get-AcceptedDomain -ErrorAction Stop | Where-Object { $_.DomainName.ToString() -eq "*" } + $wildCardAcceptedDomain = Get-AcceptedDomain -ErrorAction Stop | Where-Object { $_.DomainName.ToString() -eq "*" } } catch { Write-Verbose "Failed to run Get-AcceptedDomain" - $orgInfo.WildCardAcceptedDomain = "Unknown" + $wildCardAcceptedDomain = "Unknown" Invoke-CatchActions } # NO Edge Server Collection if (-not ($EdgeServer)) { - $orgInfo.AdSchemaInformation = Get-ExchangeAdSchemaInformation - $orgInfo.DomainsAclPermissions = Get-ExchangeDomainsAclPermissions - $orgInfo.WellKnownSecurityGroups = Get-ExchangeWellKnownSecurityGroups - $orgInfo.IsSplitADPermissions = Get-ExchangeADSplitPermissionsEnabled -CatchActionFunction ${Function:Invoke-CatchActions} + $adSchemaInformation = Get-ExchangeAdSchemaInformation + $domainsAclPermissions = Get-ExchangeDomainsAclPermissions + $wellKnownSecurityGroups = Get-ExchangeWellKnownSecurityGroups + $isSplitADPermissions = Get-ExchangeADSplitPermissionsEnabled -CatchActionFunction ${Function:Invoke-CatchActions} try { $rootDSE = [ADSI]("LDAP://$([System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Name)/RootDSE") @@ -64,14 +74,14 @@ function Get-OrganizationInformation { $directorySearcher.SearchRoot = [ADSI]("LDAP://" + $rootDSE.configurationNamingContext.ToString()) $directorySearcher.Filter = "(objectCategory=site)" $directorySearcher.PageSize = 100 - $orgInfo.ADSiteCount = ($directorySearcher.FindAll()).Count + $adSiteCount = ($directorySearcher.FindAll()).Count } catch { Write-Verbose "Failed to collect AD Site Count information" Invoke-CatchActions } $schemaRangeUpper = ( - ($orgInfo.AdSchemaInformation.msExchSchemaVersionPt.Properties["RangeUpper"])[0]).ToInt32([System.Globalization.NumberFormatInfo]::InvariantInfo) + ($adSchemaInformation.msExchSchemaVersionPt.Properties["RangeUpper"])[0]).ToInt32([System.Globalization.NumberFormatInfo]::InvariantInfo) if ($schemaRangeUpper -lt 15323) { $schemaLevel = "2013" @@ -82,37 +92,50 @@ function Get-OrganizationInformation { } $cve21978Params = @{ - DomainsAcls = $orgInfo.DomainsAclPermissions - ExchangeWellKnownSecurityGroups = $orgInfo.WellKnownSecurityGroups + DomainsAcls = $domainsAclPermissions + ExchangeWellKnownSecurityGroups = $wellKnownSecurityGroups ExchangeSchemaLevel = $schemaLevel - SplitADPermissions = $orgInfo.IsSplitADPermissions + SplitADPermissions = $isSplitADPermissions } $cve34470Params = @{ - MsExchStorageGroup = $orgInfo.AdSchemaInformation.MsExchStorageGroup + MsExchStorageGroup = $adSchemaInformation.MsExchStorageGroup } - $orgInfo.SecurityResults = [PSCustomObject]@{ + $securityResults = [PSCustomObject]@{ CVE202221978 = (Get-SecurityCve-2022-21978 @cve21978Params) CVE202134470 = (Get-SecurityCve-2021-34470 @cve34470Params) } try { - $orgInfo.GetHybridConfiguration = Get-HybridConfiguration -ErrorAction Stop + $getHybridConfiguration = Get-HybridConfiguration -ErrorAction Stop } catch { Write-Yellow "Failed to run Get-HybridConfiguration" Invoke-CatchActions } try { - $orgInfo.GetSettingOverride = Get-SettingOverride -ErrorAction Stop + $getSettingOverride = Get-SettingOverride -ErrorAction Stop } catch { Write-Verbose "Failed to run Get-SettingOverride" - $orgInfo.GetSettingOverride = "Unknown" + $getSettingOverride = "Unknown" Invoke-CatchActions } } } end { - return $orgInfo + return [PSCustomObject]@{ + GetOrganizationConfig = $organizationConfig + DomainsAclPermissions = $domainsAclPermissions + WellKnownSecurityGroups = $wellKnownSecurityGroups + AdSchemaInformation = $adSchemaInformation + GetHybridConfiguration = $getHybridConfiguration + EnableDownloadDomains = $enableDownloadDomains + WildCardAcceptedDomain = $wildCardAcceptedDomain + MapiHttpEnabled = $mapiHttpEnabled + SecurityResults = $securityResults + IsSplitADPermissions = $isSplitADPermissions + ADSiteCount = $adSiteCount + GetSettingOverride = $getSettingOverride + } } } diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index 5019cd966e..db462869c5 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -12,29 +12,11 @@ using System.Collections; public object HardwareInformation; // Hardware Object Information public object OSInformation; // OS Version Object Information public ExchangeInformation ExchangeInformation; //Detailed Exchange Information - public OrganizationInformation OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. + public object OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. public string HealthCheckerVersion; //To determine the version of the script on the object. public DateTime GenerationTime; //Time stamp of running the script } - // Organization Information - Things that only need to be collected once - public class OrganizationInformation - { - public object GetOrganizationConfig; //Stores the result from Get-OrganizationConfig - public object DomainsAclPermissions; //Stores the ACLs that we care about from Exchange Domain that contains the MESO container - public object WellKnownSecurityGroups; //Stores the well known Exchange Security Groups information - public object AdSchemaInformation; //Stores the properties of from the Schema class - public object GetHybridConfiguration; //Stores the Get-HybridConfiguration Object - public object EnableDownloadDomains; //True if Download Domains are enabled on org level - public object WildCardAcceptedDomain; // for issues with * accepted domain. - public System.Array AMSIConfiguration; //Stores the Setting Override for AMSI Interface - public bool MapiHttpEnabled; //Stored from organization config - public object SecurityResults; // Stores different CVE results that are secured against Setup.exe /PrepareAD /PrepareDomain /PrepareSchema - public bool IsSplitADPermissions = new bool(); // Used to determine if split permissions are detected. - public int ADSiteCount; // Count for the numbers of sites the environment has. - public object GetSettingOverride; // Stores the Get-SettingOverride - } - // ExchangeInformation public class ExchangeInformation { From 4da94236d353479eac4326408175adca4bc16597 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 19 Jan 2023 21:07:25 -0600 Subject: [PATCH 09/33] Removed ExchangeInformation class from HC --- .../Analyzer/Invoke-AnalyzerOsInformation.ps1 | 58 +++- ...oke-AnalyzerSecurityCve-MarchSuSpecial.ps1 | 5 +- .../Invoke-AnalyzerSecuritySettings.ps1 | 8 +- .../Get-ExchangeInformation.ps1 | 277 +++++++----------- .../Get-ExchangeServerMaintenanceState.ps1 | 88 +++--- .../Get-FIPFSScanEngineVersionState.ps1 | 28 +- .../Get-HealthCheckerExchangeServer.ps1 | 30 +- .../Features/Get-HealthCheckerData.ps1 | 2 +- Diagnostics/HealthChecker/Helpers/Class.ps1 | 58 +--- 9 files changed, 237 insertions(+), 317 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 index 9af46890bb..303427253d 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 @@ -93,7 +93,59 @@ function Invoke-AnalyzerOsInformation { Add-AnalyzedResultInformation @params } - if ($exchangeInformation.NETFramework.OnRecommendedVersion) { + # .NET Supported Levels + [HealthChecker.ExchangeCULevel]$cuLevel = $exchangeInformation.BuildInformation.CU + [HealthChecker.OSServerVersion]$osVersion = $osInformation.BuildInformation.MajorVersion + [HealthChecker.ExchangeMajorVersion]$exchangeVersion = $exchangeInformation.BuildInformation.MajorVersion + $recommendedNetVersion = $null + + Write-Verbose "Checking $exchangeVersion .NET Framework Support Versions" + + if ([HealthChecker.ExchangeMajorVersion]::Exchange2019 -eq $exchangeVersion) { + if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU2) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 + } else { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 + } + } elseif ([HealthChecker.ExchangeMajorVersion]::Exchange2016 -eq $exchangeVersion) { + if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU2) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix + } elseif ($cuLevel -eq [HealthChecker.ExchangeCULevel]::CU2) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix + } elseif ($cuLevel -eq [HealthChecker.ExchangeCULevel]::CU3) { + if ($osVersion -eq [HealthChecker.OSServerVersion]::Windows2016) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 + } else { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix + } + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU8) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU11) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU13) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 + } else { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 + } + } else { + if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU4) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5 + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU13) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU15) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU19) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU21) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 + } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU23) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 + } else { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 + } + } + + if ($osInformation.NETFramework.MajorVersion -eq $recommendedNetVersion) { $params = $baseParams + @{ Name = ".NET Framework" Details = $osInformation.NETFramework.FriendlyName @@ -102,11 +154,11 @@ function Invoke-AnalyzerOsInformation { } Add-AnalyzedResultInformation @params } else { - $displayFriendly = Get-NETFrameworkVersion -NetVersionKey $exchangeInformation.NETFramework.MaxSupportedVersion + $displayFriendly = Get-NETFrameworkVersion -NetVersionKey $recommendedNetVersion $displayValue = "{0} - Warning Recommended .NET Version is {1}" -f $osInformation.NETFramework.FriendlyName, $displayFriendly.FriendlyName $testValue = [PSCustomObject]@{ CurrentValue = $osInformation.NETFramework.FriendlyName - MaxSupportedVersion = $exchangeInformation.NETFramework.MaxSupportedVersion + MaxSupportedVersion = $recommendedNetVersion } $params = $baseParams + @{ Name = ".NET Framework" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 index e5611a30df..154cf5ce7a 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 @@ -19,7 +19,10 @@ function Invoke-AnalyzerSecurityCve-MarchSuSpecial { #Description: March 2021 Exchange vulnerabilities Security Update (SU) check for outdated version (CUs) #Affected Exchange versions: Exchange 2013, Exchange 2016, Exchange 2016 (we only provide this special SU for these versions) #Fix: Update to a supported CU and apply KB5000871 - if (($SecurityObject.ExchangeInformation.BuildInformation.March2021SUInstalled) -and + $march2021SUInstalled = $null -ne $SecurityObject.ExchangeInformation.BuildInformation.KBsInstalled -and + $SecurityObject.ExchangeInformation.BuildInformation.KBsInstalled -like "*KB5000871*" + + if (($march2021SUInstalled) -and ($SecurityObject.ExchangeInformation.BuildInformation.VersionInformation.SupportedBuild -eq $false)) { if (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) -and ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU23)) { diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index 75b2d0d34f..254002c626 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -438,9 +438,11 @@ function Invoke-AnalyzerSecuritySettings { Write-Verbose "Server runs a FIP-FS fixed build: $($fipFsInfoObject.FIPFSFixedBuild) - Highest version number: $highestVersion" } } else { - $fipFsIssueBaseParams.Details = "Warning: Unable to check if the system is vulnerable to the FIP-FS bad pattern issue. Please re-run. $moreInformation" - $fipFsIssueBaseParams.DisplayWriteType = "Yellow" - $params = $baseParams + $fipFsIssueBaseParams + $fipFsIssueBaseParams = $baseParams + @{ + Name = "FIP-FS Update Issue Detected" + Details = "Warning: Unable to check if the system is vulnerable to the FIP-FS bad pattern issue. Please re-run. $moreInformation" + DisplayWriteType = "Yellow" + } Add-AnalyzedResultInformation @params } } diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index bb8af549bf..dd52b85ed2 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -26,167 +26,85 @@ function Get-ExchangeInformation { [string]$Server, [Parameter(Mandatory = $true)] - [object]$PassedOrganizationInformation, - - [HealthChecker.OSServerVersion]$OSMajorVersion + [object]$PassedOrganizationInformation ) - Write-Verbose "Calling: $($MyInvocation.MyCommand) Passed: OSMajorVersion: $OSMajorVersion" - [HealthChecker.ExchangeInformation]$exchangeInformation = New-Object -TypeName HealthChecker.ExchangeInformation - $exchangeInformation.GetExchangeServer = (Get-ExchangeServer -Identity $Server -Status) - $exchangeInformation.ExchangeCertificates = Get-ExchangeServerCertificates -Server $Server - $buildInformation = $exchangeInformation.BuildInformation - $buildInformation.ServerRole = (Get-ServerRole -ExchangeServerObj $exchangeInformation.GetExchangeServer) - $buildInformation.ExchangeSetup = Get-ExSetupDetails -Server $Server - $exchangeInformation.DependentServices = (Get-ExchangeDependentServices -MachineName $Server) - $buildInformation.VersionInformation = (Get-ExchangeBuildVersionInformation -FileVersion ($buildInformation.ExchangeSetup.FileVersion)) - $buildInformation.MajorVersion = ([HealthChecker.ExchangeMajorVersion]$buildInformation.VersionInformation.MajorVersion) - $buildInformation.CU = ([HealthChecker.ExchangeCULevel]$buildInformation.VersionInformation.CU) + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $params = @{ + ComputerName = $Server + ScriptBlock = { [environment]::OSVersion.Version -ge "10.0.0.0" } + ScriptBlockDescription = "Windows 2016 or Greater Check" + CatchActionFunction = ${Function:Invoke-CatchActions} + } + $windows2016OrGreater = Invoke-ScriptBlockHandler @params + $getExchangeServer = (Get-ExchangeServer -Identity $Server -Status) + $exchangeCertificates = Get-ExchangeServerCertificates -Server $Server + $exSetupDetails = Get-ExSetupDetails -Server $Server + $versionInformation = (Get-ExchangeBuildVersionInformation -FileVersion ($exSetupDetails.FileVersion)) + + $buildInformation = [PSCustomObject]@{ + ServerRole = (Get-ServerRole -ExchangeServerObj $getExchangeServer) + MajorVersion = $versionInformation.MajorVersion + CU = $versionInformation.CU + ExchangeSetup = $exSetupDetails + VersionInformation = $versionInformation + LocalBuildNumber = "$($Script:ExchangeShellComputer.Major).$($Script:ExchangeShellComputer.Minor).$($Script:ExchangeShellComputer.Build).$($Script:ExchangeShellComputer.Revision)" + KBsInstalled = Get-ExchangeUpdates -Server $Server -ExchangeMajorVersion $versionInformation.MajorVersion + } + + $dependentServices = (Get-ExchangeDependentServices -MachineName $Server) - if ($buildInformation.ServerRole -le [HealthChecker.ExchangeServerRole]::Mailbox ) { try { - $exchangeInformation.GetMailboxServer = (Get-MailboxServer -Identity $Server -ErrorAction Stop) + $getMailboxServer = (Get-MailboxServer -Identity $Server -ErrorAction Stop) } catch { Write-Verbose "Failed to run Get-MailboxServer" Invoke-CatchActions } - } - if (($buildInformation.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2016 -and - $buildInformation.ServerRole -le [HealthChecker.ExchangeServerRole]::Mailbox) -or - ($buildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013 -and - ($buildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::ClientAccess -or - $buildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::MultiRole))) { - $exchangeInformation.GetOwaVirtualDirectory = Get-OwaVirtualDirectory -Identity ("{0}\owa (Default Web Site)" -f $Server) -ADPropertiesOnly - $exchangeInformation.GetWebServicesVirtualDirectory = Get-WebServicesVirtualDirectory -Server $Server - } - - if ($Script:ExchangeShellComputer.ToolsOnly) { - $buildInformation.LocalBuildNumber = "{0}.{1}.{2}.{3}" -f $Script:ExchangeShellComputer.Major, $Script:ExchangeShellComputer.Minor, ` - $Script:ExchangeShellComputer.Build, ` - $Script:ExchangeShellComputer.Revision - } - - #Exchange 2013 or greater - if ($buildInformation.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2013) { - $netFrameworkExchange = $exchangeInformation.NETFramework - if ($buildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { - Write-Verbose "Exchange 2019 is detected. Setting Supported .NET Builds" - #Exchange 2019 .NET Information - if ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU2) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU4) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } else { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } - } elseif ($buildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) { - Write-Verbose "Exchange 2016 is detected. Setting Supported .NET Builds" - #Exchange 2016 .NET Information - if ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU2) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - } elseif ($buildInformation.CU -eq [HealthChecker.ExchangeCULevel]::CU2) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } elseif ($buildInformation.CU -eq [HealthChecker.ExchangeCULevel]::CU3) { - - if ($OSMajorVersion -eq [HealthChecker.OSServerVersion]::Windows2016) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } else { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } - } elseif ($buildInformation.CU -eq [HealthChecker.ExchangeCULevel]::CU4) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU8) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU10) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU11) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU13) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU15) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } else { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } - } else { - Write-Verbose "Exchange 2013 is detected. Setting Supported .NET Builds" - #Exchange 2013 .NET Information - if ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU4) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU13) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU15) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } elseif ($buildInformation.CU -eq [HealthChecker.ExchangeCULevel]::CU15) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d5d1 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU19) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU21) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - } elseif ($buildInformation.CU -lt [HealthChecker.ExchangeCULevel]::CU23) { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } else { - $netFrameworkExchange.MinSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - $netFrameworkExchange.MaxSupportedVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } + try { + $getOwaVirtualDirectory = Get-OwaVirtualDirectory -Identity ("{0}\owa (Default Web Site)" -f $Server) -ADPropertiesOnly -ErrorAction Stop + $getWebServicesVirtualDirectory = Get-WebServicesVirtualDirectory -Server $Server -ErrorAction Stop + } catch { + Write-Verbose "Failed to get OWA or EWS virtual directory" + Invoke-CatchActions } - $exchangeInformation.ExchangeEmergencyMitigationService = Get-ExchangeEmergencyMitigationServiceState ` - -RequiredInformation ([PSCustomObject]@{ + $params = @{ + RequiredInformation = [PSCustomObject]@{ ComputerName = $Server MitigationsEnabled = if ($null -ne $PassedOrganizationInformation.OrganizationConfig) { $PassedOrganizationInformation.OrganizationConfig.MitigationsEnabled } else { $null } - GetExchangeServer = $exchangeInformation.GetExchangeServer - }) ` - -CatchActionFunction ${Function:Invoke-CatchActions} + GetExchangeServer = $getExchangeServer + } + CatchActionFunction = ${Function:Invoke-CatchActions} + } + + $exchangeEmergencyMitigationService = Get-ExchangeEmergencyMitigationServiceState @params - if (($OSMajorVersion -ge [HealthChecker.OSServerVersion]::Windows2016) -and - ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { - $exchangeInformation.AMSIConfiguration = Get-ExchangeAMSIConfigurationState -GetSettingOverride $PassedOrganizationInformation.SettingOverride + if (($windows2016OrGreater) -and + ($getExchangeServer.IsEdgeServer -eq $false)) { + $amsiConfiguration = Get-ExchangeAMSIConfigurationState -GetSettingOverride $PassedOrganizationInformation.SettingOverride } else { Write-Verbose "AMSI Interface is not available on this OS / Exchange server role" } - $exchangeInformation.RegistryValues = Get-ExchangeRegistryValues -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} - $serverExchangeBinDirectory = [System.Io.Path]::Combine($exchangeInformation.RegistryValues.MisInstallPath, "Bin\") + $registryValues = Get-ExchangeRegistryValues -MachineName $Server -CatchActionFunction ${Function:Invoke-CatchActions} + $serverExchangeBinDirectory = [System.Io.Path]::Combine($registryValues.MisInstallPath, "Bin\") Write-Verbose "Found Exchange Bin: $serverExchangeBinDirectory" - if ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { - $exchangeInformation.ApplicationPools = Get-ExchangeAppPoolsInformation -Server $Server + if ($getExchangeServer.IsEdgeServer -eq $false) { + $applicationPools = Get-ExchangeAppPoolsInformation -Server $Server Write-Verbose "Query Exchange Connector settings via 'Get-ExchangeConnectors'" - $exchangeInformation.ExchangeConnectors = Get-ExchangeConnectors ` - -ComputerName $Server ` - -CertificateObject $exchangeInformation.ExchangeCertificates + $exchangeConnectors = Get-ExchangeConnectors -ComputerName $Server -CertificateObject $exchangeCertificates $exchangeServerIISParams = @{ ComputerName = $Server - IsLegacyOS = ($OSMajorVersion -lt [HealthChecker.OSServerVersion]::Windows2016) + IsLegacyOS = ($windows2016OrGreater -eq $false) CatchActionFunction = ${Function:Invoke-CatchActions} } Write-Verbose "Trying to query Exchange Server IIS settings" - $exchangeInformation.IISSettings = Get-ExchangeServerIISSettings @exchangeServerIISParams + $iisSettings = Get-ExchangeServerIISSettings @exchangeServerIISParams Write-Verbose "Query extended protection configuration for multiple CVEs testing" $getExtendedProtectionConfigurationParams = @{ @@ -196,60 +114,42 @@ function Get-ExchangeInformation { } try { - if ($null -ne $exchangeInformation.IISSettings.ApplicationHostConfig) { - $getExtendedProtectionConfigurationParams.ApplicationHostConfig = [xml]$exchangeInformation.IISSettings.ApplicationHostConfig + if ($null -ne $iisSettings.ApplicationHostConfig) { + $getExtendedProtectionConfigurationParams.ApplicationHostConfig = [xml]$iisSettings.ApplicationHostConfig } Write-Verbose "Was able to convert the ApplicationHost.Config to XML" - $exchangeInformation.ExtendedProtectionConfig = Get-ExtendedProtectionConfiguration @getExtendedProtectionConfigurationParams + $extendedProtectionConfig = Get-ExtendedProtectionConfiguration @getExtendedProtectionConfigurationParams } catch { Write-Verbose "Failed to get the ExtendedProtectionConfig" Invoke-CatchActions } } - $exchangeInformation.ApplicationConfigFileStatus = Get-ExchangeApplicationConfigurationFileValidation -ComputerName $Server -ConfigFileLocation ("{0}EdgeTransport.exe.config" -f $serverExchangeBinDirectory) - - $buildInformation.KBsInstalled = Get-ExchangeUpdates -Server $Server -ExchangeMajorVersion $buildInformation.MajorVersion - if (($null -ne $buildInformation.KBsInstalled) -and ($buildInformation.KBsInstalled -like "*KB5000871*")) { - Write-Verbose "March 2021 SU: KB5000871 was detected on the system" - $buildInformation.March2021SUInstalled = $true - } else { - Write-Verbose "March 2021 SU: KB5000871 was not detected on the system" - $buildInformation.March2021SUInstalled = $false - } - - Write-Verbose "Checking if FIP-FS is affected by the pattern issue" - $fipFsParams = @{ - ComputerName = $Server - ExSetupVersion = $buildInformation.ExchangeSetup.FileVersion - ServerRole = $buildInformation.ServerRole - } - - $buildInformation.FIPFSUpdateIssue = Get-FIPFSScanEngineVersionState @fipFsParams + $applicationConfigFileStatus = Get-ExchangeApplicationConfigurationFileValidation -ComputerName $Server -ConfigFileLocation ("{0}EdgeTransport.exe.config" -f $serverExchangeBinDirectory) + $serverMaintenance = Get-ExchangeServerMaintenanceState -Server $Server -ComponentsToSkip "ForwardSyncDaemon", "ProvisioningRps" + $settingOverrides = Get-ExchangeSettingOverride -Server $Server -CatchActionFunction ${Function:Invoke-CatchActions} - if (($buildInformation.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + if (($versionInformation.BuildVersion -ge "15.1.0.0") -and + ($getExchangeServer.IsEdgeServer -eq $false)) { Write-Verbose "SerializedDataSigning must be configured via SettingOverride" - $exchangeInformation.SerializationDataSigningConfiguration = Get-ExchangeSerializedDataSigningState -GetSettingOverride $PassedOrganizationInformation.SettingOverride - } elseif (($buildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) -and - ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + $serializationDataSigningConfiguration = Get-ExchangeSerializedDataSigningState -GetSettingOverride $PassedOrganizationInformation.SettingOverride + } elseif (($versionInformation -like "15.0.*") -and + ($getExchangeServer.IsEdgeServer -eq $false)) { Write-Verbose "SerializedDataSigning must be configured via Registry Value" - $exchangeInformation.SerializationDataSigningConfiguration = $exchangeInformation.RegistryValues.SerializedDataSigning + $serializationDataSigningConfiguration = $registryValues.SerializedDataSigning } else { Write-Verbose "SerializedDataSigning is not supported on this Exchange version & role combination" } - $exchangeInformation.ServerMaintenance = Get-ExchangeServerMaintenanceState -Server $Server -ComponentsToSkip "ForwardSyncDaemon", "ProvisioningRps" - $exchangeInformation.SettingOverrides = Get-ExchangeSettingOverride -Server $Server -CatchActionFunction ${Function:Invoke-CatchActions} - - if (($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::ClientAccess) -and - ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::None)) { + if (($getExchangeServer.IsMailboxServer) -and + ($getExchangeServer.IsEdgeServer)) { try { + $exchangeServicesNotRunning = @() $testServiceHealthResults = Test-ServiceHealth -Server $Server -ErrorAction Stop foreach ($notRunningService in $testServiceHealthResults.ServicesNotRunning) { - if ($exchangeInformation.ExchangeServicesNotRunning -notcontains $notRunningService) { - $exchangeInformation.ExchangeServicesNotRunning += $notRunningService + if ($exchangeServicesNotRunning -notcontains $notRunningService) { + $exchangeServicesNotRunning += $notRunningService } } } catch { @@ -257,12 +157,39 @@ function Get-ExchangeInformation { Invoke-CatchActions } } - } elseif ($buildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2010) { - Write-Verbose "Exchange 2010 detected." - $buildInformation.FriendlyName = "Exchange 2010" - $buildInformation.BuildNumber = $exchangeInformation.GetExchangeServer.AdminDisplayVersion.ToString() - } - Write-Verbose "Exiting: Get-ExchangeInformation" - return $exchangeInformation + Write-Verbose "Checking if FIP-FS is affected by the pattern issue" + $fipFsParams = @{ + ComputerName = $Server + ExSetupVersion = $buildInformation.ExchangeSetup.FileVersion + AffectedServerRole = $($getExchangeServer.IsMailboxServer -eq $true) + } + + $FIPFSUpdateIssue = Get-FIPFSScanEngineVersionState @fipFsParams + } end { + + Write-Verbose "Exiting: Get-ExchangeInformation" + return [PSCustomObject]@{ + BuildInformation = $buildInformation + GetExchangeServer = $getExchangeServer + GetMailboxServer = $getMailboxServer + GetOwaVirtualDirectory = $getOwaVirtualDirectory + GetWebServicesVirtualDirectory = $getWebServicesVirtualDirectory + ExtendedProtectionConfig = $extendedProtectionConfig + ExchangeConnectors = $exchangeConnectors + AMSIConfiguration = $amsiConfiguration + SerializationDataSigningConfiguration = $serializationDataSigningConfiguration + ExchangeServicesNotRunning = $exchangeServicesNotRunning + ApplicationPools = $applicationPools + RegistryValues = $registryValues + ServerMaintenance = $serverMaintenance + ExchangeCertificates = $exchangeCertificates + ExchangeEmergencyMitigationService = $exchangeEmergencyMitigationService + ApplicationConfigFileStatus = $applicationConfigFileStatus + DependentServices = $dependentServices + IISSettings = $iisSettings + SettingOverrides = $settingOverrides + FIPFSUpdateIssue = $FIPFSUpdateIssue + } + } } diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 index b0e33d0134..525394f7bb 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 @@ -10,60 +10,70 @@ function Get-ExchangeServerMaintenanceState { [Parameter(Mandatory = $false)] [array]$ComponentsToSkip ) - Write-Verbose "Calling Function: $($MyInvocation.MyCommand)" + begin { + Write-Verbose "Calling Function: $($MyInvocation.MyCommand)" + $getClusterNode = $null + $getServerComponentState = $null + $inactiveComponents = @() + } process { - [HealthChecker.ExchangeServerMaintenance]$serverMaintenance = New-Object -TypeName HealthChecker.ExchangeServerMaintenance - $serverMaintenance.GetServerComponentState = Get-ServerComponentState -Identity $Server -ErrorAction SilentlyContinue + $getServerComponentState = Get-ServerComponentState -Identity $Server -ErrorAction SilentlyContinue - try { - $serverMaintenance.GetClusterNode = Get-ClusterNode -Name $Server -ErrorAction Stop - } catch { - Write-Verbose "Failed to run Get-ClusterNode" - Invoke-CatchActions - } + try { + $getClusterNode = Get-ClusterNode -Name $Server -ErrorAction Stop + } catch { + Write-Verbose "Failed to run Get-ClusterNode" + Invoke-CatchActions + } - Write-Verbose "Running ServerComponentStates checks" + Write-Verbose "Running ServerComponentStates checks" - foreach ($component in $serverMaintenance.GetServerComponentState) { - if (($null -ne $ComponentsToSkip -and - $ComponentsToSkip.Count -ne 0) -and - $ComponentsToSkip -notcontains $component.Component) { - if ($component.State.ToString() -ne "Active") { - $latestLocalState = $null - $latestRemoteState = $null + foreach ($component in $getServerComponentState) { + if (($null -ne $ComponentsToSkip -and + $ComponentsToSkip.Count -ne 0) -and + $ComponentsToSkip -notcontains $component.Component) { + if ($component.State.ToString() -ne "Active") { + $latestLocalState = $null + $latestRemoteState = $null - if ($null -ne $component.LocalStates -and - $component.LocalStates.Count -gt 0) { - $latestLocalState = ($component.LocalStates | Sort-Object { $_.TimeStamp } -ErrorAction SilentlyContinue)[-1] - } + if ($null -ne $component.LocalStates -and + $component.LocalStates.Count -gt 0) { + $latestLocalState = ($component.LocalStates | Sort-Object { $_.TimeStamp } -ErrorAction SilentlyContinue)[-1] + } - if ($null -ne $component.RemoteStates -and - $component.RemoteStates.Count -gt 0) { - $latestRemoteState = ($component.RemoteStates | Sort-Object { $_.TimeStamp } -ErrorAction SilentlyContinue)[-1] - } + if ($null -ne $component.RemoteStates -and + $component.RemoteStates.Count -gt 0) { + $latestRemoteState = ($component.RemoteStates | Sort-Object { $_.TimeStamp } -ErrorAction SilentlyContinue)[-1] + } - Write-Verbose "Component: '$($component.Component)' LocalState: '$($latestLocalState.State)' RemoteState: '$($latestRemoteState.State)'" + Write-Verbose "Component: '$($component.Component)' LocalState: '$($latestLocalState.State)' RemoteState: '$($latestRemoteState.State)'" - if ($latestLocalState.State -eq $latestRemoteState.State) { - $serverMaintenance.InactiveComponents += "'{0}' is in Maintenance Mode" -f $component.Component - } else { - if (($null -ne $latestLocalState) -and + if ($latestLocalState.State -eq $latestRemoteState.State) { + $inactiveComponents += "'{0}' is in Maintenance Mode" -f $component.Component + } else { + if (($null -ne $latestLocalState) -and ($latestLocalState.State -ne "Active")) { - $serverMaintenance.InactiveComponents += "'{0}' is in Local Maintenance Mode only" -f $component.Component - } + $inactiveComponents += "'{0}' is in Local Maintenance Mode only" -f $component.Component + } - if (($null -ne $latestRemoteState) -and + if (($null -ne $latestRemoteState) -and ($latestRemoteState.State -ne "Active")) { - $serverMaintenance.InactiveComponents += "'{0}' is in Remote Maintenance Mode only" -f $component.Component + $inactiveComponents += "'{0}' is in Remote Maintenance Mode only" -f $component.Component + } } + } else { + Write-Verbose "Component '$($component.Component)' is Active" } } else { - Write-Verbose "Component '$($component.Component)' is Active" + Write-Verbose "Component: $($component.Component) will be skipped" } - } else { - Write-Verbose "Component: $($component.Component) will be skipped" } - } + } end { - return $serverMaintenance + return [PSCustomObject]@{ + InactiveComponents = $inactiveComponents + GetServerComponentState = $getServerComponentState + GetClusterNode = $getClusterNode + } + } } diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-FIPFSScanEngineVersionState.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-FIPFSScanEngineVersionState.ps1 index eac25fa6be..99268d8750 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-FIPFSScanEngineVersionState.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-FIPFSScanEngineVersionState.ps1 @@ -15,8 +15,8 @@ function Get-FIPFSScanEngineVersionState { [System.Version] $ExSetupVersion, [Parameter(Mandatory = $true)] - [HealthChecker.ExchangeServerRole] - $ServerRole + [bool] + $AffectedServerRole ) begin { @@ -83,25 +83,6 @@ function Get-FIPFSScanEngineVersionState { return $null } - function IsServerRoleAffected { - param ( - [HealthChecker.ExchangeServerRole] - $ServerRole - ) - - Write-Verbose "Calling: $($MyInvocation.MyCommand)" - - # Affected roles are Hub Transport, Mailbox and MultiRole - if (($ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) -and - ($ServerRole -ne [HealthChecker.ExchangeServerRole]::None) -and - ($ServerRole -ne [HealthChecker.ExchangeServerRole]::ClientAccess)) { - Write-Verbose "Server role is affected by this FIP-FS issue" - return $true - } else { - Write-Verbose "Server role is NOT affected by this FIP-FS issue" - return $false - } - } function IsFIPFSFixedBuild { param ( [System.Version] @@ -137,8 +118,7 @@ function Get-FIPFSScanEngineVersionState { $isAffectedByFIPFSUpdateIssue = $false try { - $serverRoleAffected = IsServerRoleAffected -ServerRole $ServerRole - if ($serverRoleAffected) { + if ($AffectedServerRole) { $highestScanEngineVersionNumber = GetHighestScanEngineVersionNumber -ComputerName $ComputerName $fipFsIssueFixedBuild = IsFIPFSFixedBuild -BuildNumber $ExSetupVersion @@ -163,7 +143,7 @@ function Get-FIPFSScanEngineVersionState { } end { return [PSCustomObject]@{ FIPFSFixedBuild = $fipFsIssueFixedBuild - ServerRoleAffected = $serverRoleAffected + ServerRoleAffected = $AffectedServerRole HighestVersionNumberDetected = $highestScanEngineVersionNumber BadVersionNumberDirDetected = $isAffectedByFIPFSUpdateIssue } diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 index 6f4451737a..49bf2f0019 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-HealthCheckerExchangeServer.ps1 @@ -15,20 +15,22 @@ function Get-HealthCheckerExchangeServer { [object]$PassedOrganizationInformation ) - Write-Verbose "Calling: $($MyInvocation.MyCommand)" + process { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" - [HealthChecker.HealthCheckerExchangeServer]$HealthExSvrObj = New-Object -TypeName HealthChecker.HealthCheckerExchangeServer - $HealthExSvrObj.ServerName = $ServerName - $HealthExSvrObj.HardwareInformation = Get-HardwareInformation -Server $ServerName - $HealthExSvrObj.OSInformation = Get-OperatingSystemInformation -Server $ServerName - $HealthExSvrObj.ExchangeInformation = Get-ExchangeInformation -Server $ServerName -OSMajorVersion $HealthExSvrObj.OSInformation.BuildInformation.MajorVersion -PassedOrganizationInformation $PassedOrganizationInformation - - if ($HealthExSvrObj.OSInformation.NETFramework.MajorVersion -eq $HealthExSvrObj.ExchangeInformation.NETFramework.MaxSupportedVersion) { - $HealthExSvrObj.ExchangeInformation.NETFramework.OnRecommendedVersion = $true + $hardwareInformation = Get-HardwareInformation -Server $ServerName + $osInformation = Get-OperatingSystemInformation -Server $ServerName + $exchangeInformation = Get-ExchangeInformation -Server $ServerName -PassedOrganizationInformation $PassedOrganizationInformation + } end { + Write-Verbose "Finished building health Exchange Server Object for server: $ServerName" + return [PSCustomObject]@{ + ServerName = $ServerName + HardwareInformation = $hardwareInformation + OSInformation = $osInformation + ExchangeInformation = $exchangeInformation + HealthCheckerVersion = $BuildVersion + OrganizationInformation = $null + GenerationTime = [DateTime]::Now + } } - - $HealthExSvrObj.HealthCheckerVersion = $BuildVersion - $HealthExSvrObj.GenerationTime = [DateTime]::Now - Write-Verbose "Finished building health Exchange Server Object for server: $ServerName" - return $HealthExSvrObj } diff --git a/Diagnostics/HealthChecker/Features/Get-HealthCheckerData.ps1 b/Diagnostics/HealthChecker/Features/Get-HealthCheckerData.ps1 index 7607982f83..15fa0998e9 100644 --- a/Diagnostics/HealthChecker/Features/Get-HealthCheckerData.ps1 +++ b/Diagnostics/HealthChecker/Features/Get-HealthCheckerData.ps1 @@ -102,7 +102,7 @@ function Get-HealthCheckerData { try { Invoke-SetOutputInstanceLocation -Server $serverName -FileName "HealthChecker" -IncludeServerName $true Write-HostLog "Exchange Health Checker version $BuildVersion" - [HealthChecker.HealthCheckerExchangeServer]$HealthObject = Get-HealthCheckerExchangeServer -ServerName $serverNameParam -PassedOrganizationInformation $passedOrganizationInformation + $HealthObject = Get-HealthCheckerExchangeServer -ServerName $serverNameParam -PassedOrganizationInformation $passedOrganizationInformation $HealthObject.OrganizationInformation = $organizationInformation $paramWriteProgress.Status = "Analyzing Data" diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index db462869c5..29d66abac3 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -11,68 +11,12 @@ using System.Collections; public string ServerName; //String of the server that we are working with public object HardwareInformation; // Hardware Object Information public object OSInformation; // OS Version Object Information - public ExchangeInformation ExchangeInformation; //Detailed Exchange Information + public object ExchangeInformation; //Detailed Exchange Information public object OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. public string HealthCheckerVersion; //To determine the version of the script on the object. public DateTime GenerationTime; //Time stamp of running the script } - // ExchangeInformation - public class ExchangeInformation - { - public ExchangeBuildInformation BuildInformation = new ExchangeBuildInformation(); //Exchange build information - public object GetExchangeServer; //Stores the Get-ExchangeServer Object - public object GetMailboxServer; //Stores the Get-MailboxServer Object - public object GetOwaVirtualDirectory; //Stores the Get-OwaVirtualDirectory Object - public object GetWebServicesVirtualDirectory; //stores the Get-WebServicesVirtualDirectory object - public object GetOrganizationConfig; //Stores the result from Get-OrganizationConfig - public object ExchangeAdPermissions; //Stores the Exchange AD permissions for vulnerability testing - public object ExtendedProtectionConfig; //Stores the extended protection configuration - public object ExchangeConnectors; //Stores the Get-ExchangeConnectors Object - public System.Array AMSIConfiguration; //Stores the Setting Override for AMSI Interface - public System.Array SerializationDataSigningConfiguration; //Stores for the SerializationDataSigning feature configuration - public ExchangeNetFrameworkInformation NETFramework = new ExchangeNetFrameworkInformation(); - public System.Array ExchangeServicesNotRunning; //Contains the Exchange services not running by Test-ServiceHealth - public Hashtable ApplicationPools = new Hashtable(); - public object RegistryValues; //stores all Exchange Registry values - public ExchangeServerMaintenance ServerMaintenance; - public System.Array ExchangeCertificates; //stores all the Exchange certificates on the servers. - public object ExchangeEmergencyMitigationService; //stores the Exchange Emergency Mitigation Service (EEMS) object - public Hashtable ApplicationConfigFileStatus = new Hashtable(); - public object DependentServices; // store the results for the dependent services of Exchange. - public object IISSettings; //Stores the IISConfigurationSettings, applicationHostConfig and IISModulesInformation - public object SettingOverrides; //Stores the information regarding the Exchange Setting Overrides on the server. - } - - public class ExchangeBuildInformation - { - public ExchangeServerRole ServerRole; //Roles that are currently set and installed. - public ExchangeMajorVersion MajorVersion; //Exchange Version (Exchange 2010/2013/2019) - public ExchangeCULevel CU; // Exchange CU Level - public object VersionInformation; // Stores results from Get-ExchangeBuildVersionInformation - public System.Version LocalBuildNumber; //Local Build Number. Is only populated if from a Tools Machine - public object ExchangeSetup; //Stores the Get-Command ExSetup object - public System.Array KBsInstalled; //Stored object IU or Security KB fixes - public bool March2021SUInstalled; //True if March 2021 SU is installed - public object FIPFSUpdateIssue; //Stores FIP-FS update issue information - } - - public class ExchangeNetFrameworkInformation - { - public NetMajorVersion MinSupportedVersion; //Min Supported .NET Framework version - public NetMajorVersion MaxSupportedVersion; //Max (Recommended) Supported .NET version. - public bool OnRecommendedVersion; //RecommendedNetVersion Info includes all the factors. Windows Version & CU. - public string DisplayWording; //Display if we are in Support or not - } - - public class ExchangeServerMaintenance - { - public System.Array InactiveComponents; - public object GetServerComponentState; - public object GetClusterNode; - public object GetMailboxServer; //TODO: Remove this - } - //enum for CU levels of Exchange public enum ExchangeCULevel { From 180ceb7db361f9c4d8ed17f7ebfba63888ae9175 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 20 Jan 2023 20:30:56 -0600 Subject: [PATCH 10/33] Update to address pester results --- ...Invoke-AnalyzerFrequentConfigurationIssues.ps1 | 15 +++++++++------ .../Security/Invoke-AnalyzerSecuritySettings.ps1 | 4 ++-- .../Get-ExchangeInformation.ps1 | 1 - .../Get-FIPFSScanEngineVersionState.Tests.ps1 | 15 ++++++--------- .../Get-OrganizationInformation.ps1 | 8 ++++---- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 index 9eebe4db56..53e9a6db89 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 @@ -144,15 +144,18 @@ function Invoke-AnalyzerFrequentConfigurationIssues { } } - $displayWriteType = "Grey" - $displayValue = "Not Set" + $displayWriteType = "Yellow" + $displayValue = "Unknown - Unable to run Get-AcceptedDomain" $additionalDisplayValue = [string]::Empty - if ($null -ne $organizationInformation.WildCardAcceptedDomain) { + if ($null -ne $organizationInformation.GetAcceptedDomain -and + $organizationInformation.GetAcceptedDomain -ne "Unknown") { + + $wildCardAcceptedDomain = $organizationInformation.GetAcceptedDomain | Where-Object { $_.DomainName.ToString() -eq "*" } - if ($organizationInformation.WildCardAcceptedDomain -eq "Unknown") { - $displayValue = "Unknown - Unable to run Get-AcceptedDomain" - $displayWriteType = "Yellow" + if ($null -eq $wildCardAcceptedDomain) { + $displayValue = "Not Set" + $displayWriteType = "Grey" } else { $displayWriteType = "Red" $domain = $organizationInformation.WildCardAcceptedDomain diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index 254002c626..2374da599a 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -389,8 +389,8 @@ function Invoke-AnalyzerSecuritySettings { Invoke-AnalyzerSecuritySerializedDataSigningState -AnalyzeResults $AnalyzeResults -HealthServerObject $HealthServerObject -DisplayGroupingKey $keySecuritySettings Invoke-AnalyzerSecurityMitigationService -AnalyzeResults $AnalyzeResults -HealthServerObject $HealthServerObject -DisplayGroupingKey $keySecuritySettings - if ($null -ne $HealthServerObject.ExchangeInformation.BuildInformation.FIPFSUpdateIssue) { - $fipFsInfoObject = $HealthServerObject.ExchangeInformation.BuildInformation.FIPFSUpdateIssue + if ($null -ne $HealthServerObject.ExchangeInformation.FIPFSUpdateIssue) { + $fipFsInfoObject = $HealthServerObject.ExchangeInformation.FIPFSUpdateIssue $highestVersion = $fipFsInfoObject.HighestVersionNumberDetected $fipFsIssueBaseParams = @{ Name = "FIP-FS Update Issue Detected" diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index dd52b85ed2..67493c1499 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -48,7 +48,6 @@ function Get-ExchangeInformation { CU = $versionInformation.CU ExchangeSetup = $exSetupDetails VersionInformation = $versionInformation - LocalBuildNumber = "$($Script:ExchangeShellComputer.Major).$($Script:ExchangeShellComputer.Minor).$($Script:ExchangeShellComputer.Build).$($Script:ExchangeShellComputer.Revision)" KBsInstalled = Get-ExchangeUpdates -Server $Server -ExchangeMajorVersion $versionInformation.MajorVersion } diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 index a8ad6028ba..1a06498248 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 @@ -15,7 +15,6 @@ BeforeAll { param() } - $Script:serverRoles = New-Object HealthChecker.ExchangeServerRole [System.Version]$Script:fixed = "15.1.2308.27" [System.Version]$Script:notFixed = "15.1.2300.20" } @@ -25,7 +24,7 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { Context "Invalid Pattern Detected On Affected Exchange Build" { BeforeAll { Mock Invoke-ScriptBlockHandler -MockWith { return Import-Clixml $Script:parentPath\Tests\DataCollection\GetChildItemInvalidPattern.xml } - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -ServerRole $Script:serverRoles + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -AffectedServerRole $true } It "System Affected By Transport Queue Issue" { @@ -39,7 +38,7 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { Context "Valid Pattern Detected On Affected Exchange Build" { BeforeAll { Mock Invoke-ScriptBlockHandler -MockWith { return Import-Clixml $Script:parentPath\Tests\DataCollection\GetChildItemValidPattern.xml } - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -ServerRole $Script:serverRoles + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -AffectedServerRole $true } It "System NOT Affected By Transport Queue Issue" { @@ -53,7 +52,7 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { Context "Invalid Pattern Detected On Fixed Exchange Build" { BeforeAll { Mock Invoke-ScriptBlockHandler -MockWith { return Import-Clixml $Script:parentPath\Tests\DataCollection\GetChildItemInvalidPattern.xml } - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:Fixed -ServerRole $Script:serverRoles + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:Fixed -AffectedServerRole $true } It "System NOT Affected By Transport Queue Issue Due To Fixed Exchange Build" { @@ -66,10 +65,8 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { Context "Exchange Server Role Not Affected" { BeforeAll { - $edgeRole = $Script:serverRoles - $edgeRole = [HealthChecker.ExchangeServerRole]::Edge Mock Invoke-ScriptBlockHandler -MockWith { return Import-Clixml $Script:parentPath\Tests\DataCollection\GetChildItemInvalidPattern.xml } - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:Fixed -ServerRole $edgeRole + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:Fixed -AffectedServerRole $false } It "Edge Transport Server Role Isn't Affected" { @@ -87,7 +84,7 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { } It "HighestVersionNumberDetected return null" { - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -ServerRole $Script:serverRoles + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -AffectedServerRole $true $results.HighestVersionNumberDetected | Should -Be $null $results.BadVersionNumberDirDetected | Should -Be $false Assert-MockCalled -CommandName Write-Verbose -Exactly 1 -ParameterFilter { $Message -eq "No FIP-FS scan engine version(s) detected - GetFolderFromExchangeInstallPath returned null" } @@ -101,7 +98,7 @@ Describe "Testing Get-FIPFSScanEngineVersionState.ps1" { } It "HighestVersionNumberDetected return null" { - $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -ServerRole $Script:serverRoles + $Script:results = Get-FIPFSScanEngineVersionState -ComputerName $Script:Server -ExSetupVersion $Script:notFixed -AffectedServerRole $true $results.HighestVersionNumberDetected | Should -Be $null $results.BadVersionNumberDirDetected | Should -Be $false Assert-MockCalled -CommandName Write-Verbose -Exactly 1 -ParameterFilter { $Message -eq "Failed to find the scan engine directory" } diff --git a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 index 4e9f298163..82f39aa1c6 100644 --- a/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/OrganizationInformation/Get-OrganizationInformation.ps1 @@ -21,7 +21,7 @@ function Get-OrganizationInformation { $adSchemaInformation = $null $getHybridConfiguration = $null $enableDownloadDomains = $null - $wildCardAcceptedDomain = $null + $getAcceptedDomain = $null $mapiHttpEnabled = $false $securityResults = $null $isSplitADPermissions = $false @@ -52,10 +52,10 @@ function Get-OrganizationInformation { } try { - $wildCardAcceptedDomain = Get-AcceptedDomain -ErrorAction Stop | Where-Object { $_.DomainName.ToString() -eq "*" } + $getAcceptedDomain = Get-AcceptedDomain -ErrorAction Stop } catch { Write-Verbose "Failed to run Get-AcceptedDomain" - $wildCardAcceptedDomain = "Unknown" + $getAcceptedDomain = "Unknown" Invoke-CatchActions } @@ -130,7 +130,7 @@ function Get-OrganizationInformation { AdSchemaInformation = $adSchemaInformation GetHybridConfiguration = $getHybridConfiguration EnableDownloadDomains = $enableDownloadDomains - WildCardAcceptedDomain = $wildCardAcceptedDomain + GetAcceptedDomain = $getAcceptedDomain MapiHttpEnabled = $mapiHttpEnabled SecurityResults = $securityResults IsSplitADPermissions = $isSplitADPermissions From c9804dbf3545953b6bf2f634f24d18a664a62c14 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Mon, 23 Jan 2023 11:56:55 -0600 Subject: [PATCH 11/33] Be able to reverse lookup build number by Exchange CU/SU level --- .../Get-ExchangeBuildVersionInformation.ps1 | 368 +++++++++++++----- ...-ExchangeBuildVersionInformation.Tests.ps1 | 45 ++- 2 files changed, 309 insertions(+), 104 deletions(-) diff --git a/Shared/Get-ExchangeBuildVersionInformation.ps1 b/Shared/Get-ExchangeBuildVersionInformation.ps1 index 29bec1d42a..aa63639e3c 100644 --- a/Shared/Get-ExchangeBuildVersionInformation.ps1 +++ b/Shared/Get-ExchangeBuildVersionInformation.ps1 @@ -3,6 +3,9 @@ . $PSScriptRoot\Invoke-CatchActionError.ps1 +# This function is used to determine the version of Exchange based off a build number or +# by providing the Exchange Version and CU and/or SU. This provides one location in the entire repository +# that is required to be updated for when a new release of Exchange is dropped. function Get-ExchangeBuildVersionInformation { [CmdletBinding(DefaultParameterSetName = "AdminDisplayVersion")] param( @@ -12,10 +15,170 @@ function Get-ExchangeBuildVersionInformation { [Parameter(ParameterSetName = "ExSetup")] [System.Version]$FileVersion, + [Parameter(ParameterSetName = "VersionCU", Mandatory = $true)] + [ValidateSet("Exchange2013", "Exchange2016", "Exchange2019")] + [string]$Version, + + [Parameter(ParameterSetName = "VersionCU", Mandatory = $true)] + [ValidateSet("CU1", "CU2", "CU3", "CU4", "CU5", "CU6", "CU7", "CU8", + "CU9", "CU10", "CU11", "CU12", "CU13", "CU14", "CU15", "CU16", "CU17", + "CU18", "CU19", "CU20", "CU21", "CU22", "CU23")] + [string]$CU, + + [Parameter(ParameterSetName = "VersionCU", Mandatory = $false)] + [ValidateSet("Mar21SU", "Apr21SU", "May21SU", "Jul21SU", "Oct21SU", + "Nov21SU", "Jan22SU", "Mar22SU", "May22SU", "Aug22SU", "Oct22SU", + "Nov22SU", "Jan23SU")] + [string]$SU, + [Parameter(Mandatory = $false)] [ScriptBlock]$CatchActionFunction ) begin { + + function NewCUAndSUObject { + param( + [string]$CUBuildNumber, + [Hashtable]$SUBuildNumber + ) + return @{ + "CU" = $CUBuildNumber + "SU" = $SUBuildNumber + } + } + + function GetBuildVersion { + param( + [Parameter(Position = 1)] + [string]$ExchangeVersion, + [Parameter(Position = 2)] + [string]$CU, + [Parameter(Position = 3)] + [string]$SU + ) + $cuResult = $exchangeBuildDictionary[$ExchangeVersion][$CU] + + if ((-not [string]::IsNullOrEmpty($SU)) -and + $cuResult.SU.ContainsKey($SU)) { + return $cuResult.SU[$SU] + } else { + return $cuResult.CU + } + } + + # Dictionary of Exchange Version/CU/SU to build number + $exchangeBuildDictionary = @{ + "Exchange2013" = @{ + "CU1" = (NewCUAndSUObject "15.0.620.29") + "CU2" = (NewCUAndSUObject "15.0.712.24") + "CU3" = (NewCUAndSUObject "15.0.775.38") + "CU4" = (NewCUAndSUObject "15.0.847.32") + "CU5" = (NewCUAndSUObject "15.0.913.22") + "CU6" = (NewCUAndSUObject "15.0.995.29") + "CU7" = (NewCUAndSUObject "15.0.1044.25") + "CU8" = (NewCUAndSUObject "15.0.1076.9") + "CU9" = (NewCUAndSUObject "15.0.1104.5") + "CU10" = (NewCUAndSUObject "15.0.1130.7") + "CU11" = (NewCUAndSUObject "15.0.1156.6") + "CU12" = (NewCUAndSUObject "15.0.1178.4") + "CU13" = (NewCUAndSUObject "15.0.1210.3") + "CU14" = (NewCUAndSUObject "15.0.1236.3") + "CU15" = (NewCUAndSUObject "15.0.1263.5") + "CU16" = (NewCUAndSUObject "15.0.1293.2") + "CU17" = (NewCUAndSUObject "15.0.1320.4") + "CU18" = (NewCUAndSUObject "15.0.1347.2") + "CU19" = (NewCUAndSUObject "15.0.1365.1") + "CU20" = (NewCUAndSUObject "15.0.1367.3") + "CU21" = (NewCUAndSUObject "15.0.1395.4") + "CU22" = (NewCUAndSUObject "15.0.1473.3") + "CU23" = (NewCUAndSUObject "15.0.1497.2" @{ + "Mar21SU" = "15.0.1497.12" + "Apr21SU" = "15.0.1497.15" + "May21SU" = "15.0.1497.18" + "Jul21SU" = "15.0.1497.23" + "Oct21SU" = "15.0.1497.24" + "Nov21SU" = "15.0.1497.26" + "Jan22SU" = "15.0.1497.28" + "Mar22SU" = "15.0.1497.33" + "May22SU" = "15.0.1497.36" + "Aug22SU" = "15.0.1497.40" + "Oct22SU" = "15.0.1497.42" + "Nov22SU" = "15.0.1497.44" + "Jan23SU" = "15.0.1497.45" + }) + } + "Exchange2016" = @{ + "CU1" = (NewCUAndSUObject "15.1.396.30") + "CU2" = (NewCUAndSUObject "15.1.466.34") + "CU3" = (NewCUAndSUObject "15.1.544.27") + "CU4" = (NewCUAndSUObject "15.1.669.32") + "CU5" = (NewCUAndSUObject "15.1.845.34") + "CU6" = (NewCUAndSUObject "15.1.1034.26") + "CU7" = (NewCUAndSUObject "15.1.1261.35") + "CU8" = (NewCUAndSUObject "15.1.1415.2") + "CU9" = (NewCUAndSUObject "15.1.1466.3") + "CU10" = (NewCUAndSUObject "15.1.1531.3") + "CU11" = (NewCUAndSUObject "15.1.1591.10") + "CU12" = (NewCUAndSUObject "15.1.1713.5") + "CU13" = (NewCUAndSUObject "15.1.1779.2") + "CU14" = (NewCUAndSUObject "15.1.1847.3") + "CU15" = (NewCUAndSUObject "15.1.1913.5") + "CU16" = (NewCUAndSUObject "15.1.1979.3") + "CU17" = (NewCUAndSUObject "15.1.2044.4") + "CU18" = (NewCUAndSUObject "15.1.2106.2") + "CU19" = (NewCUAndSUObject "15.1.2176.2") + "CU20" = (NewCUAndSUObject "15.1.2242.4") + "CU21" = (NewCUAndSUObject "15.1.2308.8") + "CU22" = (NewCUAndSUObject "15.1.2375.7" @{ + "Oct21SU" = "15.1.2375.12" + "Nov21SU" = "15.1.2375.17" + "Jan22SU" = "15.1.2375.18" + "Mar22SU" = "15.1.2375.24" + "May22SU" = "15.1.2375.28" + "Aug22SU" = "15.1.2375.31" + "Oct22SU" = "15.1.2375.32" + "Nov22SU" = "15.1.2375.37" + }) + "CU23" = (NewCUAndSUObject "15.1.2507.6" @{ + "May22SU" = "15.1.2507.9" + "Aug22SU" = "15.1.2507.12" + "Oct22SU" = "15.1.2507.13" + "Nov22SU" = "15.1.2507.16" + "Jan23SU" = "15.1.2507.17" + }) + } + "Exchange2019" = @{ + "CU1" = (NewCUAndSUObject "15.2.330.5") + "CU2" = (NewCUAndSUObject "15.2.397.3") + "CU3" = (NewCUAndSUObject "15.2.464.5") + "CU4" = (NewCUAndSUObject "15.2.529.5") + "CU5" = (NewCUAndSUObject "15.2.595.3") + "CU6" = (NewCUAndSUObject "15.2.659.4") + "CU7" = (NewCUAndSUObject "15.2.721.2") + "CU8" = (NewCUAndSUObject "15.2.792.3") + "CU9" = (NewCUAndSUObject "15.2.858.5") + "CU10" = (NewCUAndSUObject "15.2.922.7") + "CU11" = (NewCUAndSUObject "15.2.986.5" @{ + "Oct21SU" = "15.2.986.9" + "Nov21SU" = "15.2.986.14" + "Jan22SU" = "15.2.986.15" + "Mar22SU" = "15.2.986.22" + "May22SU" = "15.2.986.26" + "Aug22SU" = "15.2.986.29" + "Oct22SU" = "15.2.986.30" + "Nov22SU" = "15.2.986.36" + "Jan23SU" = "15.2.986.37" + }) + "CU12" = (NewCUAndSUObject "15.2.1118.7" @{ + "May22SU" = "15.2.1118.9" + "Aug22SU" = "15.2.1118.12" + "Oct22SU" = "15.2.1118.15" + "Nov22SU" = "15.2.1118.20" + "Jan23SU" = "15.2.1118.21" + }) + } + } + Write-Verbose "Calling: $($MyInvocation.MyCommand)" $exchangeMajorVersion = [string]::Empty $exchangeVersion = $null @@ -29,11 +192,16 @@ function Get-ExchangeBuildVersionInformation { $orgValue = 0 $schemaValue = 0 $mesoValue = 0 + $ex19 = "Exchange2019" + $ex16 = "Exchange2016" + $ex13 = "Exchange2013" } process { # Convert both input types to a [System.Version] try { - if ($PSCmdlet.ParameterSetName -eq "AdminDisplayVersion") { + if ($PSCmdlet.ParameterSetName -eq "VersionCU") { + [System.Version]$exchangeVersion = GetBuildVersion -ExchangeVersion $Version -CU $CU -SU $SU + } elseif ($PSCmdlet.ParameterSetName -eq "AdminDisplayVersion") { $AdminDisplayVersion = $AdminDisplayVersion.ToString() Write-Verbose "Passed AdminDisplayVersion: $AdminDisplayVersion" $split1 = $AdminDisplayVersion.Substring(($AdminDisplayVersion.IndexOf(" ")) + 1, 4).Split(".") @@ -65,89 +233,89 @@ function Get-ExchangeBuildVersionInformation { $orgValue = 16760 switch ($exchangeVersion) { - { $_ -ge "15.2.1118.7" } { + { $_ -ge (GetBuildVersion $ex19 "CU12") } { $cuLevel = "CU12" $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true } - "15.2.1118.21" { $suName = "Jan23SU"; $latestSUBuild = $true } - "15.2.1118.20" { $suName = "Nov22SU" } - "15.2.1118.15" { $suName = "Oct22SU" } - "15.2.1118.12" { $suName = "Aug22SU" } - "15.2.1118.9" { $suName = "May22SU" } - { $_ -lt "15.2.1118.7" } { + (GetBuildVersion $ex19 "CU12" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } + (GetBuildVersion $ex19 "CU12" -SU "Nov22SU") { $suName = "Nov22SU" } + (GetBuildVersion $ex19 "CU12" -SU "Oct22SU") { $suName = "Oct22SU" } + (GetBuildVersion $ex19 "CU12" -SU "Aug22SU") { $suName = "Aug22SU" } + (GetBuildVersion $ex19 "CU12" -SU "May22SU") { $suName = "May22SU" } + { $_ -lt (GetBuildVersion $ex19 "CU12") } { $cuLevel = "CU11" $cuReleaseDate = "09/28/2021" $supportedBuildNumber = $true $mesoValue = 13242 $orgValue = 16759 } - "15.2.986.37" { $suName = "Jan23SU"; $latestSUBuild = $true } - "15.2.986.36" { $suName = "Nov22SU" } - "15.2.986.30" { $suName = "Oct22SU" } - "15.2.986.29" { $suName = "Aug22SU" } - "15.2.986.26" { $suName = "May22SU"; $mesoValue = 13243 } - "15.2.986.22" { $suName = "Mar22SU" } - "15.2.986.15" { $suName = "Jan22SU" } - "15.2.986.14" { $suName = "Nov21SU" } - "15.2.986.9" { $suName = "Oct21SU" } - { $_ -lt "15.2.986.5" } { + (GetBuildVersion $ex19 "CU11" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } + (GetBuildVersion $ex19 "CU11" -SU "Nov22SU") { $suName = "Nov22SU" } + (GetBuildVersion $ex19 "CU11" -SU "Oct22SU") { $suName = "Oct22SU" } + (GetBuildVersion $ex19 "CU11" -SU "Aug22SU") { $suName = "Aug22SU" } + (GetBuildVersion $ex19 "CU11" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13243 } + (GetBuildVersion $ex19 "CU11" -SU "Mar22SU") { $suName = "Mar22SU" } + (GetBuildVersion $ex19 "CU11" -SU "Jan22SU") { $suName = "Jan22SU" } + (GetBuildVersion $ex19 "CU11" -SU "Nov21SU") { $suName = "Nov21SU" } + (GetBuildVersion $ex19 "CU11" -SU "Oct21SU") { $suName = "Oct21SU" } + { $_ -lt (GetBuildVersion $ex19 "CU11") } { $cuLevel = "CU10" $cuReleaseDate = "06/29/2021" $mesoValue = 13241 $orgValue = 16758 $supportedBuildNumber = $false } - { $_ -lt "15.2.922.7" } { + { $_ -lt (GetBuildVersion $ex19 "CU10") } { $cuLevel = "CU9" $cuReleaseDate = "03/16/2021" $schemaValue = 17002 $mesoValue = 13240 $orgValue = 16757 } - { $_ -lt "15.2.858.5" } { + { $_ -lt (GetBuildVersion $ex19 "CU9") } { $cuLevel = "CU8" $cuReleaseDate = "12/15/2020" $mesoValue = 13239 $orgValue = 16756 } - { $_ -lt "15.2.792.3" } { + { $_ -lt (GetBuildVersion $ex19 "CU8") } { $cuLevel = "CU7" $cuReleaseDate = "09/15/2020" $schemaValue = 17001 $mesoValue = 13238 $orgValue = 16755 } - { $_ -lt "15.2.721.2" } { + { $_ -lt (GetBuildVersion $ex19 "CU7") } { $cuLevel = "CU6" $cuReleaseDate = "06/16/2020" $mesoValue = 13237 $orgValue = 16754 } - { $_ -lt "15.2.659.4" } { + { $_ -lt (GetBuildVersion $ex19 "CU6") } { $cuLevel = "CU5" $cuReleaseDate = "03/17/2020" } - { $_ -lt "15.2.595.3" } { + { $_ -lt (GetBuildVersion $ex19 "CU5") } { $cuLevel = "CU4" $cuReleaseDate = "12/17/2019" } - { $_ -lt "15.2.529.5" } { + { $_ -lt (GetBuildVersion $ex19 "CU4") } { $cuLevel = "CU3" $cuReleaseDate = "09/17/2019" } - { $_ -lt "15.2.464.5" } { + { $_ -lt (GetBuildVersion $ex19 "CU3") } { $cuLevel = "CU2" $cuReleaseDate = "06/18/2019" } - { $_ -lt "15.2.397.3" } { + { $_ -lt (GetBuildVersion $ex19 "CU2") } { $cuLevel = "CU1" $cuReleaseDate = "02/12/2019" $schemaValue = 17000 $mesoValue = 13236 $orgValue = 16752 } - { $_ -lt "15.2.330.5" } { + { $_ -lt (GetBuildVersion $ex19 "CU1") } { $cuLevel = "RTM" $cuReleaseDate = "10/22/2018" $orgValue = 16751 @@ -165,132 +333,132 @@ function Get-ExchangeBuildVersionInformation { $orgValue = 16223 switch ($exchangeVersion) { - { $_ -ge "15.1.2507.6" } { + { $_ -ge (GetBuildVersion $ex16 "CU23") } { $cuLevel = "CU23" $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true } - "15.1.2507.17" { $suName = "Jan23SU"; $latestSUBuild = $true } - "15.1.2507.16" { $suName = "Nov22SU" } - "15.1.2507.13" { $suName = "Oct22SU" } - "15.1.2507.12" { $suName = "Aug22SU" } - "15.1.2507.9" { $suName = "May22SU" } - { $_ -lt "15.1.2507.6" } { + (GetBuildVersion $ex16 "CU23" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } + (GetBuildVersion $ex16 "CU23" -SU "Nov22SU") { $suName = "Nov22SU" } + (GetBuildVersion $ex16 "CU23" -SU "Oct22SU") { $suName = "Oct22SU" } + (GetBuildVersion $ex16 "CU23" -SU "Aug22SU") { $suName = "Aug22SU" } + (GetBuildVersion $ex16 "CU23" -SU "May22SU") { $suName = "May22SU" } + { $_ -lt (GetBuildVersion $ex16 "CU23") } { $cuLevel = "CU22" $cuReleaseDate = "09/28/2021" $supportedBuildNumber = $false $mesoValue = 13242 $orgValue = 16222 } - "15.1.2375.37" { $suName = "Nov22SU"; $latestSUBuild = $true } - "15.1.2375.32" { $suName = "Oct22SU" } - "15.1.2375.31" { $suName = "Aug22SU" } - "15.1.2375.28" { $suName = "May22SU"; $mesoValue = 13243 } - "15.1.2375.24" { $suName = "Mar22SU" } - "15.1.2375.18" { $suName = "Jan22SU" } - "15.1.2375.17" { $suName = "Nov21SU" } - "15.1.2375.12" { $suName = "Oct21SU" } - { $_ -lt "15.1.2375.7" } { + (GetBuildVersion $ex16 "CU22" -SU "Nov22SU") { $suName = "Nov22SU" } + (GetBuildVersion $ex16 "CU22" -SU "Oct22SU") { $suName = "Oct22SU" } + (GetBuildVersion $ex16 "CU22" -SU "Aug22SU") { $suName = "Aug22SU" } + (GetBuildVersion $ex16 "CU22" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13243 } + (GetBuildVersion $ex16 "CU22" -SU "Mar22SU") { $suName = "Mar22SU" } + (GetBuildVersion $ex16 "CU22" -SU "Jan22SU") { $suName = "Jan22SU" } + (GetBuildVersion $ex16 "CU22" -SU "Nov21SU") { $suName = "Nov21SU" } + (GetBuildVersion $ex16 "CU22" -SU "Oct21SU") { $suName = "Oct21SU" } + { $_ -lt (GetBuildVersion $ex16 "CU22") } { $cuLevel = "CU21" $cuReleaseDate = "06/29/2021" $mesoValue = 13241 $orgValue = 16221 } - { $_ -lt "15.1.2308.8" } { + { $_ -lt (GetBuildVersion $ex16 "CU21") } { $cuLevel = "CU20" $cuReleaseDate = "03/16/2021" $schemaValue = 15333 $mesoValue = 13240 $orgValue = 16220 } - { $_ -lt "15.1.2242.4" } { + { $_ -lt (GetBuildVersion $ex16 "CU20") } { $cuLevel = "CU19" $cuReleaseDate = "12/15/2020" $mesoValue = 13239 $orgValue = 16219 } - { $_ -lt "15.1.2176.2" } { + { $_ -lt (GetBuildVersion $ex16 "CU19") } { $cuLevel = "CU18" $cuReleaseDate = "09/15/2020" $schemaValue = 15332 $mesoValue = 13238 $orgValue = 16218 } - { $_ -lt "15.1.2106.2" } { + { $_ -lt (GetBuildVersion $ex16 "CU18") } { $cuLevel = "CU17" $cuReleaseDate = "06/16/2020" $mesoValue = 13237 $orgValue = 16217 } - { $_ -lt "15.1.2044.4" } { + { $_ -lt (GetBuildVersion $ex16 "CU17") } { $cuLevel = "CU16" $cuReleaseDate = "03/17/2020" } - { $_ -lt "15.1.1979.3" } { + { $_ -lt (GetBuildVersion $ex16 "CU16") } { $cuLevel = "CU15" $cuReleaseDate = "12/17/2019" } - { $_ -lt "15.1.1913.5" } { + { $_ -lt (GetBuildVersion $ex16 "CU15") } { $cuLevel = "CU14" $cuReleaseDate = "09/17/2019" } - { $_ -lt "15.1.1847.3" } { + { $_ -lt (GetBuildVersion $ex16 "CU14") } { $cuLevel = "CU13" $cuReleaseDate = "06/18/2019" } - { $_ -lt "15.1.1779.2" } { + { $_ -lt (GetBuildVersion $ex16 "CU13") } { $cuLevel = "CU12" $cuReleaseDate = "02/12/2019" $mesoValue = 13236 $orgValue = 16215 } - { $_ -lt "15.1.1713.5" } { + { $_ -lt (GetBuildVersion $ex16 "CU12") } { $cuLevel = "CU11" $cuReleaseDate = "10/16/2018" $orgValue = 16214 } - { $_ -lt "15.1.1591.10" } { + { $_ -lt (GetBuildVersion $ex16 "CU11") } { $cuLevel = "CU10" $cuReleaseDate = "06/19/2018" $orgValue = 16213 } - { $_ -lt "15.1.1531.3" } { + { $_ -lt (GetBuildVersion $ex16 "CU10") } { $cuLevel = "CU9" $cuReleaseDate = "03/20/2018" } - { $_ -lt "15.1.1466.3" } { + { $_ -lt (GetBuildVersion $ex16 "CU9") } { $cuLevel = "CU8" $cuReleaseDate = "12/19/2017" } - { $_ -lt "15.1.1415.2" } { + { $_ -lt (GetBuildVersion $ex16 "CU8") } { $cuLevel = "CU7" $cuReleaseDate = "09/16/2017" } - { $_ -lt "15.1.1261.35" } { + { $_ -lt (GetBuildVersion $ex16 "CU7") } { $cuLevel = "CU6" $cuReleaseDate = "06/24/2017" $schemaValue = 15330 } - { $_ -lt "15.1.1034.26" } { + { $_ -lt (GetBuildVersion $ex16 "CU6") } { $cuLevel = "CU5" $cuReleaseDate = "03/21/2017" $schemaValue = 15326 } - { $_ -lt "15.1.845.34" } { + { $_ -lt (GetBuildVersion $ex16 "CU5") } { $cuLevel = "CU4" $cuReleaseDate = "12/13/2016" } - { $_ -lt "15.1.669.32" } { + { $_ -lt (GetBuildVersion $ex16 "CU4") } { $cuLevel = "CU3" $cuReleaseDate = "09/20/2016" $orgValue = 16212 } - { $_ -lt "15.1.544.27" } { + { $_ -lt (GetBuildVersion $ex16 "CU3") } { $cuLevel = "CU2" $cuReleaseDate = "06/21/2016" $schemaValue = 15325 } - { $_ -lt "15.1.466.34" } { + { $_ -lt (GetBuildVersion $ex16 "CU2") } { $cuLevel = "CU1" $cuReleaseDate = "03/15/2016" $schemaValue = 15323 @@ -309,123 +477,123 @@ function Get-ExchangeBuildVersionInformation { $orgValue = 16133 switch ($exchangeVersion) { - { $_ -ge "15.0.1497.2" } { + { $_ -ge (GetBuildVersion $ex13 "CU23") } { $cuLevel = "CU23" $cuReleaseDate = "06/18/2019" $supportedBuildNumber = $true } - "15.0.1497.45" { $suName = "Jan23SU"; $latestSUBuild = $true } - "15.0.1497.44" { $suName = "Nov22SU" } - "15.0.1497.42" { $suName = "Oct22SU" } - "15.0.1497.40" { $suName = "Aug22SU" } - "15.0.1497.36" { $suName = "May22SU"; $mesoValue = 13238 } - "15.0.1497.33" { $suName = "Mar22SU" } - "15.0.1497.28" { $suName = "Jan22SU" } - "15.0.1497.26" { $suName = "Nov21SU" } - "15.0.1497.24" { $suName = "Oct21SU" } - "15.0.1497.23" { $suName = "Jul21SU" } - "15.0.1497.18" { $suName = "May21SU" } - "15.0.1497.15" { $suName = "Apr21SU" } - "15.0.1497.12" { $suName = "Mar21SU" } - { $_ -lt "15.0.1497.2" } { + (GetBuildVersion $ex13 "CU23" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } + (GetBuildVersion $ex13 "CU23" -SU "Nov22SU") { $suName = "Nov22SU" } + (GetBuildVersion $ex13 "CU23" -SU "Oct22SU") { $suName = "Oct22SU" } + (GetBuildVersion $ex13 "CU23" -SU "Aug22SU") { $suName = "Aug22SU" } + (GetBuildVersion $ex13 "CU23" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13238 } + (GetBuildVersion $ex13 "CU23" -SU "Mar22SU") { $suName = "Mar22SU" } + (GetBuildVersion $ex13 "CU23" -SU "Jan22SU") { $suName = "Jan22SU" } + (GetBuildVersion $ex13 "CU23" -SU "Nov21SU") { $suName = "Nov21SU" } + (GetBuildVersion $ex13 "CU23" -SU "Oct21SU") { $suName = "Oct21SU" } + (GetBuildVersion $ex13 "CU23" -SU "Jul21SU") { $suName = "Jul21SU" } + (GetBuildVersion $ex13 "CU23" -SU "May21SU") { $suName = "May21SU" } + (GetBuildVersion $ex13 "CU23" -SU "Apr21SU") { $suName = "Apr21SU" } + (GetBuildVersion $ex13 "CU23" -SU "Mar21SU") { $suName = "Mar21SU" } + { $_ -lt (GetBuildVersion $ex13 "CU23") } { $cuLevel = "CU22" $cuReleaseDate = "02/12/2019" $mesoValue = 13236 $orgValue = 16131 $supportedBuildNumber = $false } - { $_ -lt "15.0.1473.3" } { + { $_ -lt (GetBuildVersion $ex13 "CU22") } { $cuLevel = "CU21" $cuReleaseDate = "06/19/2018" $orgValue = 16130 } - { $_ -lt "15.0.1395.4" } { + { $_ -lt (GetBuildVersion $ex13 "CU21") } { $cuLevel = "CU20" $cuReleaseDate = "03/20/2018" } - { $_ -lt "15.0.1367.3" } { + { $_ -lt (GetBuildVersion $ex13 "CU20") } { $cuLevel = "CU19" $cuReleaseDate = "12/19/2017" } - { $_ -lt "15.0.1365.1" } { + { $_ -lt (GetBuildVersion $ex13 "CU19") } { $cuLevel = "CU18" $cuReleaseDate = "09/16/2017" } - { $_ -lt "15.0.1347.2" } { + { $_ -lt (GetBuildVersion $ex13 "CU18") } { $cuLevel = "CU17" $cuReleaseDate = "06/24/2017" } - { $_ -lt "15.0.1320.4" } { + { $_ -lt (GetBuildVersion $ex13 "CU17") } { $cuLevel = "CU16" $cuReleaseDate = "03/21/2017" } - { $_ -lt "15.0.1293.2" } { + { $_ -lt (GetBuildVersion $ex13 "CU16") } { $cuLevel = "CU15" $cuReleaseDate = "12/13/2016" } - { $_ -lt "15.0.1263.5" } { + { $_ -lt (GetBuildVersion $ex13 "CU15") } { $cuLevel = "CU14" $cuReleaseDate = "09/20/2016" } - { $_ -lt "15.0.1236.3" } { + { $_ -lt (GetBuildVersion $ex13 "CU14") } { $cuLevel = "CU13" $cuReleaseDate = "06/21/2016" } - { $_ -lt "15.0.1210.3" } { + { $_ -lt (GetBuildVersion $ex13 "CU13") } { $cuLevel = "CU12" $cuReleaseDate = "03/15/2016" } - { $_ -lt "15.0.1178.4" } { + { $_ -lt (GetBuildVersion $ex13 "CU12") } { $cuLevel = "CU11" $cuReleaseDate = "12/15/2015" } - { $_ -lt "15.0.1156.6" } { + { $_ -lt (GetBuildVersion $ex13 "CU11") } { $cuLevel = "CU10" $cuReleaseDate = "09/15/2015" } - { $_ -lt "15.0.1130.7" } { + { $_ -lt (GetBuildVersion $ex13 "CU10") } { $cuLevel = "CU9" $cuReleaseDate = "06/17/2015" $orgValue = 15965 } - { $_ -lt "15.0.1104.5" } { + { $_ -lt (GetBuildVersion $ex13 "CU9") } { $cuLevel = "CU8" $cuReleaseDate = "03/17/2015" } - { $_ -lt "15.0.1076.9" } { + { $_ -lt (GetBuildVersion $ex13 "CU8") } { $cuLevel = "CU7" $cuReleaseDate = "12/09/2014" } - { $_ -lt "15.0.1044.25" } { + { $_ -lt (GetBuildVersion $ex13 "CU7") } { $cuLevel = "CU6" $cuReleaseDate = "08/26/2014" $schemaValue = 15303 } - { $_ -lt "15.0.995.29" } { + { $_ -lt (GetBuildVersion $ex13 "CU6") } { $cuLevel = "CU5" $cuReleaseDate = "05/27/2014" $schemaValue = 15300 $orgValue = 15870 } - { $_ -lt "15.0.913.22" } { + { $_ -lt (GetBuildVersion $ex13 "CU5") } { $cuLevel = "CU4" $cuReleaseDate = "02/25/2014" $schemaValue = 15292 $orgValue = 15844 } - { $_ -lt "15.0.847.32" } { + { $_ -lt (GetBuildVersion $ex13 "CU4") } { $cuLevel = "CU3" $cuReleaseDate = "11/25/2013" $schemaValue = 15283 $orgValue = 15763 } - { $_ -lt "15.0.775.38" } { + { $_ -lt (GetBuildVersion $ex13 "CU3") } { $cuLevel = "CU2" $cuReleaseDate = "07/09/2013" $schemaValue = 15281 $orgValue = 15688 } - { $_ -lt "15.0.712.24" } { + { $_ -lt (GetBuildVersion $ex13 "CU2") } { $cuLevel = "CU1" $cuReleaseDate = "04/02/2013" $schemaValue = 15254 diff --git a/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 b/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 index 9eb1c6365e..1edd638faa 100644 --- a/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 +++ b/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 @@ -20,7 +20,7 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { It "Return the final E19CU11 version object" { $results.MajorVersion | Should -Be "Exchange2019" - $results.FriendlyName = "Exchange 2019 CU11" + $results.FriendlyName | Should -Be "Exchange 2019 CU11" $results.BuildVersion.ToString() | Should -Be "15.2.986.5" $results.CU | Should -Be "CU11" $results.ReleaseDate | Should -Be ([System.Convert]::ToDateTime([DateTime]"9/28/2021", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)) @@ -41,7 +41,7 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { It "Return the final E19CU11 version object" { $results.MajorVersion | Should -Be "Exchange2019" - $results.FriendlyName = "Exchange 2019 CU11" + $results.FriendlyName | Should -Be "Exchange 2019 CU11" $results.BuildVersion.ToString() | Should -Be "15.2.986.5" $results.CU | Should -Be "CU11" $results.ReleaseDate | Should -Be ([System.Convert]::ToDateTime([DateTime]"9/28/2021", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)) @@ -62,7 +62,7 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { It "Return the final E19CU12 Oct22SU version object" { $results.MajorVersion | Should -Be "Exchange2019" - $results.FriendlyName = "Exchange 2019 CU12 Oct22SU" + $results.FriendlyName | Should -Be "Exchange 2019 CU12 Oct22SU" $results.BuildVersion.ToString() | Should -Be "15.2.1118.15" $results.CU | Should -Be "CU12" $results.ReleaseDate | Should -Be ([System.Convert]::ToDateTime([DateTime]"04/20/2022", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)) @@ -83,7 +83,7 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { It "Return the final E19CU12 Oct22SU version object" { $results.MajorVersion | Should -Be "Exchange2019" - $results.FriendlyName = "Exchange 2019 CU10 Jul21SU" + $results.FriendlyName | Should -Be "Exchange 2019 CU10" $results.BuildVersion.ToString() | Should -Be "15.2.922.13" $results.CU | Should -Be "CU10" $results.ReleaseDate | Should -Be ([System.Convert]::ToDateTime([DateTime]"06/29/2021", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)) @@ -95,4 +95,41 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { $results.ADLevel.OrgValue | Should -Be 16758 } } + + Context "Testing Exchange CU Build Lookups" { + It "Exchange 2013 CU23" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2013" -CU "CU23" + $results.BuildVersion.ToString() | Should -Be "15.0.1497.2" + $results.FriendlyName | Should -Be "Exchange 2013 CU23" + } + + It "Exchange 2013 CU23 Jan23SU" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2013" -CU "CU23" -SU "Jan23SU" + $results.BuildVersion.ToString() | Should -Be "15.0.1497.45" + $results.FriendlyName | Should -Be "Exchange 2013 CU23 Jan23SU" + } + + It "Exchange 2016 CU22" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2016" -CU "CU22" + $results.BuildVersion.ToString() | Should -Be "15.1.2375.7" + $results.FriendlyName | Should -Be "Exchange 2016 CU22" + } + + It "Exchange 2016 CU22 Jan23SU - Should Be CU22 Base" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2016" -CU "CU22" -SU "Jan23SU" + $results.BuildVersion.ToString() | Should -Be "15.1.2375.7" + $results.FriendlyName | Should -Be "Exchange 2016 CU22" + } + + It "Exchange 2019 CU12" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2019" -CU "CU12" + $results.BuildVersion.ToString() | Should -Be "15.2.1118.7" + $results.FriendlyName | Should -Be "Exchange 2019 CU12" + } + + It "Exchange 2019 CU23 - Should be NULL" { + $results = Get-ExchangeBuildVersionInformation -Version "Exchange2019" -CU "CU23" + $results.BuildVersion | Should -Be $null + } + } } From 3dd6249223fb92ba6d928229da4195afbaf0b633 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Mon, 23 Jan 2023 11:57:50 -0600 Subject: [PATCH 12/33] Be able to do -Verbose against Invoke-AnalyzerEngine --- Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 index a1370d4e16..c8d0c56e83 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 @@ -15,6 +15,7 @@ . $PSScriptRoot\Security\Invoke-AnalyzerSecuritySettings.ps1 . $PSScriptRoot\Security\Invoke-AnalyzerSecurityVulnerability.ps1 function Invoke-AnalyzerEngine { + [CmdletBinding()] param( [object]$HealthServerObject ) From 2fa8af857db6ab18910b57d4c7dc9339aa5cfc8f Mon Sep 17 00:00:00 2001 From: David Paulson Date: Mon, 23 Jan 2023 12:21:22 -0600 Subject: [PATCH 13/33] New comparison file --- .../Helpers/CompareExchangeBuildLevel.ps1 | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 Diagnostics/HealthChecker/Helpers/CompareExchangeBuildLevel.ps1 diff --git a/Diagnostics/HealthChecker/Helpers/CompareExchangeBuildLevel.ps1 b/Diagnostics/HealthChecker/Helpers/CompareExchangeBuildLevel.ps1 new file mode 100644 index 0000000000..9fa467159f --- /dev/null +++ b/Diagnostics/HealthChecker/Helpers/CompareExchangeBuildLevel.ps1 @@ -0,0 +1,149 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +. $PSScriptRoot\..\..\..\Shared\Get-ExchangeBuildVersionInformation.ps1 +function Test-ExchangeBuildGreaterOrEqualThanBuild { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory = $true)] + [object]$CurrentExchangeBuild, + [Parameter(Mandatory = $true)] + [string]$Version, + [Parameter(Mandatory = $true)] + [string]$CU, + [Parameter(Mandatory = $false)] + [string]$SU + ) + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $testResult = $false + } process { + if ($CurrentExchangeBuild.MajorVersion -eq $Version) { + $params = @{ + Version = $Version + CU = $CU + } + + if (-not([string]::IsNullOrEmpty($SU))) { + $params.SU = $SU + } + $testBuild = Get-ExchangeBuildVersionInformation @params + $testResult = $CurrentExchangeBuild.BuildVersion -ge $testBuild.BuildVersion + } + } end { + Write-Verbose "Result $testResult" + return $testResult + } +} + +function Test-ExchangeBuildLessThanBuild { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory = $true)] + [object]$CurrentExchangeBuild, + [Parameter(Mandatory = $true)] + [string]$Version, + [Parameter(Mandatory = $true)] + [string]$CU, + [Parameter(Mandatory = $false)] + [string]$SU + ) + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $testResult = $false + } process { + if ($CurrentExchangeBuild.MajorVersion -eq $Version) { + $params = @{ + Version = $Version + CU = $CU + } + + if (-not([string]::IsNullOrEmpty($SU))) { + $params.SU = $SU + } + + $testBuild = Get-ExchangeBuildVersionInformation @params + $testResult = $CurrentExchangeBuild.BuildVersion -lt $testBuild.BuildVersion + } + } end { + Write-Verbose "Result $testResult" + return $testResult + } +} + +function Test-ExchangeBuildEqualBuild { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory = $true)] + [object]$CurrentExchangeBuild, + [Parameter(Mandatory = $true)] + [string]$Version, + [Parameter(Mandatory = $true)] + [string]$CU, + [Parameter(Mandatory = $false)] + [string]$SU + ) + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $testResult = $false + } process { + if ($CurrentExchangeBuild.MajorVersion -eq $Version) { + $params = @{ + Version = $Version + CU = $CU + } + + if (-not([string]::IsNullOrEmpty($SU))) { + $params.SU = $SU + } + $testBuild = Get-ExchangeBuildVersionInformation @params + $testResult = $CurrentExchangeBuild.BuildVersion -eq $testBuild.BuildVersion + } + } end { + Write-Verbose "Result $testResult" + return $testResult + } +} + +function Test-ExchangeBuildGreaterOrEqualThanSecurityPatch { + [CmdletBinding()] + [OutputType([bool])] + param( + [object]$CurrentExchangeBuild, + [string]$SUName + ) + begin { + Write-Verbose "Calling: $($MyInvocation.MyCommand)" + $testResult = $false + } process { + $allSecurityPatches = Get-ExchangeBuildVersionInformation -FindBySUName $SUName | + Where-Object { $_.MajorVersion -eq $CurrentExchangeBuild.MajorVersion } | + Sort-Object ReleaseDate -Descending + + if ($null -eq $allSecurityPatches -or + $allSecurityPatches.Count -eq 0) { + Write-Verbose "We didn't find a security path for this version of Exchange." + Write-Verbose "We assume this means that this version of Exchange $($CurrentExchangeBuild.MajorVersion) isn't vulnerable for this SU $SUName" + $testResult = $true + return + } + + # The first item in the list should be the latest CU for this security patch. + # If the current exchange build is greater than the latest CU + security patch, then we are good. + # Otherwise, we need to look at the CU that we are on to make sure we are patched. + if ($CurrentExchangeBuild.BuildVersion -ge $allSecurityPatches[0].BuildVersion) { + $testResult = $true + return + } + Write-Verbose "Need to look at particular CU match" + $matchCU = $allSecurityPatches | Where-Object { $_.CU -eq $CurrentExchangeBuild.CU } + Write-Verbose "Found match CU $($null -ne $matchCU)" + $testResult = $null -ne $matchCU -and $CurrentExchangeBuild.BuildVersion -ge $matchCU.BuildVersion + } end { + Write-Verbose "Result $testResult" + return $testResult + } +} From 7d85943ddf1a1964b03901469f2da98a2d64f7a7 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 24 Jan 2023 12:28:08 -0600 Subject: [PATCH 14/33] Add Find by SU Name option --- .../Get-ExchangeBuildVersionInformation.ps1 | 538 ++++++++++++------ ...-ExchangeBuildVersionInformation.Tests.ps1 | 11 +- 2 files changed, 376 insertions(+), 173 deletions(-) diff --git a/Shared/Get-ExchangeBuildVersionInformation.ps1 b/Shared/Get-ExchangeBuildVersionInformation.ps1 index aa63639e3c..ece1e6e1ce 100644 --- a/Shared/Get-ExchangeBuildVersionInformation.ps1 +++ b/Shared/Get-ExchangeBuildVersionInformation.ps1 @@ -16,37 +16,26 @@ function Get-ExchangeBuildVersionInformation { [System.Version]$FileVersion, [Parameter(ParameterSetName = "VersionCU", Mandatory = $true)] - [ValidateSet("Exchange2013", "Exchange2016", "Exchange2019")] + [ValidateScript( { ValidateVersionParameter $_ } )] [string]$Version, [Parameter(ParameterSetName = "VersionCU", Mandatory = $true)] - [ValidateSet("CU1", "CU2", "CU3", "CU4", "CU5", "CU6", "CU7", "CU8", - "CU9", "CU10", "CU11", "CU12", "CU13", "CU14", "CU15", "CU16", "CU17", - "CU18", "CU19", "CU20", "CU21", "CU22", "CU23")] + [ValidateScript( { ValidateCUParameter $_ } )] [string]$CU, [Parameter(ParameterSetName = "VersionCU", Mandatory = $false)] - [ValidateSet("Mar21SU", "Apr21SU", "May21SU", "Jul21SU", "Oct21SU", - "Nov21SU", "Jan22SU", "Mar22SU", "May22SU", "Aug22SU", "Oct22SU", - "Nov22SU", "Jan23SU")] + [ValidateScript( { ValidateSUParameter $_ } )] [string]$SU, + [Parameter(ParameterSetName = "FindSUBuilds", Mandatory = $true)] + [ValidateScript( { ValidateSUParameter $_ } )] + [string]$FindBySUName, + [Parameter(Mandatory = $false)] [ScriptBlock]$CatchActionFunction ) begin { - function NewCUAndSUObject { - param( - [string]$CUBuildNumber, - [Hashtable]$SUBuildNumber - ) - return @{ - "CU" = $CUBuildNumber - "SU" = $SUBuildNumber - } - } - function GetBuildVersion { param( [Parameter(Position = 1)] @@ -58,7 +47,7 @@ function Get-ExchangeBuildVersionInformation { ) $cuResult = $exchangeBuildDictionary[$ExchangeVersion][$CU] - if ((-not [string]::IsNullOrEmpty($SU)) -and + if ((-not [string]::IsNullOrEmpty($SU)) -and $cuResult.SU.ContainsKey($SU)) { return $cuResult.SU[$SU] } else { @@ -67,117 +56,7 @@ function Get-ExchangeBuildVersionInformation { } # Dictionary of Exchange Version/CU/SU to build number - $exchangeBuildDictionary = @{ - "Exchange2013" = @{ - "CU1" = (NewCUAndSUObject "15.0.620.29") - "CU2" = (NewCUAndSUObject "15.0.712.24") - "CU3" = (NewCUAndSUObject "15.0.775.38") - "CU4" = (NewCUAndSUObject "15.0.847.32") - "CU5" = (NewCUAndSUObject "15.0.913.22") - "CU6" = (NewCUAndSUObject "15.0.995.29") - "CU7" = (NewCUAndSUObject "15.0.1044.25") - "CU8" = (NewCUAndSUObject "15.0.1076.9") - "CU9" = (NewCUAndSUObject "15.0.1104.5") - "CU10" = (NewCUAndSUObject "15.0.1130.7") - "CU11" = (NewCUAndSUObject "15.0.1156.6") - "CU12" = (NewCUAndSUObject "15.0.1178.4") - "CU13" = (NewCUAndSUObject "15.0.1210.3") - "CU14" = (NewCUAndSUObject "15.0.1236.3") - "CU15" = (NewCUAndSUObject "15.0.1263.5") - "CU16" = (NewCUAndSUObject "15.0.1293.2") - "CU17" = (NewCUAndSUObject "15.0.1320.4") - "CU18" = (NewCUAndSUObject "15.0.1347.2") - "CU19" = (NewCUAndSUObject "15.0.1365.1") - "CU20" = (NewCUAndSUObject "15.0.1367.3") - "CU21" = (NewCUAndSUObject "15.0.1395.4") - "CU22" = (NewCUAndSUObject "15.0.1473.3") - "CU23" = (NewCUAndSUObject "15.0.1497.2" @{ - "Mar21SU" = "15.0.1497.12" - "Apr21SU" = "15.0.1497.15" - "May21SU" = "15.0.1497.18" - "Jul21SU" = "15.0.1497.23" - "Oct21SU" = "15.0.1497.24" - "Nov21SU" = "15.0.1497.26" - "Jan22SU" = "15.0.1497.28" - "Mar22SU" = "15.0.1497.33" - "May22SU" = "15.0.1497.36" - "Aug22SU" = "15.0.1497.40" - "Oct22SU" = "15.0.1497.42" - "Nov22SU" = "15.0.1497.44" - "Jan23SU" = "15.0.1497.45" - }) - } - "Exchange2016" = @{ - "CU1" = (NewCUAndSUObject "15.1.396.30") - "CU2" = (NewCUAndSUObject "15.1.466.34") - "CU3" = (NewCUAndSUObject "15.1.544.27") - "CU4" = (NewCUAndSUObject "15.1.669.32") - "CU5" = (NewCUAndSUObject "15.1.845.34") - "CU6" = (NewCUAndSUObject "15.1.1034.26") - "CU7" = (NewCUAndSUObject "15.1.1261.35") - "CU8" = (NewCUAndSUObject "15.1.1415.2") - "CU9" = (NewCUAndSUObject "15.1.1466.3") - "CU10" = (NewCUAndSUObject "15.1.1531.3") - "CU11" = (NewCUAndSUObject "15.1.1591.10") - "CU12" = (NewCUAndSUObject "15.1.1713.5") - "CU13" = (NewCUAndSUObject "15.1.1779.2") - "CU14" = (NewCUAndSUObject "15.1.1847.3") - "CU15" = (NewCUAndSUObject "15.1.1913.5") - "CU16" = (NewCUAndSUObject "15.1.1979.3") - "CU17" = (NewCUAndSUObject "15.1.2044.4") - "CU18" = (NewCUAndSUObject "15.1.2106.2") - "CU19" = (NewCUAndSUObject "15.1.2176.2") - "CU20" = (NewCUAndSUObject "15.1.2242.4") - "CU21" = (NewCUAndSUObject "15.1.2308.8") - "CU22" = (NewCUAndSUObject "15.1.2375.7" @{ - "Oct21SU" = "15.1.2375.12" - "Nov21SU" = "15.1.2375.17" - "Jan22SU" = "15.1.2375.18" - "Mar22SU" = "15.1.2375.24" - "May22SU" = "15.1.2375.28" - "Aug22SU" = "15.1.2375.31" - "Oct22SU" = "15.1.2375.32" - "Nov22SU" = "15.1.2375.37" - }) - "CU23" = (NewCUAndSUObject "15.1.2507.6" @{ - "May22SU" = "15.1.2507.9" - "Aug22SU" = "15.1.2507.12" - "Oct22SU" = "15.1.2507.13" - "Nov22SU" = "15.1.2507.16" - "Jan23SU" = "15.1.2507.17" - }) - } - "Exchange2019" = @{ - "CU1" = (NewCUAndSUObject "15.2.330.5") - "CU2" = (NewCUAndSUObject "15.2.397.3") - "CU3" = (NewCUAndSUObject "15.2.464.5") - "CU4" = (NewCUAndSUObject "15.2.529.5") - "CU5" = (NewCUAndSUObject "15.2.595.3") - "CU6" = (NewCUAndSUObject "15.2.659.4") - "CU7" = (NewCUAndSUObject "15.2.721.2") - "CU8" = (NewCUAndSUObject "15.2.792.3") - "CU9" = (NewCUAndSUObject "15.2.858.5") - "CU10" = (NewCUAndSUObject "15.2.922.7") - "CU11" = (NewCUAndSUObject "15.2.986.5" @{ - "Oct21SU" = "15.2.986.9" - "Nov21SU" = "15.2.986.14" - "Jan22SU" = "15.2.986.15" - "Mar22SU" = "15.2.986.22" - "May22SU" = "15.2.986.26" - "Aug22SU" = "15.2.986.29" - "Oct22SU" = "15.2.986.30" - "Nov22SU" = "15.2.986.36" - "Jan23SU" = "15.2.986.37" - }) - "CU12" = (NewCUAndSUObject "15.2.1118.7" @{ - "May22SU" = "15.2.1118.9" - "Aug22SU" = "15.2.1118.12" - "Oct22SU" = "15.2.1118.15" - "Nov22SU" = "15.2.1118.20" - "Jan23SU" = "15.2.1118.21" - }) - } - } + $exchangeBuildDictionary = GetExchangeBuildDictionary Write-Verbose "Calling: $($MyInvocation.MyCommand)" $exchangeMajorVersion = [string]::Empty @@ -199,7 +78,17 @@ function Get-ExchangeBuildVersionInformation { process { # Convert both input types to a [System.Version] try { - if ($PSCmdlet.ParameterSetName -eq "VersionCU") { + if ($PSCmdlet.ParameterSetName -eq "FindSUBuilds") { + foreach ($exchangeKey in $exchangeBuildDictionary.Keys) { + foreach ($cuKey in $exchangeBuildDictionary[$exchangeKey].Keys) { + if ($null -ne $exchangeBuildDictionary[$exchangeKey][$cuKey].SU -and + $exchangeBuildDictionary[$exchangeKey][$cuKey].SU.ContainsKey($FindBySUName)) { + Get-ExchangeBuildVersionInformation -FileVersion $exchangeBuildDictionary[$exchangeKey][$cuKey].SU[$FindBySUName] + } + } + } + return + } elseif ($PSCmdlet.ParameterSetName -eq "VersionCU") { [System.Version]$exchangeVersion = GetBuildVersion -ExchangeVersion $Version -CU $CU -SU $SU } elseif ($PSCmdlet.ParameterSetName -eq "AdminDisplayVersion") { $AdminDisplayVersion = $AdminDisplayVersion.ToString() @@ -238,11 +127,7 @@ function Get-ExchangeBuildVersionInformation { $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true } - (GetBuildVersion $ex19 "CU12" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } - (GetBuildVersion $ex19 "CU12" -SU "Nov22SU") { $suName = "Nov22SU" } - (GetBuildVersion $ex19 "CU12" -SU "Oct22SU") { $suName = "Oct22SU" } - (GetBuildVersion $ex19 "CU12" -SU "Aug22SU") { $suName = "Aug22SU" } - (GetBuildVersion $ex19 "CU12" -SU "May22SU") { $suName = "May22SU" } + (GetBuildVersion $ex19 "CU12" -SU "Jan23SU") { $latestSUBuild = $true } { $_ -lt (GetBuildVersion $ex19 "CU12") } { $cuLevel = "CU11" $cuReleaseDate = "09/28/2021" @@ -250,15 +135,8 @@ function Get-ExchangeBuildVersionInformation { $mesoValue = 13242 $orgValue = 16759 } - (GetBuildVersion $ex19 "CU11" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } - (GetBuildVersion $ex19 "CU11" -SU "Nov22SU") { $suName = "Nov22SU" } - (GetBuildVersion $ex19 "CU11" -SU "Oct22SU") { $suName = "Oct22SU" } - (GetBuildVersion $ex19 "CU11" -SU "Aug22SU") { $suName = "Aug22SU" } - (GetBuildVersion $ex19 "CU11" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13243 } - (GetBuildVersion $ex19 "CU11" -SU "Mar22SU") { $suName = "Mar22SU" } - (GetBuildVersion $ex19 "CU11" -SU "Jan22SU") { $suName = "Jan22SU" } - (GetBuildVersion $ex19 "CU11" -SU "Nov21SU") { $suName = "Nov21SU" } - (GetBuildVersion $ex19 "CU11" -SU "Oct21SU") { $suName = "Oct21SU" } + (GetBuildVersion $ex19 "CU11" -SU "Jan23SU") { $latestSUBuild = $true } + (GetBuildVersion $ex19 "CU11" -SU "May22SU") { $mesoValue = 13243 } { $_ -lt (GetBuildVersion $ex19 "CU11") } { $cuLevel = "CU10" $cuReleaseDate = "06/29/2021" @@ -338,11 +216,7 @@ function Get-ExchangeBuildVersionInformation { $cuReleaseDate = "04/20/2022" $supportedBuildNumber = $true } - (GetBuildVersion $ex16 "CU23" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } - (GetBuildVersion $ex16 "CU23" -SU "Nov22SU") { $suName = "Nov22SU" } - (GetBuildVersion $ex16 "CU23" -SU "Oct22SU") { $suName = "Oct22SU" } - (GetBuildVersion $ex16 "CU23" -SU "Aug22SU") { $suName = "Aug22SU" } - (GetBuildVersion $ex16 "CU23" -SU "May22SU") { $suName = "May22SU" } + (GetBuildVersion $ex16 "CU23" -SU "Jan23SU") { $latestSUBuild = $true } { $_ -lt (GetBuildVersion $ex16 "CU23") } { $cuLevel = "CU22" $cuReleaseDate = "09/28/2021" @@ -350,14 +224,7 @@ function Get-ExchangeBuildVersionInformation { $mesoValue = 13242 $orgValue = 16222 } - (GetBuildVersion $ex16 "CU22" -SU "Nov22SU") { $suName = "Nov22SU" } - (GetBuildVersion $ex16 "CU22" -SU "Oct22SU") { $suName = "Oct22SU" } - (GetBuildVersion $ex16 "CU22" -SU "Aug22SU") { $suName = "Aug22SU" } - (GetBuildVersion $ex16 "CU22" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13243 } - (GetBuildVersion $ex16 "CU22" -SU "Mar22SU") { $suName = "Mar22SU" } - (GetBuildVersion $ex16 "CU22" -SU "Jan22SU") { $suName = "Jan22SU" } - (GetBuildVersion $ex16 "CU22" -SU "Nov21SU") { $suName = "Nov21SU" } - (GetBuildVersion $ex16 "CU22" -SU "Oct21SU") { $suName = "Oct21SU" } + (GetBuildVersion $ex16 "CU22" -SU "May22SU") { $mesoValue = 13243 } { $_ -lt (GetBuildVersion $ex16 "CU22") } { $cuLevel = "CU21" $cuReleaseDate = "06/29/2021" @@ -482,19 +349,8 @@ function Get-ExchangeBuildVersionInformation { $cuReleaseDate = "06/18/2019" $supportedBuildNumber = $true } - (GetBuildVersion $ex13 "CU23" -SU "Jan23SU") { $suName = "Jan23SU"; $latestSUBuild = $true } - (GetBuildVersion $ex13 "CU23" -SU "Nov22SU") { $suName = "Nov22SU" } - (GetBuildVersion $ex13 "CU23" -SU "Oct22SU") { $suName = "Oct22SU" } - (GetBuildVersion $ex13 "CU23" -SU "Aug22SU") { $suName = "Aug22SU" } - (GetBuildVersion $ex13 "CU23" -SU "May22SU") { $suName = "May22SU"; $mesoValue = 13238 } - (GetBuildVersion $ex13 "CU23" -SU "Mar22SU") { $suName = "Mar22SU" } - (GetBuildVersion $ex13 "CU23" -SU "Jan22SU") { $suName = "Jan22SU" } - (GetBuildVersion $ex13 "CU23" -SU "Nov21SU") { $suName = "Nov21SU" } - (GetBuildVersion $ex13 "CU23" -SU "Oct21SU") { $suName = "Oct21SU" } - (GetBuildVersion $ex13 "CU23" -SU "Jul21SU") { $suName = "Jul21SU" } - (GetBuildVersion $ex13 "CU23" -SU "May21SU") { $suName = "May21SU" } - (GetBuildVersion $ex13 "CU23" -SU "Apr21SU") { $suName = "Apr21SU" } - (GetBuildVersion $ex13 "CU23" -SU "Mar21SU") { $suName = "Mar21SU" } + (GetBuildVersion $ex13 "CU23" -SU "Jan23SU") { $latestSUBuild = $true } + (GetBuildVersion $ex13 "CU23" -SU "May22SU") { $mesoValue = 13238 } { $_ -lt (GetBuildVersion $ex13 "CU23") } { $cuLevel = "CU22" $cuReleaseDate = "02/12/2019" @@ -603,8 +459,32 @@ function Get-ExchangeBuildVersionInformation { } else { Write-Verbose "Unknown version of Exchange is detected." } + + # Now get the SU Name + if ([string]::IsNullOrEmpty($exchangeMajorVersion) -or + [string]::IsNullOrEmpty($cuLevel)) { + Write-Verbose "Can't lookup when keys aren't set" + return + } + + $currentSUInfo = $exchangeBuildDictionary[$exchangeMajorVersion][$cuLevel].SU + $compareValue = $exchangeVersion.ToString() + if ($null -ne $currentSUInfo -and + $currentSUInfo.ContainsValue($compareValue)) { + foreach ($key in $currentSUInfo.Keys) { + if ($compareValue -eq $currentSUInfo[$key]) { + $suName = $key + } + } + } } end { + + if ($PSCmdlet.ParameterSetName -eq "FindSUBuilds") { + Write-Verbose "Return nothing here, results were already returned on the pipeline" + return + } + $friendlyName = "$friendlyName $cuLevel $suName".Trim() Write-Verbose "Determined Build Version $friendlyName" return [PSCustomObject]@{ @@ -624,3 +504,319 @@ function Get-ExchangeBuildVersionInformation { } } } + +function GetExchangeBuildDictionary { + + function NewCUAndSUObject { + param( + [string]$CUBuildNumber, + [Hashtable]$SUBuildNumber + ) + return @{ + "CU" = $CUBuildNumber + "SU" = $SUBuildNumber + } + } + + @{ + "Exchange2013" = @{ + "CU1" = (NewCUAndSUObject "15.0.620.29") + "CU2" = (NewCUAndSUObject "15.0.712.24") + "CU3" = (NewCUAndSUObject "15.0.775.38") + "CU4" = (NewCUAndSUObject "15.0.847.32") + "CU5" = (NewCUAndSUObject "15.0.913.22") + "CU6" = (NewCUAndSUObject "15.0.995.29") + "CU7" = (NewCUAndSUObject "15.0.1044.25") + "CU8" = (NewCUAndSUObject "15.0.1076.9") + "CU9" = (NewCUAndSUObject "15.0.1104.5") + "CU10" = (NewCUAndSUObject "15.0.1130.7") + "CU11" = (NewCUAndSUObject "15.0.1156.6") + "CU12" = (NewCUAndSUObject "15.0.1178.4") + "CU13" = (NewCUAndSUObject "15.0.1210.3") + "CU14" = (NewCUAndSUObject "15.0.1236.3") + "CU15" = (NewCUAndSUObject "15.0.1263.5") + "CU16" = (NewCUAndSUObject "15.0.1293.2") + "CU17" = (NewCUAndSUObject "15.0.1320.4") + "CU18" = (NewCUAndSUObject "15.0.1347.2" @{ + "Mar18SU" = "15.0.1347.5" + }) + "CU19" = (NewCUAndSUObject "15.0.1365.1" @{ + "Mar18SU" = "15.0.1365.3" + "May18SU" = "15.0.1365.7" + }) + "CU20" = (NewCUAndSUObject "15.0.1367.3" @{ + "May18SU" = "15.0.1367.6" + "Aug18SU" = "15.0.1367.9" + }) + "CU21" = (NewCUAndSUObject "15.0.1395.4" @{ + "Aug18SU" = "15.0.1395.7" + "Oct18SU" = "15.0.1395.8" + "Jan19SU" = "15.0.1395.10" + "Mar21SU" = "15.0.1395.12" + }) + "CU22" = (NewCUAndSUObject "15.0.1473.3" @{ + "Feb19SU" = "15.0.1473.3" + "Apr19SU" = "15.0.1473.4" + "Jun19SU" = "15.0.1473.5" + "Mar21SU" = "15.0.1473.6" + }) + "CU23" = (NewCUAndSUObject "15.0.1497.2" @{ + "Jul19SU" = "15.0.1497.3" + "Nov19SU" = "15.0.1497.4" + "Feb20SU" = "15.0.1497.6" + "Oct20SU" = "15.0.1497.7" + "Nov20SU" = "15.0.1497.8" + "Dec20SU" = "15.0.1497.10" + "Mar21SU" = "15.0.1497.12" + "Apr21SU" = "15.0.1497.15" + "May21SU" = "15.0.1497.18" + "Jul21SU" = "15.0.1497.23" + "Oct21SU" = "15.0.1497.24" + "Nov21SU" = "15.0.1497.26" + "Jan22SU" = "15.0.1497.28" + "Mar22SU" = "15.0.1497.33" + "May22SU" = "15.0.1497.36" + "Aug22SU" = "15.0.1497.40" + "Oct22SU" = "15.0.1497.42" + "Nov22SU" = "15.0.1497.44" + "Jan23SU" = "15.0.1497.45" + }) + } + "Exchange2016" = @{ + "CU1" = (NewCUAndSUObject "15.1.396.30") + "CU2" = (NewCUAndSUObject "15.1.466.34") + "CU3" = (NewCUAndSUObject "15.1.544.27") + "CU4" = (NewCUAndSUObject "15.1.669.32") + "CU5" = (NewCUAndSUObject "15.1.845.34") + "CU6" = (NewCUAndSUObject "15.1.1034.26") + "CU7" = (NewCUAndSUObject "15.1.1261.35" @{ + "Mar18SU" = "15.1.1261.39" + }) + "CU8" = (NewCUAndSUObject "15.1.1415.2" @{ + "Mar18SU" = "15.1.1415.4" + "May18SU" = "15.1.1415.7" + "Mar21SU" = "15.1.1415.8" + }) + "CU9" = (NewCUAndSUObject "15.1.1466.3" @{ + "May18SU" = "15.1.1466.8" + "Aug18SU" = "15.1.1466.9" + "Mar21SU" = "15.1.1466.13" + }) + "CU10" = (NewCUAndSUObject "15.1.1531.3" @{ + "Aug18SU" = "15.1.1531.6" + "Oct18SU" = "15.1.1531.8" + "Jan19SU" = "15.1.1531.10" + "Mar21SU" = "15.1.1531.12" + }) + "CU11" = (NewCUAndSUObject "15.1.1591.10" @{ + "Dec18SU" = "15.1.1591.11" + "Jan19SU" = "15.1.1591.13" + "Apr19SU" = "15.1.1591.16" + "Jun19SU" = "15.1.1591.17" + "Mar21SU" = "15.1.1591.18" + }) + "CU12" = (NewCUAndSUObject "15.1.1713.5" @{ + "Apr19SU" = "15.1.1713.6" + "Jun19SU" = "15.1.1713.7" + "Jul19SU" = "15.1.1713.8" + "Sep19SU" = "15.1.1713.9" + "Mar21SU" = "15.1.1713.10" + }) + "CU13" = (NewCUAndSUObject "15.1.1779.2" @{ + "Jul19SU" = "15.1.1779.4" + "Sep19SU" = "15.1.1779.5" + "Nov19SU" = "15.1.1779.7" + "Mar21SU" = "15.1.1779.8" + }) + "CU14" = (NewCUAndSUObject "15.1.1847.3" @{ + "Nov19SU" = "15.1.1847.5" + "Feb20SU" = "15.1.1847.7" + "Mar20SU" = "15.1.1847.10" + "Mar21SU" = "15.1.1847.12" + }) + "CU15" = (NewCUAndSUObject "15.1.1913.5" @{ + "Feb20SU" = "15.1.1913.7" + "Mar20SU" = "15.1.1913.10" + "Mar21SU" = "15.1.1913.12" + }) + "CU16" = (NewCUAndSUObject "15.1.1979.3" @{ + "Sep20SU" = "15.1.1979.6" + "Mar21SU" = "15.1.1979.8" + }) + "CU17" = (NewCUAndSUObject "15.1.2044.4" @{ + "Sep20SU" = "15.1.2044.6" + "Oct20SU" = "15.1.2044.7" + "Nov20SU" = "15.1.2044.8" + "Dec20SU" = "15.1.2044.12" + "Mar21SU" = "15.1.2044.13" + }) + "CU18" = (NewCUAndSUObject "15.1.2106.2" @{ + "Oct20SU" = "15.1.2106.3" + "Nov20SU" = "15.1.2106.4" + "Dec20SU" = "15.1.2106.6" + "Feb21SU" = "15.1.2106.8" + "Mar21SU" = "15.1.2106.13" + }) + "CU19" = (NewCUAndSUObject "15.1.2176.2" @{ + "Feb21SU" = "15.1.2176.4" + "Mar21SU" = "15.1.2176.9" + "Apr21SU" = "15.1.2176.12" + "May21SU" = "15.1.2176.14" + }) + "CU20" = (NewCUAndSUObject "15.1.2242.4" @{ + "Apr21SU" = "15.1.2242.8" + "May21SU" = "15.1.2242.10" + "Jul21SU" = "15.1.2242.12" + }) + "CU21" = (NewCUAndSUObject "15.1.2308.8" @{ + "Jul21SU" = "15.1.2308.14" + "Oct21SU" = "15.1.2308.15" + "Nov21SU" = "15.1.2308.20" + "Jan22SU" = "15.1.2308.21" + "Mar22SU" = "15.1.2308.27" + }) + "CU22" = (NewCUAndSUObject "15.1.2375.7" @{ + "Oct21SU" = "15.1.2375.12" + "Nov21SU" = "15.1.2375.17" + "Jan22SU" = "15.1.2375.18" + "Mar22SU" = "15.1.2375.24" + "May22SU" = "15.1.2375.28" + "Aug22SU" = "15.1.2375.31" + "Oct22SU" = "15.1.2375.32" + "Nov22SU" = "15.1.2375.37" + }) + "CU23" = (NewCUAndSUObject "15.1.2507.6" @{ + "May22SU" = "15.1.2507.9" + "Aug22SU" = "15.1.2507.12" + "Oct22SU" = "15.1.2507.13" + "Nov22SU" = "15.1.2507.16" + "Jan23SU" = "15.1.2507.17" + }) + } + "Exchange2019" = @{ + "CU1" = (NewCUAndSUObject "15.2.330.5" @{ + "Apr19SU" = "15.2.330.7" + "Jun19SU" = "15.2.330.8" + "Jul19SU" = "15.2.330.9" + "Sep19SU" = "15.2.330.10" + "Mar21SU" = "15.2.330.11" + }) + "CU2" = (NewCUAndSUObject "15.2.397.3" @{ + "Jul19SU" = "15.2.397.5" + "Sep19SU" = "15.2.397.6" + "Nov19SU" = "15.2.397.9" + "Mar21SU" = "15.2.397.11" + }) + "CU3" = (NewCUAndSUObject "15.2.464.5" @{ + "Nov19SU" = "15.2.464.7" + "Feb20SU" = "15.2.464.11" + "Mar20SU" = "15.2.464.14" + "Mar21SU" = "15.2.464.15" + }) + "CU4" = (NewCUAndSUObject "15.2.529.5" @{ + "Feb20SU" = "15.2.529.8" + "Mar20SU" = "15.2.529.11" + "Mar21SU" = "15.2.529.13" + }) + "CU5" = (NewCUAndSUObject "15.2.595.3" @{ + "Sep20SU" = "15.2.595.6" + "Mar21SU" = "15.2.595.8" + }) + "CU6" = (NewCUAndSUObject "15.2.659.4" @{ + "Sep20SU" = "15.2.659.6" + "Oct20SU" = "15.2.659.7" + "Nov20SU" = "15.2.659.8" + "Dec20SU" = "15.2.659.11" + "Mar21SU" = "15.2.659.12" + }) + "CU7" = (NewCUAndSUObject "15.2.721.2" @{ + "Oct20SU" = "15.2.721.3" + "Nov20SU" = "15.2.721.4" + "Dec20SU" = "15.2.721.6" + "Feb21SU" = "15.2.721.8" + "Mar21SU" = "15.2.721.13" + }) + "CU8" = (NewCUAndSUObject "15.2.792.3" @{ + "Feb21SU" = "15.2.792.5" + "Mar21SU" = "15.2.792.10" + "Apr21SU" = "15.2.792.13" + "May21SU" = "15.2.792.15" + }) + "CU9" = (NewCUAndSUObject "15.2.858.5" @{ + "Apr21SU" = "15.2.858.10" + "May21SU" = "15.2.858.12" + "Jul21SU" = "15.2.858.15" + }) + "CU10" = (NewCUAndSUObject "15.2.922.7" @{ + "Jul21SU" = "15.2.922.13" + "Oct21SU" = "15.2.922.14" + "Nov21SU" = "15.2.922.19" + "Jan22SU" = "15.2.922.20" + "Mar22SU" = "15.2.922.27" + }) + "CU11" = (NewCUAndSUObject "15.2.986.5" @{ + "Oct21SU" = "15.2.986.9" + "Nov21SU" = "15.2.986.14" + "Jan22SU" = "15.2.986.15" + "Mar22SU" = "15.2.986.22" + "May22SU" = "15.2.986.26" + "Aug22SU" = "15.2.986.29" + "Oct22SU" = "15.2.986.30" + "Nov22SU" = "15.2.986.36" + "Jan23SU" = "15.2.986.37" + }) + "CU12" = (NewCUAndSUObject "15.2.1118.7" @{ + "May22SU" = "15.2.1118.9" + "Aug22SU" = "15.2.1118.12" + "Oct22SU" = "15.2.1118.15" + "Nov22SU" = "15.2.1118.20" + "Jan23SU" = "15.2.1118.21" + }) + } + } +} + +# Must be outside function to use it as a validate script +function GetValidatePossibleParameters { + $exchangeBuildDictionary = GetExchangeBuildDictionary + $suNames = New-Object 'System.Collections.Generic.HashSet[string]' + $cuNames = New-Object 'System.Collections.Generic.HashSet[string]' + $versionNames = New-Object 'System.Collections.Generic.HashSet[string]' + + foreach ($exchangeKey in $exchangeBuildDictionary.Keys) { + [void]$versionNames.Add($exchangeKey) + foreach ($cuKey in $exchangeBuildDictionary[$exchangeKey].Keys) { + [void]$cuNames.Add($cuKey) + if ($null -eq $exchangeBuildDictionary[$exchangeKey][$cuKey].SU) { continue } + foreach ($suKey in $exchangeBuildDictionary[$exchangeKey][$cuKey].SU.Keys) { + [void]$suNames.Add($suKey) + } + } + } + return [PSCustomObject]@{ + Version = $versionNames + CU = $cuNames + SU = $suNames + } +} + +function ValidateSUParameter { + param($name) + + $possibleParameters = GetValidatePossibleParameters + $possibleParameters.SU.Contains($Name) +} + +function ValidateCUParameter { + param($Name) + + $possibleParameters = GetValidatePossibleParameters + $possibleParameters.CU.Contains($Name) +} + +function ValidateVersionParameter { + param($Name) + + $possibleParameters = GetValidatePossibleParameters + $possibleParameters.Version.Contains($Name) +} diff --git a/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 b/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 index 1edd638faa..2860bdc606 100644 --- a/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 +++ b/Shared/Tests/Get-ExchangeBuildVersionInformation.Tests.ps1 @@ -81,9 +81,9 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { $Script:results = Get-ExchangeBuildVersionInformation -FileVersion $fileVersion } - It "Return the final E19CU12 Oct22SU version object" { + It "Return the final E19CU10 Jul21SU version object" { $results.MajorVersion | Should -Be "Exchange2019" - $results.FriendlyName | Should -Be "Exchange 2019 CU10" + $results.FriendlyName | Should -Be "Exchange 2019 CU10 Jul21SU" $results.BuildVersion.ToString() | Should -Be "15.2.922.13" $results.CU | Should -Be "CU10" $results.ReleaseDate | Should -Be ([System.Convert]::ToDateTime([DateTime]"06/29/2021", [System.Globalization.DateTimeFormatInfo]::InvariantInfo)) @@ -132,4 +132,11 @@ Describe "Testing Get-ExchangeBuildVersionInformation.ps1" { $results.BuildVersion | Should -Be $null } } + + Context "Testing FindBySUName" { + It "Nov22SU" { + $results = Get-ExchangeBuildVersionInformation -FindBySUName "Nov22SU" + $results.Count | Should -Be 5 + } + } } From 786e33f0317d0925b49625ee860ed421d6178834 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 24 Jan 2023 17:21:02 -0600 Subject: [PATCH 15/33] Incude Feb19SU --- Shared/Get-ExchangeBuildVersionInformation.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Shared/Get-ExchangeBuildVersionInformation.ps1 b/Shared/Get-ExchangeBuildVersionInformation.ps1 index ece1e6e1ce..5240affae3 100644 --- a/Shared/Get-ExchangeBuildVersionInformation.ps1 +++ b/Shared/Get-ExchangeBuildVersionInformation.ps1 @@ -616,6 +616,7 @@ function GetExchangeBuildDictionary { "Mar21SU" = "15.1.1591.18" }) "CU12" = (NewCUAndSUObject "15.1.1713.5" @{ + "Feb19SU" = "15.1.1713.5" "Apr19SU" = "15.1.1713.6" "Jun19SU" = "15.1.1713.7" "Jul19SU" = "15.1.1713.8" @@ -695,6 +696,7 @@ function GetExchangeBuildDictionary { } "Exchange2019" = @{ "CU1" = (NewCUAndSUObject "15.2.330.5" @{ + "Feb19SU" = "15.2.330.5" "Apr19SU" = "15.2.330.7" "Jun19SU" = "15.2.330.8" "Jul19SU" = "15.2.330.9" From 2eaecf5d1ace669cbe52c237e38531182ec72e64 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 13:02:22 -0600 Subject: [PATCH 16/33] Include Feb19SU in name of test --- Setup/Tests/SetupAssist.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Setup/Tests/SetupAssist.Tests.ps1 b/Setup/Tests/SetupAssist.Tests.ps1 index 18093a3a9a..db604d8fdd 100644 --- a/Setup/Tests/SetupAssist.Tests.ps1 +++ b/Setup/Tests/SetupAssist.Tests.ps1 @@ -71,7 +71,7 @@ Describe "Testing SetupAssist" { $results = Test-ExchangeADSetupLevel Assert-MockCalled -CommandName Test-UserGroupMemberOf -ParameterFilter { $PrepareAdRequired -eq $true -and $PrepareSchemaRequired -eq $true } -Exactly 1 $results.Result | Should -Be "Failed" - $results.Details | Should -Be "Exchange 2013 CU22" + $results.Details | Should -Be "Exchange 2013 CU22 Feb19SU" } It "Exchange 2013 CU23 Ready" { From 153692a66eee97db406d143fb1f1e40360ed64a5 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 09:59:08 -0600 Subject: [PATCH 17/33] Load Microsoft.PowerShell.Security module for certificate tests --- .../Tests/Get-ExchangeServerCertificates.Tests.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-ExchangeServerCertificates.Tests.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-ExchangeServerCertificates.Tests.ps1 index 0c5193d8b3..761120d369 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-ExchangeServerCertificates.Tests.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-ExchangeServerCertificates.Tests.ps1 @@ -8,6 +8,11 @@ BeforeAll { $Script:parentPath = (Split-Path -Parent $PSScriptRoot) $Script:Server = $env:COMPUTERNAME . $Script:parentPath\Get-ExchangeServerCertificates.ps1 + . $PSScriptRoot\..\..\..\..\..\.build\Load-Module.ps1 + + if (-not (Load-Module -Name "Microsoft.PowerShell.Security" -MinimumVersion "7.0.0.0")) { + throw "Failed to load required security module" + } function Invoke-CatchActions { param() From e5dd82d882923e6f5e1719ad7023713df2da7a1d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 09:58:08 -0600 Subject: [PATCH 18/33] Make Operating System Build Info use same property name as Exchange Build Info BuildVersion should be what is used and as a System.Version type --- .../ServerInformation/Get-OperatingSystemBuildInformation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 index 4f5502af59..79c5d6f773 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemBuildInformation.ps1 @@ -16,7 +16,7 @@ function Get-OperatingSystemBuildInformation { $win32_OperatingSystem = Get-WmiObjectCriticalHandler -ComputerName $Server -Class Win32_OperatingSystem -CatchActionFunction ${Function:Invoke-CatchActions} } end { return [PSCustomObject]@{ - VersionBuild = $win32_OperatingSystem.Version + BuildVersion = [System.Version]$win32_OperatingSystem.Version MajorVersion = (Get-ServerOperatingSystemVersion -OsCaption $win32_OperatingSystem.Caption) FriendlyName = $win32_OperatingSystem.Caption OperatingSystem = $win32_OperatingSystem From 1db5bcf414e2df40be119c9bd6ff00240bdcfb7e Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 10:00:51 -0600 Subject: [PATCH 19/33] Fixed bug in Get-ExchangeInformation --- .../ExchangeInformation/Get-ExchangeInformation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index 67493c1499..e5a4dda07a 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -141,7 +141,7 @@ function Get-ExchangeInformation { Write-Verbose "SerializedDataSigning is not supported on this Exchange version & role combination" } - if (($getExchangeServer.IsMailboxServer) -and + if (($getExchangeServer.IsMailboxServer) -or ($getExchangeServer.IsEdgeServer)) { try { $exchangeServicesNotRunning = @() From c8ba351bf2e2e75df5edd4a6ede7055ca54836fd Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 10:04:24 -0600 Subject: [PATCH 20/33] Fixed issue within Invoke-AnalyzerFrequentConfigurationIssues.ps1 --- .../Invoke-AnalyzerFrequentConfigurationIssues.ps1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 index 53e9a6db89..41af8f3f9d 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 @@ -158,17 +158,16 @@ function Invoke-AnalyzerFrequentConfigurationIssues { $displayWriteType = "Grey" } else { $displayWriteType = "Red" - $domain = $organizationInformation.WildCardAcceptedDomain - $displayValue = "Error --- Accepted Domain `"$($domain.Id)`" is set to a Wild Card (*) Domain Name with a domain type of $($domain.DomainType.ToString()). This is not recommended as this is an open relay for the entire environment.`r`n`t`tMore Information: https://aka.ms/HC-OpenRelayDomain" + $displayValue = "Error --- Accepted Domain `"$($wildCardAcceptedDomain.Id)`" is set to a Wild Card (*) Domain Name with a domain type of $($wildCardAcceptedDomain.DomainType.ToString()). This is not recommended as this is an open relay for the entire environment.`r`n`t`tMore Information: https://aka.ms/HC-OpenRelayDomain" - if ($domain.DomainType.ToString() -eq "InternalRelay" -and + if ($wildCardAcceptedDomain.DomainType.ToString() -eq "InternalRelay" -and (($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016 -and $exchangeInformation.BuildInformation.CU -ge [HealthChecker.ExchangeCULevel]::CU22) -or ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019 -and $exchangeInformation.BuildInformation.CU -ge [HealthChecker.ExchangeCULevel]::CU11))) { $additionalDisplayValue = "`r`n`t`tERROR: You have an open relay set as Internal Replay Type and on a CU that is known to cause issues with transport services crashing. Follow the above article for more information." - } elseif ($domain.DomainType.ToString() -eq "InternalRelay") { + } elseif ($wildCardAcceptedDomain.DomainType.ToString() -eq "InternalRelay") { $additionalDisplayValue = "`r`n`t`tWARNING: You have an open relay set as Internal Relay Type. You are not on a CU yet that is having issue, recommended to change this prior to upgrading. Follow the above article for more information." } } From 1c27a5685b17ef67e9a7eb265d33126e21a58a4d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 10:05:21 -0600 Subject: [PATCH 21/33] Fixed issue within Invoke-AnalyzerExchangeInformation.ps1 --- .../Analyzer/Invoke-AnalyzerExchangeInformation.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index 58443b67b7..d82de9c311 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -256,7 +256,8 @@ function Invoke-AnalyzerExchangeInformation { Write-Verbose "Working on results from Test-ServiceHealth" $servicesNotRunning = $exchangeInformation.ExchangeServicesNotRunning - if ($null -ne $servicesNotRunning) { + if ($null -ne $servicesNotRunning -and + $servicesNotRunning.Count -gt 0 ) { Add-AnalyzedResultInformation -Name "Services Not Running" @baseParams foreach ($stoppedService in $servicesNotRunning) { From 2d792729f0b85939f2e75ca911eea2a42a64028b Mon Sep 17 00:00:00 2001 From: David Paulson Date: Tue, 24 Jan 2023 17:27:12 -0600 Subject: [PATCH 22/33] Remove CULevel from HC class --- ...ke-AnalyzerFrequentConfigurationIssues.ps1 | 8 +- .../Analyzer/Invoke-AnalyzerOsInformation.ps1 | 77 ++- ...Invoke-AnalyzerSecurityAMSIConfigState.ps1 | 12 +- .../Invoke-AnalyzerSecurityCve-2020-0796.ps1 | 4 +- .../Invoke-AnalyzerSecurityCve-2021-1730.ps1 | 9 +- .../Invoke-AnalyzerSecurityCve-2021-34470.ps1 | 15 +- .../Invoke-AnalyzerSecurityCve-2022-21978.ps1 | 2 +- ...oke-AnalyzerSecurityCve-MarchSuSpecial.ps1 | 74 +-- .../Invoke-AnalyzerSecurityCveCheck.ps1 | 453 ++++-------------- ...rSecurityExtendedProtectionConfigState.ps1 | 3 +- .../Invoke-AnalyzerSecurityIISModules.ps1 | 2 +- ...voke-AnalyzerSecurityMitigationService.ps1 | 9 +- ...yzerSecuritySerializedDataSigningState.ps1 | 22 +- .../Invoke-AnalyzerSecuritySettings.ps1 | 3 +- Diagnostics/HealthChecker/Helpers/Class.ps1 | 31 -- 15 files changed, 211 insertions(+), 513 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 index 41af8f3f9d..3da05060b1 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerFrequentConfigurationIssues.ps1 @@ -3,6 +3,7 @@ . $PSScriptRoot\Add-AnalyzedResultInformation.ps1 . $PSScriptRoot\Get-DisplayResultsGroupingKey.ps1 +. $PSScriptRoot\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerFrequentConfigurationIssues { [CmdletBinding()] param( @@ -161,11 +162,8 @@ function Invoke-AnalyzerFrequentConfigurationIssues { $displayValue = "Error --- Accepted Domain `"$($wildCardAcceptedDomain.Id)`" is set to a Wild Card (*) Domain Name with a domain type of $($wildCardAcceptedDomain.DomainType.ToString()). This is not recommended as this is an open relay for the entire environment.`r`n`t`tMore Information: https://aka.ms/HC-OpenRelayDomain" if ($wildCardAcceptedDomain.DomainType.ToString() -eq "InternalRelay" -and - (($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016 -and - $exchangeInformation.BuildInformation.CU -ge [HealthChecker.ExchangeCULevel]::CU22) -or - ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019 -and - $exchangeInformation.BuildInformation.CU -ge [HealthChecker.ExchangeCULevel]::CU11))) { - + ((Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2016" -CU "CU22") -or + (Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2019" -CU "CU11"))) { $additionalDisplayValue = "`r`n`t`tERROR: You have an open relay set as Internal Replay Type and on a CU that is known to cause issues with transport services crashing. Follow the above article for more information." } elseif ($wildCardAcceptedDomain.DomainType.ToString() -eq "InternalRelay") { $additionalDisplayValue = "`r`n`t`tWARNING: You have an open relay set as Internal Relay Type. You are not on a CU yet that is having issue, recommended to change this prior to upgrading. Follow the above article for more information." diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 index 303427253d..fccbc0bd50 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 @@ -4,6 +4,7 @@ . $PSScriptRoot\Add-AnalyzedResultInformation.ps1 . $PSScriptRoot\Get-DisplayResultsGroupingKey.ps1 . $PSScriptRoot\..\..\..\Shared\VisualCRedistributableVersionFunctions.ps1 +. $PSScriptRoot\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerOsInformation { [CmdletBinding()] param( @@ -94,57 +95,41 @@ function Invoke-AnalyzerOsInformation { } # .NET Supported Levels - [HealthChecker.ExchangeCULevel]$cuLevel = $exchangeInformation.BuildInformation.CU - [HealthChecker.OSServerVersion]$osVersion = $osInformation.BuildInformation.MajorVersion - [HealthChecker.ExchangeMajorVersion]$exchangeVersion = $exchangeInformation.BuildInformation.MajorVersion + $currentExchangeBuild = $exchangeInformation.BuildInformation.VersionInformation + $ex2019 = "Exchange2019" + $ex2016 = "Exchange2016" + $ex2013 = "Exchange2013" + $osVersion = $osInformation.BuildInformation.MajorVersion $recommendedNetVersion = $null - Write-Verbose "Checking $exchangeVersion .NET Framework Support Versions" - - if ([HealthChecker.ExchangeMajorVersion]::Exchange2019 -eq $exchangeVersion) { - if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU2) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } else { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } - } elseif ([HealthChecker.ExchangeMajorVersion]::Exchange2016 -eq $exchangeVersion) { - if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU2) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - } elseif ($cuLevel -eq [HealthChecker.ExchangeCULevel]::CU2) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } elseif ($cuLevel -eq [HealthChecker.ExchangeCULevel]::CU3) { - if ($osVersion -eq [HealthChecker.OSServerVersion]::Windows2016) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } else { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU8) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU11) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU13) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } else { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } + Write-Verbose "Checking $($exchangeInformation.BuildInformation.MajorVersion) .NET Framework Support Versions" + + if ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU4")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5 + } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU13") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU2")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix + } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU15") -or + (Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU2") -or + ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU3") -and + $osVersion -ne "Windows2016")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix + } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU19") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU8")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 + } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU21") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU11")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 + } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU21") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU13") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU2")) { + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 } else { - if ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU4) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5 - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU13) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU15) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU19) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU21) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 - } elseif ($cuLevel -lt [HealthChecker.ExchangeCULevel]::CU23) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 - } else { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 - } + $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 } + Write-Verbose "Recommended NET Version: $recommendedNetVersion" + if ($osInformation.NETFramework.MajorVersion -eq $recommendedNetVersion) { $params = $baseParams + @{ Name = ".NET Framework" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1 index 0a991906ab..475809d3af 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityAMSIConfigState.ps1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 + function Invoke-AnalyzerSecurityAMSIConfigState { [CmdletBinding()] param( @@ -26,12 +28,10 @@ function Invoke-AnalyzerSecurityAMSIConfigState { # AMSI integration is only available on Windows Server 2016 or higher and only on # Exchange Server 2016 CU21+ or Exchange Server 2019 CU10+. # AMSI is also not available on Edge Transport Servers (no http component available). - if ((($osInformation.BuildInformation.MajorVersion -ge [HealthChecker.OSServerVersion]::Windows2016) -and - (($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($exchangeCU -ge [HealthChecker.ExchangeCULevel]::CU21)) -or - (($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) -and - ($exchangeCU -ge [HealthChecker.ExchangeCULevel]::CU10))) -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + if (($osInformation.BuildInformation.BuildVersion -ge [System.Version]"10.0.0.0") -and + ((Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2016" -CU "CU21") -or + (Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2019" -CU "CU10")) -and + ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false)) { $amsiInformation = $HealthServerObject.ExchangeInformation.AMSIConfiguration $amsiWriteType = "Yellow" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-0796.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-0796.ps1 index 30fbd7a3d9..cc4c65a4b4 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-0796.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-0796.ps1 @@ -22,9 +22,9 @@ function Invoke-AnalyzerSecurityCve-2020-0796 { #Fix: KB4551762 #Workaround: Disable SMBv3 compression - if ($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { + if ($SecurityObject.MajorVersion -eq "Exchange2019") { Write-Verbose "Testing CVE: CVE-2020-0796" - $buildNumber = $SecurityObject.OsInformation.BuildInformation.VersionBuild.Split(".")[2] + $buildNumber = $SecurityObject.OsInformation.BuildInformation.BuildVersion.Build if (($buildNumber -eq 18362 -or $buildNumber -eq 18363) -and diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-1730.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-1730.ps1 index 549cd609c0..08c5ed11a8 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-1730.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-1730.ps1 @@ -2,6 +2,7 @@ # Licensed under the MIT License. . $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecurityCve-2021-1730 { [CmdletBinding()] param( @@ -20,11 +21,9 @@ function Invoke-AnalyzerSecurityCve-2021-1730 { #Fix: Configure Download Domains feature #Workaround: N/A - if (((($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($SecurityObject.CU -ge [HealthChecker.ExchangeCULevel]::CU18)) -or - (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) -and - ($SecurityObject.CU -ge [HealthChecker.ExchangeCULevel]::CU7))) -and - $SecurityObject.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if (((Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $SecurityObject.BuildInformation -Version "Exchange2016" -CU "CU18") -or + (Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $SecurityObject.BuildInformation -Version "Exchange2019" -CU "CU7")) -and + $SecurityObject.IsEdgeServer -eq $false) { $downloadDomainsEnabled = $SecurityObject.OrgInformation.EnableDownloadDomains $owaVDirObject = $SecurityObject.ExchangeInformation.GetOwaVirtualDirectory diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-34470.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-34470.ps1 index bc8c482433..18d55dde70 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-34470.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2021-34470.ps1 @@ -2,6 +2,7 @@ # Licensed under the MIT License. . $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecurityCve-2021-34470 { [CmdletBinding()] param( @@ -24,17 +25,15 @@ function Invoke-AnalyzerSecurityCve-2021-34470 { ##Exchange 2019 CU9 + July 2021 SU + /PrepareSchema or CU10 #Workaround: N/A - if (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) -or - (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU21)) -or - (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) -and - ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU10)) -and - $SecurityObject.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if (($SecurityObject.MajorVersion -eq "Exchange2013") -or + ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $SecurityObject.BuildInformation -Version "Exchange2016" -CU "CU21") -or + (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $SecurityObject.BuildInformation -Version "Exchange2019" -CU "CU10")) -and + $SecurityObject.IsEdgeServer -eq $false) { Write-Verbose "Testing CVE: CVE-2021-34470" $displayWriteTypeColor = $null - if ($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $SecurityObject.BuildRevision -SecurityFixedBuilds "1497.23" -CVENames "CVE-2021-34470" + if ($SecurityObject.MajorVersion -eq "Exchange2013") { + TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision "$($SecurityObject.ExchangeInformation.BuildInformation.ExchangeSetup.FileBuildPart).$($SecurityObject.ExchangeInformation.BuildInformation.ExchangeSetup.FilePrivatePart)" -SecurityFixedBuilds "1497.23" -CVENames "CVE-2021-34470" } if ($SecurityObject.OrgInformation.SecurityResults.CVE202134470.Unknown -or diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-21978.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-21978.ps1 index baf82f806d..311f4bdf4a 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-21978.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-21978.ps1 @@ -26,7 +26,7 @@ function Invoke-AnalyzerSecurityCve-2022-21978 { # Workaround: N/A # Because this is a security vulnerability in the domain, doesn't matter what version of Exchange is installed, still need to check each domain. - if ($SecurityObject.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if ($SecurityObject.IsEdgeServer -eq $false) { Write-Verbose "Testing CVE: CVE-2022-21978" $cveResults = $SecurityObject.OrgInformation.SecurityResults.CVE202221978 diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 index 154cf5ce7a..096874f709 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-MarchSuSpecial.ps1 @@ -2,6 +2,7 @@ # Licensed under the MIT License. . $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecurityCve-MarchSuSpecial { [CmdletBinding()] param( @@ -21,43 +22,54 @@ function Invoke-AnalyzerSecurityCve-MarchSuSpecial { #Fix: Update to a supported CU and apply KB5000871 $march2021SUInstalled = $null -ne $SecurityObject.ExchangeInformation.BuildInformation.KBsInstalled -and $SecurityObject.ExchangeInformation.BuildInformation.KBsInstalled -like "*KB5000871*" + $ex2019 = "Exchange2019" + $ex2016 = "Exchange2016" + $ex2013 = "Exchange2013" + $currentExchangeBuild = $SecurityObject.BuildInformation if (($march2021SUInstalled) -and ($SecurityObject.ExchangeInformation.BuildInformation.VersionInformation.SupportedBuild -eq $false)) { - if (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) -and - ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU23)) { - switch ($SecurityObject.CU) { - ([HealthChecker.ExchangeCULevel]::CU21) { $KBCveComb = @{KB4340731 = "CVE-2018-8302"; KB4459266 = "CVE-2018-8265", "CVE-2018-8448"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588" } } - ([HealthChecker.ExchangeCULevel]::CU22) { $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2019-0858"; KB4503027 = "ADV190018" } } - } - } elseif (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU18)) { - switch ($SecurityObject.CU) { - ([HealthChecker.ExchangeCULevel]::CU8) { $KBCveComb = @{KB4073392 = "CVE-2018-0924", "CVE-2018-0940", "CVE-2018-0941"; KB4092041 = "CVE-2018-8151", "CVE-2018-8152", "CVE-2018-8153", "CVE-2018-8154", "CVE-2018-8159" } } - ([HealthChecker.ExchangeCULevel]::CU9) { $KBCveComb = @{KB4092041 = "CVE-2018-8151", "CVE-2018-8152", "CVE-2018-8153", "CVE-2018-8154", "CVE-2018-8159"; KB4340731 = "CVE-2018-8374", "CVE-2018-8302" } } - ([HealthChecker.ExchangeCULevel]::CU10) { $KBCveComb = @{KB4340731 = "CVE-2018-8374", "CVE-2018-8302"; KB4459266 = "CVE-2018-8265", "CVE-2018-8448"; KB4468741 = "CVE-2018-8604"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588" } } - ([HealthChecker.ExchangeCULevel]::CU11) { $KBCveComb = @{KB4468741 = "CVE-2018-8604"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588"; KB4487563 = "CVE-2019-0817", "CVE-2018-0858"; KB4503027 = "ADV190018" } } - ([HealthChecker.ExchangeCULevel]::CU12) { $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2018-0858"; KB4503027 = "ADV190018"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266" } } - ([HealthChecker.ExchangeCULevel]::CU13) { $KBCveComb = @{KB4509409 = "CVE-2019-1084", "CVE-2019-1136", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266"; KB4523171 = "CVE-2019-1373" } } - ([HealthChecker.ExchangeCULevel]::CU14) { $KBCveComb = @{KB4523171 = "CVE-2019-1373"; KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } } - ([HealthChecker.ExchangeCULevel]::CU15) { $KBCveComb = @{KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } } - ([HealthChecker.ExchangeCULevel]::CU16) { $KBCveComb = @{KB4577352 = "CVE-2020-16875" } } - ([HealthChecker.ExchangeCULevel]::CU17) { $KBCveComb = @{KB4577352 = "CVE-2020-16875"; KB4581424 = "CVE-2020-16969"; KB4588741 = "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085"; KB4593465 = "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" } } - } - } elseif (($SecurityObject.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) -and - ($SecurityObject.CU -lt [HealthChecker.ExchangeCULevel]::CU7)) { - switch ($SecurityObject.CU) { - ([HealthChecker.ExchangeCULevel]::RTM) { $KBCveComb = @{KB4471389 = "CVE-2019-0586", "CVE-2019-0588"; KB4487563 = "CVE-2019-0817", "CVE-2019-0858"; KB4503027 = "ADV190018" } } - ([HealthChecker.ExchangeCULevel]::CU1) { $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2019-0858"; KB4503027 = "ADV190018"; KB4509409 = "CVE-2019-1084", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266" } } - ([HealthChecker.ExchangeCULevel]::CU2) { $KBCveComb = @{KB4509409 = "CVE-2019-1084", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266"; KB4523171 = "CVE-2019-1373" } } - ([HealthChecker.ExchangeCULevel]::CU3) { $KBCveComb = @{KB4523171 = "CVE-2019-1373"; KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } } - ([HealthChecker.ExchangeCULevel]::CU4) { $KBCveComb = @{KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } } - ([HealthChecker.ExchangeCULevel]::CU5) { $KBCveComb = @{KB4577352 = "CVE-2020-16875" } } - ([HealthChecker.ExchangeCULevel]::CU6) { $KBCveComb = @{KB4577352 = "CVE-2020-16875"; KB4581424 = "CVE-2020-16969"; KB4588741 = "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085"; KB4593465 = "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" } } - } + + if ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU21")) { + $KBCveComb = @{KB4340731 = "CVE-2018-8302"; KB4459266 = "CVE-2018-8265", "CVE-2018-8448"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU22")) { + $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2019-0858"; KB4503027 = "ADV190018" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU8")) { + $KBCveComb = @{KB4073392 = "CVE-2018-0924", "CVE-2018-0940", "CVE-2018-0941"; KB4092041 = "CVE-2018-8151", "CVE-2018-8152", "CVE-2018-8153", "CVE-2018-8154", "CVE-2018-8159" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU9")) { + $KBCveComb = @{KB4092041 = "CVE-2018-8151", "CVE-2018-8152", "CVE-2018-8153", "CVE-2018-8154", "CVE-2018-8159"; KB4340731 = "CVE-2018-8374", "CVE-2018-8302" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU10")) { + $KBCveComb = @{KB4340731 = "CVE-2018-8374", "CVE-2018-8302"; KB4459266 = "CVE-2018-8265", "CVE-2018-8448"; KB4468741 = "CVE-2018-8604"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU11")) { + $KBCveComb = @{KB4468741 = "CVE-2018-8604"; KB4471389 = "CVE-2019-0586", "CVE-2019-0588"; KB4487563 = "CVE-2019-0817", "CVE-2018-0858"; KB4503027 = "ADV190018" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU12")) { + $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2018-0858"; KB4503027 = "ADV190018"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU13")) { + $KBCveComb = @{KB4509409 = "CVE-2019-1084", "CVE-2019-1136", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266"; KB4523171 = "CVE-2019-1373" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU14")) { + $KBCveComb = @{KB4523171 = "CVE-2019-1373"; KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU15")) { + $KBCveComb = @{KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU16")) { + $KBCveComb = @{KB4577352 = "CVE-2020-16875" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU17")) { + $KBCveComb = @{KB4577352 = "CVE-2020-16875"; KB4581424 = "CVE-2020-16969"; KB4588741 = "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085"; KB4593465 = "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU1")) { + $KBCveComb = @{KB4487563 = "CVE-2019-0817", "CVE-2019-0858"; KB4503027 = "ADV190018"; KB4509409 = "CVE-2019-1084", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU2")) { + $KBCveComb = @{KB4509409 = "CVE-2019-1084", "CVE-2019-1137"; KB4515832 = "CVE-2019-1233", "CVE-2019-1266"; KB4523171 = "CVE-2019-1373" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU3")) { + $KBCveComb = @{KB4523171 = "CVE-2019-1373"; KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU4")) { + $KBCveComb = @{KB4536987 = "CVE-2020-0688", "CVE-2020-0692"; KB4540123 = "CVE-2020-0903" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU5")) { + $KBCveComb = @{KB4577352 = "CVE-2020-16875" } + } elseif ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU6")) { + $KBCveComb = @{KB4577352 = "CVE-2020-16875"; KB4581424 = "CVE-2020-16969"; KB4588741 = "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085"; KB4593465 = "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" } } else { Write-Verbose "No need to call 'Show-March2021SUOutdatedCUWarning'" } + if ($null -ne $KBCveComb) { foreach ($kbName in $KBCveComb.Keys) { foreach ($cveName in $KBCveComb[$kbName]) { diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 index f7fddb3c21..68428771a1 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1 @@ -10,6 +10,7 @@ . $PSScriptRoot\Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 . $PSScriptRoot\Invoke-AnalyzerSecurityIISModules.ps1 . $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecurityCveCheck { [CmdletBinding()] param( @@ -65,6 +66,19 @@ function Invoke-AnalyzerSecurityCveCheck { } } + function NewCveEntry { + param( + [string[]]$CVENames, + [string[]]$ExchangeVersion + ) + foreach ($cve in $CVENames) { + [PSCustomObject]@{ + CVE = $cve + Version = $ExchangeVersion + } + } + } + $exchangeInformation = $HealthServerObject.ExchangeInformation $osInformation = $HealthServerObject.OSInformation @@ -73,370 +87,105 @@ function Invoke-AnalyzerSecurityCveCheck { $exchangeCU = $exchangeInformation.BuildInformation.CU Write-Verbose "Exchange Build Revision: $buildRevision" Write-Verbose "Exchange CU: $exchangeCU" + # This dictionary is a list of how to crawl through the list and add all the vulnerabilities to display + # only place CVEs here that are fix by code fix only. If special checks are required, we need to check for that manually. + $ex131619 = @("Exchange2013", "Exchange2016", "Exchange2019") + $ex2013 = "Exchange2013" + $ex2016 = "Exchange2016" + $ex2019 = "Exchange2019" + $suNameDictionary = @{ + "Mar18SU" = ((NewCveEntry @("CVE-2018-0924", "CVE-2018-0940") @($ex2013, $ex2016)) + (NewCveEntry "CVE-2018-0941" $ex2016)) + "May18SU" = ((NewCveEntry @("CVE-2018-8151", "CVE-2018-8154", "CVE-2018-8159") @($ex2013, $ex2016)) + (NewCveEntry @("CVE-2018-8152", "CVE-2018-8153") $ex2016)) + "Aug18SU" = (@((NewCveEntry "CVE-2018-8302" @($ex2013, $ex2016))) + (NewCveEntry "CVE-2018-8374" $ex2016)) + "Oct18SU" = (NewCveEntry @("CVE-2018-8265", "CVE-2018-8448") @($ex2013, $ex2016)) + "Dec18SU" = (@(NewCveEntry "CVE-2018-8604" $ex2016)) + "Jan19SU" = (NewCveEntry @("CVE-2019-0586", "CVE-2019-0588") @($ex2013, $ex2016)) + "Feb19SU" = (NewCveEntry @("CVE-2019-0686", "CVE-2019-0724") $ex131619) + "Apr19SU" = (NewCveEntry @("CVE-2019-0817", "CVE-2019-0858") $ex131619) + "Jun19SU" = (@(NewCveEntry @("ADV190018") $ex131619)) + "Jul19SU" = ((NewCveEntry @("CVE-2019-1084", "CVE-2019-1137") $ex131619) + (NewCveEntry "CVE-2019-1136" @($ex2013, $ex2016))) + "Sep19SU" = (NewCveEntry @("CVE-2019-1233", "CVE-2019-1266") @($ex2016, $ex2019)) + "Nov19SU" = (@(NewCveEntry "CVE-2019-1373" $ex131619)) + "Feb20SU" = (NewCveEntry @("CVE-2020-0688", "CVE-2020-0692") $ex131619) + "Mar20SU" = (@(NewCveEntry "CVE-2020-0903" @($ex2016, $ex2019))) + "Sep20SU" = (@(NewCveEntry "CVE-2020-16875" @($ex2016, $ex2019))) + "Oct20SU" = (@(NewCveEntry "CVE-2020-16969" $ex131619)) + "Nov20SU" = (NewCveEntry @("CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085") $ex131619) + "Dec20SU" = ((NewCveEntry @("CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17142", "CVE-2020-17143") $ex131619) + (NewCveEntry "CVE-2020-17141" @($ex2016, $ex2019))) + "Feb21SU" = (@(NewCveEntry "CVE-2021-24085" @($ex2016, $ex2019))) + "Mar21SU" = (NewCveEntry @("CVE-2021-26855", "CVE-2021-26857", "CVE-2021-26858", "CVE-2021-27065", "CVE-2021-26412", "CVE-2021-27078", "CVE-2021-26854") $ex131619) + "Apr21SU" = (NewCveEntry @("CVE-2021-28480", "CVE-2021-28481", "CVE-2021-28482", "CVE-2021-28483") $ex131619) + "May21SU" = (NewCveEntry @("CVE-2021-31195", "CVE-2021-31198", "CVE-2021-31207", "CVE-2021-31209") $ex131619) + "Jul21SU" = (NewCveEntry @("CVE-2021-31206", "CVE-2021-31196", "CVE-2021-33768") $ex131619) + "Oct21SU" = (@((NewCveEntry "CVE-2021-26427" $ex131619)) + (NewCveEntry @("CVE-2021-41350", "CVE-2021-41348", "CVE-2021-34453") @($ex2016, $ex2019))) + "Nov21SU" = ((NewCveEntry @("CVE-2021-42305", "CVE-2021-41349") $ex131619) + (NewCveEntry "CVE-2021-42321" @($ex2016, $ex2019))) + "Jan22SU" = (NewCveEntry @("CVE-2022-21855", "CVE-2022-21846", "CVE-2022-21969") $ex131619) + "Mar22SU" = (@((NewCveEntry "CVE-2022-23277" $ex131619)) + (NewCveEntry "CVE-2022-24463" @($ex2016, $ex2019))) + "Aug22SU" = (@(NewCveEntry "CVE-2022-34692" @($ex2016, $ex2019))) + "Nov22SU" = ((NewCveEntry @("CVE-2022-41040", "CVE-2022-41082", "CVE-2022-41079", "CVE-2022-41078", "CVE-2022-41080") $ex131619) + (NewCveEntry "CVE-2022-41123" @($ex2016, $ex2019))) + "Jan23SU" = (@((NewCveEntry "CVE-2023-21762" $ex131619)) + (NewCveEntry @("CVE-2023-21745", "CVE-2023-21761", "CVE-2023-21763", "CVE-2023-21764") @($ex2016, $ex2019))) + } - if ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) { - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU19) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1347.5", "1365.3" ` - -CVENames "CVE-2018-0924", "CVE-2018-0940" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU20) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1365.7", "1367.6" ` - -CVENames "CVE-2018-8151", "CVE-2018-8154", "CVE-2018-8159" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU21) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1367.9", "1395.7" ` - -CVENames "CVE-2018-8302" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1395.8" ` - -CVENames "CVE-2018-8265", "CVE-2018-8448" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1395.10" ` - -CVENames "CVE-2019-0586", "CVE-2019-0588" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU22) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1473.3" ` - -CVENames "CVE-2019-0686", "CVE-2019-0724" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1473.4" ` - -CVENames "CVE-2019-0817", "CVE-2019-0858" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1473.5" ` - -CVENames "ADV190018" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU23) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.3" ` - -CVENames "CVE-2019-1084", "CVE-2019-1136", "CVE-2019-1137" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.4" ` - -CVENames "CVE-2019-1373" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.6" ` - -CVENames "CVE-2020-0688", "CVE-2020-0692" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.7" ` - -CVENames "CVE-2020-16969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.8" ` - -CVENames "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.10" ` - -CVENames "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17142", "CVE-2020-17143" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1395.12", "1473.6", "1497.12" ` - -CVENames "CVE-2021-26855", "CVE-2021-26857", "CVE-2021-26858", "CVE-2021-27065" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.12" ` - -CVENames "CVE-2021-26412", "CVE-2021-27078", "CVE-2021-26854" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.15" ` - -CVENames "CVE-2021-28480", "CVE-2021-28481", "CVE-2021-28482", "CVE-2021-28483" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.18" ` - -CVENames "CVE-2021-31195", "CVE-2021-31198", "CVE-2021-31207", "CVE-2021-31209" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.23" ` - -CVENames "CVE-2021-31206", "CVE-2021-31196", "CVE-2021-33768" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.24" ` - -CVENames "CVE-2021-26427" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.26" ` - -CVENames "CVE-2021-42305", "CVE-2021-41349" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.28" ` - -CVENames "CVE-2022-21855", "CVE-2022-21846", "CVE-2022-21969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.33" ` - -CVENames "CVE-2022-23277" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.44" ` - -CVENames "CVE-2022-41040", "CVE-2022-41082", "CVE-2022-41079", "CVE-2022-41078", "CVE-2022-41080" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1497.45" ` - -CVENames "CVE-2023-21762" - } - } elseif ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) { - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU8) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1261.39", "1415.4" ` - -CVENames "CVE-2018-0924", "CVE-2018-0940", "CVE-2018-0941" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU9) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1415.7", "1466.8" ` - -CVENames "CVE-2018-8151", "CVE-2018-8152", "CVE-2018-8153", "CVE-2018-8154", "CVE-2018-8159" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU10) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1466.9", "1531.6" ` - -CVENames "CVE-2018-8374", "CVE-2018-8302" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1531.8" ` - -CVENames "CVE-2018-8265", "CVE-2018-8448" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU11) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1531.8", "1591.11" ` - -CVENames "CVE-2018-8604" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1531.10", "1591.13" ` - -CVENames "CVE-2019-0586", "CVE-2019-0588" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU12) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1591.16", "1713.6" ` - -CVENames "CVE-2019-0817", "CVE-2018-0858" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1591.17", "1713.7" ` - -CVENames "ADV190018" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1713.5" ` - -CVENames "CVE-2019-0686", "CVE-2019-0724" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU13) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1713.8", "1779.4" ` - -CVENames "CVE-2019-1084", "CVE-2019-1136", "CVE-2019-1137" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1713.9", "1779.5" ` - -CVENames "CVE-2019-1233", "CVE-2019-1266" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU14) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1779.7", "1847.5" ` - -CVENames "CVE-2019-1373" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU15) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1847.7", "1913.7" ` - -CVENames "CVE-2020-0688", "CVE-2020-0692" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1847.10", "1913.10" ` - -CVENames "CVE-2020-0903" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU17) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1979.6", "2044.6" ` - -CVENames "CVE-2020-16875" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU18) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2106.2" ` - -CVENames "CVE-2021-1730" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2044.7", "2106.3" ` - -CVENames "CVE-2020-16969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2044.8", "2106.4" ` - -CVENames "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2044.12", "2106.6" ` - -CVENames "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU19) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2106.8", "2176.4" ` - -CVENames "CVE-2021-24085" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "1415.8", "1466.13", "1531.12", "1591.18", "1713.10", "1779.8", "1847.12", "1913.12", "1979.8", "2044.13", "2106.13", "2176.9" ` - -CVENames "CVE-2021-26855", "CVE-2021-26857", "CVE-2021-26858", "CVE-2021-27065" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2106.13", "2176.9" ` - -CVENames "CVE-2021-26412", "CVE-2021-27078", "CVE-2021-26854" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU20) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2176.12", "2242.8" ` - -CVENames "CVE-2021-28480", "CVE-2021-28481", "CVE-2021-28482", "CVE-2021-28483" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2176.14", "2242.10" ` - -CVENames "CVE-2021-31195", "CVE-2021-31198", "CVE-2021-31207", "CVE-2021-31209" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU21) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2242.12", "2308.14" ` - -CVENames "CVE-2021-31206", "CVE-2021-31196", "CVE-2021-33768" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU22) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2308.15", "2375.7" ` - -CVENames "CVE-2021-26427" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2308.15", "2375.12" ` - -CVENames "CVE-2021-41350", "CVE-2021-41348", "CVE-2021-34453" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2308.20", "2375.17" ` - -CVENames "CVE-2021-42305", "CVE-2021-41349", "CVE-2021-42321" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2308.21", "2375.18" ` - -CVENames "CVE-2022-21855", "CVE-2022-21846", "CVE-2022-21969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2308.27", "2375.24" ` - -CVENames "CVE-2022-23277", "CVE-2022-24463" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU23) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2375.31", "2507.12" ` - -CVENames "CVE-2022-34692" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2375.37", "2507.16" ` - -CVENames "CVE-2022-41040", "CVE-2022-41082", "CVE-2022-41079", "CVE-2022-41078", "CVE-2022-41080", "CVE-2022-41123" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "2507.17" ` - -CVENames "CVE-2023-21745", "CVE-2023-21761", "CVE-2023-21762", "CVE-2023-21763", "CVE-2023-21764" - } - } elseif ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU1) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "221.14" ` - -CVENames "CVE-2019-0586", "CVE-2019-0588" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "221.16", "330.7" ` - -CVENames "CVE-2019-0817", "CVE-2019-0858" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "221.17", "330.8" ` - -CVENames "ADV190018" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "330.6" ` - -CVENames "CVE-2019-0686", "CVE-2019-0724" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU2) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "330.9", "397.5" ` - -CVENames "CVE-2019-1084", "CVE-2019-1137" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "397.6", "330.10" ` - -CVENames "CVE-2019-1233", "CVE-2019-1266" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU3) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "397.9", "464.7" ` - -CVENames "CVE-2019-1373" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU4) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "464.11", "529.8" ` - -CVENames "CVE-2020-0688", "CVE-2020-0692" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "464.14", "529.11" ` - -CVENames "CVE-2020-0903" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU6) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "595.6", "659.6" ` - -CVENames "CVE-2020-16875" - } - - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU7) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "721.2" ` - -CVENames "CVE-2021-1730" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "659.7", "721.3" ` - -CVENames "CVE-2020-16969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "659.8", "721.4" ` - -CVENames "CVE-2020-17083", "CVE-2020-17084", "CVE-2020-17085" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "659.11", "721.6" ` - -CVENames "CVE-2020-17117", "CVE-2020-17132", "CVE-2020-17141", "CVE-2020-17142", "CVE-2020-17143" - } + # Need to organize the list so oldest CVEs come out first. + $monthOrder = @{ + "Jan" = 1 + "Feb" = 2 + "Mar" = 3 + "Apr" = 4 + "May" = 5 + "Jun" = 6 + "Jul" = 7 + "Aug" = 8 + "Sep" = 9 + "Oct" = 10 + "Nov" = 11 + "Dec" = 12 + } + $unsortedKeys = @($suNameDictionary.Keys) + $sortedKeys = New-Object System.Collections.Generic.List[string] - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU8) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "721.8", "792.5" ` - -CVENames "CVE-2021-24085" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "221.18", "330.11", "397.11", "464.15", "529.13", "595.8", "659.12", "721.13", "792.10" ` - -CVENames "CVE-2021-26855", "CVE-2021-26857", "CVE-2021-26858", "CVE-2021-27065" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "721.13", "792.10" ` - -CVENames "CVE-2021-26412", "CVE-2021-27078", "CVE-2021-26854" - } + foreach ($value in $unsortedKeys) { + $month = $value.Substring(0, 3) + $year = [int]$value.Substring(3, 2) + $insertAt = 0 + while ($insertAt -lt $sortedKeys.Count) { - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU9) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "792.13", "858.10" ` - -CVENames "CVE-2021-28480", "CVE-2021-28481", "CVE-2021-28482", "CVE-2021-28483" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "792.15", "858.12" ` - -CVENames "CVE-2021-31195", "CVE-2021-31198", "CVE-2021-31207", "CVE-2021-31209" - } + $compareMonth = $sortedKeys[$insertAt].Substring(0, 3) + $compareYear = [int]$sortedKeys[$insertAt].Substring(3, 2) + # break to add at current spot in list + if ($compareYear -gt $year) { break } + elseif ( $compareYear -eq $year -and + $monthOrder[$month] -lt $monthOrder[$compareMonth]) { break } - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU10) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "858.15", "922.13" ` - -CVENames "CVE-2021-31206", "CVE-2021-31196", "CVE-2021-33768" + $insertAt++ } - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU11) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "922.14", "986.5" ` - -CVENames "CVE-2021-26427" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "922.14", "986.9" ` - -CVENames "CVE-2021-41350", "CVE-2021-41348", "CVE-2021-34453" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "922.19", "986.14" ` - -CVENames "CVE-2021-42305", "CVE-2021-41349", "CVE-2021-42321" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "922.20", "986.15" ` - -CVENames "CVE-2022-21855", "CVE-2022-21846", "CVE-2022-21969" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "922.27", "986.22" ` - -CVENames "CVE-2022-23277", "CVE-2022-24463" - } + $sortedKeys.Insert($insertAt, $value) + } - if ($exchangeCU -le [HealthChecker.ExchangeCULevel]::CU12) { - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "986.29", "1118.12" ` - -CVENames "CVE-2022-34692" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "986.36", "1118.20" ` - -CVENames "CVE-2022-41040", "CVE-2022-41082", "CVE-2022-41079", "CVE-2022-41078", "CVE-2022-41080", "CVE-2022-41123" - TestVulnerabilitiesByBuildNumbersForDisplay -ExchangeBuildRevision $buildRevision ` - -SecurityFixedBuilds "986.37", "1118.21" ` - -CVENames "CVE-2023-21745", "CVE-2023-21761", "CVE-2023-21762", "CVE-2023-21763", "CVE-2023-21764" + foreach ($key in $sortedKeys) { + if (-not (Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -SUName $key)) { + Write-Verbose "Tested that we aren't on SU $key or greater" + $cveNames = ($suNameDictionary[$key] | Where-Object { $_.Version.Contains($exchangeInformation.BuildInformation.MajorVersion) }).CVE + foreach ($cveName in $cveNames) { + $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 $cveName) + DisplayWriteType = "Red" + DisplayTestingValue = $cveName + AddHtmlDetailRow = $false + } + Add-AnalyzedResultInformation @params + } } - } else { - Write-Verbose "Unknown Version of Exchange" } $securityObject = [PSCustomObject]@{ + BuildInformation = $exchangeInformation.BuildInformation.VersionInformation MajorVersion = $exchangeInformation.BuildInformation.MajorVersion - ServerRole = $exchangeInformation.BuildInformation.ServerRole - CU = $exchangeCU - BuildRevision = $buildRevision + IsEdgeServer = $exchangeInformation.GetExchangeServer.IsEdgeServer ExchangeInformation = $exchangeInformation OsInformation = $osInformation OrgInformation = $HealthServerObject.OrganizationInformation diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 index 00082fa978..1b43b18752 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExtendedProtectionConfigState.ps1 @@ -23,8 +23,7 @@ function Invoke-AnalyzerSecurityExtendedProtectionConfigState { } # Supported server roles are: Mailbox and ClientAccess - if (($SecurityObject.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2013) -and - ($SecurityObject.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + if ($SecurityObject.IsEdgeServer -eq $false) { if ($null -ne $extendedProtection) { Write-Verbose "Exchange extended protection information found - performing vulnerability testing" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityIISModules.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityIISModules.ps1 index 97ba42fb9c..3af8e57ca1 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityIISModules.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityIISModules.ps1 @@ -26,7 +26,7 @@ function Invoke-AnalyzerSecurityIISModules { } # Description: Check for modules which are loaded by IIS and not signed by Microsoft or not signed at all - if ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if ($SecurityObject.IsEdgeServer -eq $false) { if ($null -ne $moduleInformation) { $iisModulesOutputList = New-Object 'System.Collections.Generic.List[object]' $modulesWriteType = "Grey" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityMitigationService.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityMitigationService.ps1 index 06760229da..82908a2240 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityMitigationService.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityMitigationService.ps1 @@ -2,6 +2,7 @@ # Licensed under the MIT License. . $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecurityMitigationService { [CmdletBinding()] param( @@ -25,11 +26,9 @@ function Invoke-AnalyzerSecurityMitigationService { } #Description: Check for Exchange Emergency Mitigation Service (EEMS) #Introduced in: Exchange 2016 CU22, Exchange 2019 CU11 - if (((($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) -and - ($exchangeCU -ge [HealthChecker.ExchangeCULevel]::CU22)) -or - (($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) -and - ($exchangeCU -ge [HealthChecker.ExchangeCULevel]::CU11))) -and - $exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if (((Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2016" -CU "CU22") -or + (Test-ExchangeBuildGreaterOrEqualThanBuild -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -Version "Exchange2019" -CU "CU11")) -and + $exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) { if (-not([String]::IsNullOrEmpty($mitigationService.MitigationServiceOrgState))) { if (($mitigationService.MitigationServiceOrgState) -and diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySerializedDataSigningState.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySerializedDataSigningState.ps1 index 718a992274..ec1112a9e5 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySerializedDataSigningState.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySerializedDataSigningState.ps1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. $PSScriptRoot\..\Add-AnalyzedResultInformation.ps1 +. $PSScriptRoot\..\..\Helpers\CompareExchangeBuildLevel.ps1 function Invoke-AnalyzerSecuritySerializedDataSigningState { [CmdletBinding()] param( @@ -18,8 +20,6 @@ function Invoke-AnalyzerSecuritySerializedDataSigningState { $exchangeInformation = $HealthServerObject.ExchangeInformation $serverName = ($HealthServerObject.ServerName.Split(".")[0]).ToLower() $exchangeBuild = $exchangeInformation.BuildInformation.VersionInformation.BuildVersion - $exchangeCU = $exchangeInformation.BuildInformation.VersionInformation.CU - $exchangeMajor = $exchangeInformation.BuildInformation.MajorVersion $baseParams = @{ AnalyzedInformation = $AnalyzeResults DisplayGroupingKey = $DisplayGroupingKey @@ -36,27 +36,15 @@ function Invoke-AnalyzerSecuritySerializedDataSigningState { Same goes for the SettingOverride set on E15 - it will be ignored and the feature remains off until the registry value is set. #> - if ($exchangeMajor -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { - switch ($exchangeCU) { - { $_ -eq "CU12" } { $serializedDataSigningSupportedBuild = ($exchangeBuild -ge "15.2.1118.21"); break } - { $_ -eq "CU11" } { $serializedDataSigningSupportedBuild = ($exchangeBuild -ge "15.2.986.37"); break } - default { $serializedDataSigningSupportedBuild = $false } - } - } elseif ($exchangeMajor -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) { - $serializedDataSigningSupportedBuild = ($exchangeBuild -ge "15.1.2507.17") - } else { - $serializedDataSigningSupportedBuild = ($exchangeBuild -ge "15.0.1497.45") - } - - if (($serializedDataSigningSupportedBuild) -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + if ((Test-ExchangeBuildGreaterOrEqualThanSecurityPatch -CurrentExchangeBuild $exchangeInformation.BuildInformation.VersionInformation -SUName "Jan23SU") -and + ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false)) { Write-Verbose "SerializedDataSigning is available on this Exchange role / version build combination" $serializedDataSigningInformation = $HealthServerObject.ExchangeInformation.SerializationDataSigningConfiguration $serializedDataSigningWriteType = "Yellow" $serializedDataSigningConfigurationWarning = "`r`n`t`tThis may pose a security risk to your servers`r`n`t`tMore Information: https://aka.ms/HC-SerializedDataSigning" - if ($exchangeMajor -ge [HealthChecker.ExchangeMajorVersion]::Exchange2016) { + if ($exchangeBuild -ge "15.1.0.0") { Write-Verbose "Checking SettingOverride for SerializedDataSigning configuration state" if (($serializedDataSigningInformation.Count -eq 1) -and (-not($serializedDataSigningInformation.FailedQuery -eq $true))) { diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index 2374da599a..d7f0be934b 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -332,7 +332,8 @@ function Invoke-AnalyzerSecuritySettings { $additionalDisplayValue = [string]::Empty $smb1Settings = $osInformation.Smb1ServerSettings - if ($osInformation.BuildInformation.MajorVersion -gt [HealthChecker.OSServerVersion]::Windows2012) { + if ($osInformation.BuildInformation.BuildVersion -ge "10.0.0.0" -or + $osInformation.BuildInformation.MajorVersion -like "Windows2012*") { $displayValue = "False" $writeType = "Green" diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index 29d66abac3..3c04486fcd 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -17,37 +17,6 @@ using System.Collections; public DateTime GenerationTime; //Time stamp of running the script } - //enum for CU levels of Exchange - public enum ExchangeCULevel - { - Unknown, - Preview, - RTM, - CU1, - CU2, - CU3, - CU4, - CU5, - CU6, - CU7, - CU8, - CU9, - CU10, - CU11, - CU12, - CU13, - CU14, - CU15, - CU16, - CU17, - CU18, - CU19, - CU20, - CU21, - CU22, - CU23 - } - //enum for the server roles that the computer is public enum ExchangeServerRole { From 449637feb4fb4c144b08061e46cfb5c8eaa8cd6c Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 3 Feb 2023 13:05:31 -0600 Subject: [PATCH 23/33] Adjust for previous missing CVE --- .../HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 | 4 ++-- .../HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 index a7704fad38..2ddd3318d9 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E16.Main.Tests.ps1 @@ -138,11 +138,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 25 + $cveTests.Count | Should -Be 26 $downloadDomains = GetObject "CVE-2021-1730" $downloadDomains.DownloadDomainsEnabled | Should -Be "false" - $Script:ActiveGrouping.Count | Should -Be 32 + $Script:ActiveGrouping.Count | Should -Be 33 } } diff --git a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 index 89d834cebb..d6216eaaa4 100644 --- a/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthChecker.E19.Main.Tests.ps1 @@ -138,7 +138,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 25 + $cveTests.Count | Should -Be 26 $downloadDomains = GetObject "CVE-2021-1730" $downloadDomains.DownloadDomainsEnabled | Should -Be "False" TestObjectMatch "Extended Protection Vulnerable" "True" -WriteType "Red" From 374c6ec2a8e7ffc99d81d8a03b18039087401d35 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Wed, 8 Feb 2023 16:21:05 -0600 Subject: [PATCH 24/33] Removed ServerRole, MajorVersion, OSVersion enums --- .../Invoke-AnalyzerExchangeInformation.ps1 | 13 ++--- .../Invoke-AnalyzerHardwareInformation.ps1 | 12 ++--- .../Invoke-AnalyzerHybridInformation.ps1 | 2 +- .../Invoke-AnalyzerIISInformation.ps1 | 2 +- .../Analyzer/Invoke-AnalyzerNicSettings.ps1 | 3 +- .../Analyzer/Invoke-AnalyzerOsInformation.ps1 | 12 ++--- ...zerSecurityCve-2022-41040.NotPublished.ps1 | 2 +- ...e-AnalyzerSecurityExchangeCertificates.ps1 | 6 +-- .../Get-ExchangeUpdates.ps1 | 7 +-- .../ExchangeInformation/Get-ServerRole.ps1 | 10 ++-- Diagnostics/HealthChecker/Helpers/Class.ps1 | 47 ------------------- 11 files changed, 34 insertions(+), 82 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index d82de9c311..a85268e4ea 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -148,7 +148,7 @@ function Invoke-AnalyzerExchangeInformation { } Add-AnalyzedResultInformation @params - if ($exchangeInformation.BuildInformation.ServerRole -le [HealthChecker.ExchangeServerRole]::Mailbox) { + if ($exchangeInformation.GetExchangeServer.IsMailboxServer -eq $true) { $dagName = [System.Convert]::ToString($exchangeInformation.GetMailboxServer.DatabaseAvailabilityGroup) if ([System.String]::IsNullOrWhiteSpace($dagName)) { $dagName = "Standalone Server" @@ -166,9 +166,7 @@ function Invoke-AnalyzerExchangeInformation { } Add-AnalyzedResultInformation @params - if (($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Hub) -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::None)) { + if ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) { Write-Verbose "Working on MRS Proxy Settings" $mrsProxyDetails = $exchangeInformation.GetWebServicesVirtualDirectory.MRSProxyEnabled @@ -187,9 +185,8 @@ function Invoke-AnalyzerExchangeInformation { Add-AnalyzedResultInformation @params } - if ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013 -and - $exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge -and - $exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Mailbox) { + if ($exchangeInformation.BuildInformation.MajorVersion -eq "Exchange2013" -and + $exchangeInformation.GetExchangeServer.IsClientAccessServer -eq $true) { if ($null -ne $exchangeInformation.ApplicationPools -and $exchangeInformation.ApplicationPools.Count -gt 0) { @@ -317,7 +314,7 @@ function Invoke-AnalyzerExchangeInformation { } } - if ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge -and + if ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false -and $null -ne $exchangeInformation.ExtendedProtectionConfig) { $params = $baseParams + @{ Name = "Extended Protection Enabled (Any VDir)" diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 index a2515bad33..30843f77d9 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 @@ -81,12 +81,12 @@ function Invoke-AnalyzerHardwareInformation { $displayWriteTypeLogic = $displayWriteTypePhysical = "Green" if (($logicalValue -gt 24 -and - $exchangeInformation.BuildInformation.MajorVersion -lt [HealthChecker.ExchangeMajorVersion]::Exchange2019) -or + $exchangeInformation.BuildInformation.VersionInformation.BuildVersion -lt "15.2.0.0") -or $logicalValue -gt 48) { $displayWriteTypeLogic = "Red" if (($physicalValue -gt 24 -and - $exchangeInformation.BuildInformation.MajorVersion -lt [HealthChecker.ExchangeMajorVersion]::Exchange2019) -or + $exchangeInformation.BuildInformation.VersionInformation.BuildVersion -lt "15.2.0.0") -or $physicalValue -gt 48) { $physicalValueDisplay = "$physicalValue - Error" $displayWriteTypePhysical = "Red" @@ -243,12 +243,12 @@ function Invoke-AnalyzerHardwareInformation { $displayWriteType = "Yellow" $displayDetails = [string]::Empty - if ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { + if ($exchangeInformation.BuildInformation.VersionInformation.BuildVersion -ge "15.2.0.0") { if ($totalPhysicalMemory -gt 256) { $displayDetails = "{0} GB `r`n`t`tWarning: We recommend for the best performance to be scaled at or below 256 GB of Memory" -f $totalPhysicalMemory } elseif ($totalPhysicalMemory -lt 64 -and - $exchangeInformation.BuildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::Edge) { + $exchangeInformation.GetExchangeServer.IsEdgeServer -eq $true) { $displayDetails = "{0} GB `r`n`t`tWarning: We recommend for the best performance to have a minimum of 64GB of RAM installed on the machine." -f $totalPhysicalMemory } elseif ($totalPhysicalMemory -lt 128) { $displayDetails = "{0} GB `r`n`t`tWarning: We recommend for the best performance to have a minimum of 128GB of RAM installed on the machine." -f $totalPhysicalMemory @@ -257,10 +257,10 @@ function Invoke-AnalyzerHardwareInformation { $displayWriteType = "Grey" } } elseif ($totalPhysicalMemory -gt 192 -and - $exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2016) { + $exchangeInformation.BuildInformation.MajorVersion -eq "Exchange2016") { $displayDetails = "{0} GB `r`n`t`tWarning: We recommend for the best performance to be scaled at or below 192 GB of Memory." -f $totalPhysicalMemory } elseif ($totalPhysicalMemory -gt 96 -and - $exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2013) { + $exchangeInformation.BuildInformation.MajorVersion -eq "Exchange2013") { $displayDetails = "{0} GB `r`n`t`tWarning: We recommend for the best performance to be scaled at or below 96GB of Memory." -f $totalPhysicalMemory } else { $displayDetails = "{0} GB" -f $totalPhysicalMemory diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHybridInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHybridInformation.ps1 index 78d1860f97..cd4c9f325a 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHybridInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHybridInformation.ps1 @@ -24,7 +24,7 @@ function Invoke-AnalyzerHybridInformation { $exchangeInformation = $HealthServerObject.ExchangeInformation $getHybridConfiguration = $HealthServerObject.OrganizationInformation.GetHybridConfiguration - if ($exchangeInformation.BuildInformation.MajorVersion -ge [HealthChecker.ExchangeMajorVersion]::Exchange2013 -and + if ($exchangeInformation.BuildInformation.VersionInformation.BuildVersion -ge "15.0.0.0" -and $null -ne $getHybridConfiguration) { $params = $baseParams + @{ diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 index 63b72d94be..633de9afec 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 @@ -23,7 +23,7 @@ function Invoke-AnalyzerIISInformation { DisplayGroupingKey = (Get-DisplayResultsGroupingKey -Name "Exchange IIS Information" -DisplayOrder $Order) } - if ($exchangeInformation.BuildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::Edge) { + if ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $true) { Write-Verbose "No IIS information to review on an Edge Server" return } diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 index 3b322f70b7..ce114c746c 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 @@ -38,7 +38,8 @@ function Invoke-AnalyzerNicSettings { } Add-AnalyzedResultInformation @params - if ($osInformation.BuildInformation.MajorVersion -ge [HealthChecker.OSServerVersion]::Windows2012R2) { + if ($osInformation.BuildInformation.MajorVersion -notlike "Windows2008*" -and + $osInformation.BuildInformation.MajorVersion -ne "Windows2012") { Write-Verbose "On Windows 2012 R2 or new. Can provide more details on the NICs" $driverDate = $adapter.DriverDate diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 index fccbc0bd50..384e9dcd49 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 @@ -193,7 +193,7 @@ function Invoke-AnalyzerOsInformation { $displayValue = ($pageFileDisplayTemplate -f $pageFileObj.Name, $pageFileObj.MaxPageSize) } - if ($exchangeInformation.BuildInformation.MajorVersion -eq [HealthChecker.ExchangeMajorVersion]::Exchange2019) { + if ($exchangeInformation.BuildInformation.VersionInformation.BuildVersion -ge "15.2.0.0") { $recommendedPageFile = [Math]::Round($totalPhysicalMemory / 4) $pageFileObj.RecommendedPageFile = $recommendedPageFile Write-Verbose "System is running Exchange 2019. Recommended PageFile Size: $recommendedPageFile" @@ -292,7 +292,7 @@ function Invoke-AnalyzerOsInformation { $displayValue = $osInformation.NetworkInformation.HttpProxy.ProxyAddress if (($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne "None") -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge)) { + ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false)) { $displayValue = "$($osInformation.NetworkInformation.HttpProxy.ProxyAddress) --- Warning this can cause client connectivity issues." $displayWriteType = "Yellow" } @@ -315,7 +315,7 @@ function Invoke-AnalyzerOsInformation { } if (($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne "None") -and - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) -and + ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) -and ($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne $exchangeInformation.GetExchangeServer.InternetWebProxy.Authority)) { $params = $baseParams + @{ Details = "Error: Exchange Internet Web Proxy doesn't match OS Web Proxy." @@ -355,7 +355,7 @@ function Invoke-AnalyzerOsInformation { } Add-AnalyzedResultInformation @params - if ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) { $params = $baseParams + @{ Name = "Visual C++ 2013" Details = $displayValue2013 @@ -364,7 +364,7 @@ function Invoke-AnalyzerOsInformation { Add-AnalyzedResultInformation @params } - if (($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge -and + if (($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false -and ($displayWriteType2012 -eq "Yellow" -or $displayWriteType2013 -eq "Yellow")) -or $displayWriteType2012 -eq "Yellow") { @@ -378,7 +378,7 @@ function Invoke-AnalyzerOsInformation { } if ($defaultValue -eq $displayValue2012 -or - ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge -and + ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false -and $displayValue2013 -eq $defaultValue)) { $params = $baseParams + @{ diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-41040.NotPublished.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-41040.NotPublished.ps1 index 32979a5d31..e636a0df56 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-41040.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2022-41040.NotPublished.ps1 @@ -23,7 +23,7 @@ function Invoke-AnalyzerSecurityCve-2022-41040 { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $details = $null - if ($SecurityObject.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if ($SecurityObject.ExchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) { Write-Verbose "Testing CVE: CVE-2022-41040" $verifyPattern = "(?=.*autodiscover)(?=.*powershell)" $foundSecureRuleDefaultWebSite = $false diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExchangeCertificates.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExchangeCertificates.ps1 index 0a9f5c7dd5..892533ec30 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExchangeCertificates.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityExchangeCertificates.ps1 @@ -170,7 +170,7 @@ function Invoke-AnalyzerSecurityExchangeCertificates { Add-AnalyzedResultInformation @params } - if ($exchangeInformation.BuildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) { + if ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) { $params = $baseParams + @{ Name = "Internal Transport Certificate" Details = $certificate.IsInternalTransportCertificate @@ -251,7 +251,7 @@ function Invoke-AnalyzerSecurityExchangeCertificates { } Add-AnalyzedResultInformation @params } - } elseif ($exchangeInformation.BuildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::Edge) { + } elseif ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $true) { $params = $baseParams + @{ Name = "Valid Internal Transport Certificate Found On Server" Details = $false @@ -322,7 +322,7 @@ function Invoke-AnalyzerSecurityExchangeCertificates { } Add-AnalyzedResultInformation @params } - } elseif ($exchangeInformation.BuildInformation.ServerRole -eq [HealthChecker.ExchangeServerRole]::Edge) { + } elseif ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $true) { $params = $baseParams + @{ Name = "Valid Auth Certificate Found On Server" Details = $false diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeUpdates.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeUpdates.ps1 index 74e26cee14..e03b9e1ca3 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeUpdates.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeUpdates.ps1 @@ -8,14 +8,15 @@ function Get-ExchangeUpdates { [string]$Server, [Parameter(Mandatory = $true)] - [HealthChecker.ExchangeMajorVersion]$ExchangeMajorVersion + [ValidateSet("Exchange2013", "Exchange2016", "Exchange2019")] + [string]$ExchangeMajorVersion ) Write-Verbose("Calling: $($MyInvocation.MyCommand) Passed: $ExchangeMajorVersion") $RegLocation = [string]::Empty - if ([HealthChecker.ExchangeMajorVersion]::Exchange2013 -eq $ExchangeMajorVersion) { + if ("Exchange2013" -eq $ExchangeMajorVersion) { $RegLocation = "SOFTWARE\Microsoft\Updates\Exchange 2013" - } elseif ([HealthChecker.ExchangeMajorVersion]::Exchange2016 -eq $ExchangeMajorVersion) { + } elseif ("Exchange2016" -eq $ExchangeMajorVersion) { $RegLocation = "SOFTWARE\Microsoft\Updates\Exchange 2016" } else { $RegLocation = "SOFTWARE\Microsoft\Updates\Exchange 2019" diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ServerRole.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ServerRole.ps1 index aedee7b47a..7f4a2f89fd 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ServerRole.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ServerRole.ps1 @@ -10,14 +10,14 @@ function Get-ServerRole { Write-Verbose "Roll: $roles" #Need to change this to like because of Exchange 2010 with AIO with the hub role. if ($roles -like "Mailbox, ClientAccess*") { - return [HealthChecker.ExchangeServerRole]::MultiRole + return "MultiRole" } elseif ($roles -eq "Mailbox") { - return [HealthChecker.ExchangeServerRole]::Mailbox + return "Mailbox" } elseif ($roles -eq "Edge") { - return [HealthChecker.ExchangeServerRole]::Edge + return "Edge" } elseif ($roles -like "*ClientAccess*") { - return [HealthChecker.ExchangeServerRole]::ClientAccess + return "ClientAccess" } else { - return [HealthChecker.ExchangeServerRole]::None + return "None" } } diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index 3c04486fcd..ce23b3031b 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -6,53 +6,6 @@ using System; using System.Collections; namespace HealthChecker { - public class HealthCheckerExchangeServer - { - public string ServerName; //String of the server that we are working with - public object HardwareInformation; // Hardware Object Information - public object OSInformation; // OS Version Object Information - public object ExchangeInformation; //Detailed Exchange Information - public object OrganizationInformation; // Organization Information that doesn't need to be collect multiple times. - public string HealthCheckerVersion; //To determine the version of the script on the object. - public DateTime GenerationTime; //Time stamp of running the script - } - - //enum for the server roles that the computer is - public enum ExchangeServerRole - { - MultiRole, - Mailbox, - ClientAccess, - Hub, - Edge, - None - } - - //enum for the Exchange version - public enum ExchangeMajorVersion - { - Unknown, - Exchange2010, - Exchange2013, - Exchange2016, - Exchange2019 - } - // End ExchangeInformation - - //enum for the OSServerVersion that we are - public enum OSServerVersion - { - Unknown, - Windows2008, - Windows2008R2, - Windows2012, - Windows2012R2, - Windows2016, - Windows2019, - Windows2022, - WindowsCore - } - //enum for the DWORD value of the .NET frame 4 that we are on public enum NetMajorVersion { From 8d712e169b8c97ddc333fa051efe21901c126a9d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 9 Feb 2023 16:21:07 -0600 Subject: [PATCH 25/33] Fix bug in if statement for Windows2012 logic --- .../Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 index d7f0be934b..940eac8ef9 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecuritySettings.ps1 @@ -333,7 +333,7 @@ function Invoke-AnalyzerSecuritySettings { $smb1Settings = $osInformation.Smb1ServerSettings if ($osInformation.BuildInformation.BuildVersion -ge "10.0.0.0" -or - $osInformation.BuildInformation.MajorVersion -like "Windows2012*") { + $osInformation.BuildInformation.MajorVersion -eq "Windows2012R2") { $displayValue = "False" $writeType = "Green" From b29e96aeaa2dda4ece2eaf42ab60efe1b8ca3d1f Mon Sep 17 00:00:00 2001 From: David Paulson Date: Thu, 9 Feb 2023 16:22:46 -0600 Subject: [PATCH 26/33] Use array casting in what was defined as an array before in the class --- .../ExchangeInformation/Get-ExchangeInformation.ps1 | 10 +++++----- .../Get-ExchangeServerMaintenanceState.ps1 | 2 +- .../ServerInformation/Get-HardwareInformation.ps1 | 2 +- .../ServerInformation/Get-NetworkingInformation.ps1 | 2 +- .../Get-OperatingSystemInformation.ps1 | 2 +- .../ServerInformation/Get-TimeZoneInformation.ps1 | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index e5a4dda07a..2651d2527c 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -48,7 +48,7 @@ function Get-ExchangeInformation { CU = $versionInformation.CU ExchangeSetup = $exSetupDetails VersionInformation = $versionInformation - KBsInstalled = Get-ExchangeUpdates -Server $Server -ExchangeMajorVersion $versionInformation.MajorVersion + KBsInstalled = [array](Get-ExchangeUpdates -Server $Server -ExchangeMajorVersion $versionInformation.MajorVersion) } $dependentServices = (Get-ExchangeDependentServices -MachineName $Server) @@ -176,13 +176,13 @@ function Get-ExchangeInformation { GetWebServicesVirtualDirectory = $getWebServicesVirtualDirectory ExtendedProtectionConfig = $extendedProtectionConfig ExchangeConnectors = $exchangeConnectors - AMSIConfiguration = $amsiConfiguration - SerializationDataSigningConfiguration = $serializationDataSigningConfiguration - ExchangeServicesNotRunning = $exchangeServicesNotRunning + AMSIConfiguration = [array]$amsiConfiguration + SerializationDataSigningConfiguration = [array]$serializationDataSigningConfiguration + ExchangeServicesNotRunning = [array]$exchangeServicesNotRunning ApplicationPools = $applicationPools RegistryValues = $registryValues ServerMaintenance = $serverMaintenance - ExchangeCertificates = $exchangeCertificates + ExchangeCertificates = [array]$exchangeCertificates ExchangeEmergencyMitigationService = $exchangeEmergencyMitigationService ApplicationConfigFileStatus = $applicationConfigFileStatus DependentServices = $dependentServices diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 index 525394f7bb..b81236a293 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeServerMaintenanceState.ps1 @@ -71,7 +71,7 @@ function Get-ExchangeServerMaintenanceState { } end { return [PSCustomObject]@{ - InactiveComponents = $inactiveComponents + InactiveComponents = [array]$inactiveComponents GetServerComponentState = $getServerComponentState GetClusterNode = $getClusterNode } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 index 4762ec063f..0b010a78e9 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HardwareInformation.ps1 @@ -37,7 +37,7 @@ function Get-HardwareInformation { System = $system Processor = $processorInformation TotalMemory = $totalMemory - MemoryInformation = $physicalMemory + MemoryInformation = [array]$physicalMemory } } } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 index 4fdc8d5ac3..95061487df 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-NetworkingInformation.ps1 @@ -29,7 +29,7 @@ function Get-NetworkingInformation { return [PSCustomObject]@{ HttpProxy = $httpProxy PacketsReceivedDiscarded = $packetsReceivedDiscarded - NetworkAdapters = $networkAdapters + NetworkAdapters = [array]$networkAdapters IPv6DisabledOnNICs = $ipv6DisabledOnNICs } } diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 index 0bb7fa8444..d945f9dfee 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-OperatingSystemInformation.ps1 @@ -55,7 +55,7 @@ function Get-OperatingSystemInformation { TimeZone = $timeZoneInformation TLSSettings = $tlsSettings ServerBootUp = $serverBootUp - VcRedistributable = $vcRedistributable + VcRedistributable = [array]$vcRedistributable RegistryValues = $registryValues Smb1ServerSettings = $smb1ServerSettings HotFixes = $hotFixes diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 index 820ddafd45..88e3c22f1b 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-TimeZoneInformation.ps1 @@ -61,7 +61,7 @@ function Get-TimeZoneInformation { StandardStart = $standardStart DaylightStart = $daylightStart DstIssueDetected = $dstIssueDetected - ActionsToTake = $actionsToTake + ActionsToTake = [array]$actionsToTake CurrentTimeZone = $currentTimeZone } } From 44cf5270287aa4732fc5673d2d91928f5fce262d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 07:37:08 -0600 Subject: [PATCH 27/33] Fix issue within Get-ExchangeInformation --- .../ExchangeInformation/Get-ExchangeInformation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index 2651d2527c..64eddb9c8a 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -133,7 +133,7 @@ function Get-ExchangeInformation { ($getExchangeServer.IsEdgeServer -eq $false)) { Write-Verbose "SerializedDataSigning must be configured via SettingOverride" $serializationDataSigningConfiguration = Get-ExchangeSerializedDataSigningState -GetSettingOverride $PassedOrganizationInformation.SettingOverride - } elseif (($versionInformation -like "15.0.*") -and + } elseif (($versionInformation.BuildVersion -like "15.0.*") -and ($getExchangeServer.IsEdgeServer -eq $false)) { Write-Verbose "SerializedDataSigning must be configured via Registry Value" $serializationDataSigningConfiguration = $registryValues.SerializedDataSigning From 3e8f95aaaed05a79fc39eb42d2047ebe94532dfc Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 14:40:22 -0600 Subject: [PATCH 28/33] New rule to prevent Clear-Host in scripts --- .build/CodeFormatterChecks/CustomRules.psm1 | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.build/CodeFormatterChecks/CustomRules.psm1 b/.build/CodeFormatterChecks/CustomRules.psm1 index 7be50a788d..d7c8ce7373 100644 --- a/.build/CodeFormatterChecks/CustomRules.psm1 +++ b/.build/CodeFormatterChecks/CustomRules.psm1 @@ -34,3 +34,37 @@ function AvoidUsingReadHost { } } } + +function AvoidUsingClearHost { + + [CmdletBinding()] + [OutputType([PSCustomObject[]])] + param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.Language.ScriptBlockAst]$ScriptBlockAst + ) + + process { + + try { + $functions = $ScriptBlockAst.FindAll( + { + $args[0] -is [System.Management.Automation.Language.CommandAst] + }, $true ) + foreach ( $function in $functions ) { + + if (($function.GetCommandName()) -eq "Clear-Host") { + [PSCustomObject]@{ + Message = "Avoid using Clear-Host. The screen should not be cleared when running the script." + Extent = $function.Extent + RuleName = $PSCmdlet.MyInvocation.InvocationName + Severity = "Error" + } + } + } + } catch { + $PSCmdlet.ThrowTerminatingError( $_ ) + } + } +} From 3b2eba3813c0eff039825e1f634415dc466ee91d Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 14:40:57 -0600 Subject: [PATCH 29/33] Follow new rule for no Clear-Host --- Admin/Get-EASMailboxLogs.ps1 | 6 ------ Databases/VSSTester/VSSTester.ps1 | 1 - 2 files changed, 7 deletions(-) diff --git a/Admin/Get-EASMailboxLogs.ps1 b/Admin/Get-EASMailboxLogs.ps1 index c8cbf88227..57f237aba7 100644 --- a/Admin/Get-EASMailboxLogs.ps1 +++ b/Admin/Get-EASMailboxLogs.ps1 @@ -46,12 +46,6 @@ if ($null -ne $EnableVerboseLogging) { } } -Clear-Host -Write-Host "Do not close this window until you are ready to collect the logs." -ForegroundColor Black -BackgroundColor Yellow -Write-Host "Press any key to continue ..." -ForegroundColor Yellow -$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null -Clear-Host - # Convert the interval into seconds $Interval = $Interval * 60 diff --git a/Databases/VSSTester/VSSTester.ps1 b/Databases/VSSTester/VSSTester.ps1 index 4b758ca9ab..c719fc97eb 100644 --- a/Databases/VSSTester/VSSTester.ps1 +++ b/Databases/VSSTester/VSSTester.ps1 @@ -202,6 +202,5 @@ function Main { } try { - Clear-Host Main } catch { } finally { } From 56d8b94332e4f8875817f178348993d480e6c04a Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 14:18:08 -0600 Subject: [PATCH 30/33] Get-NETFrameworkVersion to find by short name --- Shared/Get-NETFrameworkVersion.ps1 | 91 +++++++++++++------ .../Tests/Get-NETFrameworkVersion.Tests.ps1 | 58 ++++++++++++ 2 files changed, 123 insertions(+), 26 deletions(-) diff --git a/Shared/Get-NETFrameworkVersion.ps1 b/Shared/Get-NETFrameworkVersion.ps1 index 3101f5b354..3e4ddee5a5 100644 --- a/Shared/Get-NETFrameworkVersion.ps1 +++ b/Shared/Get-NETFrameworkVersion.ps1 @@ -4,60 +4,76 @@ . $PSScriptRoot\Get-RemoteRegistryValue.ps1 function Get-NETFrameworkVersion { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = "CollectFromServer")] param( + [Parameter(ParameterSetName = "CollectFromServer", Position = 1)] [string]$MachineName = $env:COMPUTERNAME, + + [Parameter(ParameterSetName = "NetKey")] [int]$NetVersionKey = -1, + + [Parameter(ParameterSetName = "NetName")] + [ValidateScript({ ValidateNetNameParameter $_ })] + [string]$NetVersionShortName, + [ScriptBlock]$CatchActionFunction ) begin { Write-Verbose "Calling: $($MyInvocation.MyCommand)" $friendlyName = [string]::Empty $minValue = -1 + $netVersionDictionary = GetNetVersionDictionary + + if ($PSCmdlet.ParameterSetName -eq "NetName") { + $NetVersionKey = $netVersionDictionary[$NetVersionShortName] + } } process { if ($NetVersionKey -eq -1) { - [int]$NetVersionKey = Get-RemoteRegistryValue -MachineName $MachineName ` - -SubKey "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" ` - -GetValue "Release" ` - -CatchActionFunction $CatchActionFunction + $params = @{ + MachineName = $MachineName + SubKey = "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" + GetValue = "Release" + CatchActionFunction = $CatchActionFunction + } + [int]$NetVersionKey = Get-RemoteRegistryValue @params } #Using Minimum Version as per https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed?redirectedfrom=MSDN#minimum-version - if ($NetVersionKey -lt 378389) { + if ($NetVersionKey -lt $netVersionDictionary["Net4d5"]) { $friendlyName = "Unknown" $minValue = -1 - } elseif ($NetVersionKey -lt 378675) { + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d5d1"]) { $friendlyName = "4.5" - $minValue = 378389 - } elseif ($NetVersionKey -lt 379893) { + $minValue = $netVersionDictionary["Net4d5"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d5d2"]) { $friendlyName = "4.5.1" - $minValue = 378675 - } elseif ($NetVersionKey -lt 393295) { + $minValue = $netVersionDictionary["Net4d5d1"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d6"]) { $friendlyName = "4.5.2" - $minValue = 379893 - } elseif ($NetVersionKey -lt 394254) { + $minValue = $netVersionDictionary["Net4d5d2"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d6d1"]) { $friendlyName = "4.6" - $minValue = 393295 - } elseif ($NetVersionKey -lt 394802) { + $minValue = $netVersionDictionary["Net4d6"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d6d2"]) { $friendlyName = "4.6.1" - $minValue = 394254 - } elseif ($NetVersionKey -lt 460798) { + $minValue = $netVersionDictionary["Net4d6d1"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d7"]) { $friendlyName = "4.6.2" - $minValue = 394802 - } elseif ($NetVersionKey -lt 461308) { + $minValue = $netVersionDictionary["Net4d6d2"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d7d1"]) { $friendlyName = "4.7" - $minValue = 460798 - } elseif ($NetVersionKey -lt 461808) { + $minValue = $netVersionDictionary["Net4d7"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d7d2"]) { $friendlyName = "4.7.1" - $minValue = 461308 - } elseif ($NetVersionKey -lt 528040) { + $minValue = $netVersionDictionary["Net4d7d1"] + } elseif ($NetVersionKey -lt $netVersionDictionary["Net4d8"]) { $friendlyName = "4.7.2" - $minValue = 461808 - } elseif ($NetVersionKey -ge 528040) { + $minValue = $netVersionDictionary["Net4d7d2"] + } elseif ($NetVersionKey -ge $netVersionDictionary["Net4d8"]) { $friendlyName = "4.8" - $minValue = 528040 + $minValue = $netVersionDictionary["Net4d8"] } } end { @@ -69,3 +85,26 @@ function Get-NETFrameworkVersion { } } } + +function GetNetVersionDictionary { + return @{ + "Net4d5" = 378389 + "Net4d5d1" = 378675 + "Net4d5d2" = 379893 + "Net4d5d2wFix" = 380035 + "Net4d6" = 393295 + "Net4d6d1" = 394254 + "Net4d6d1wFix" = 394294 + "Net4d6d2" = 394802 + "Net4d7" = 460798 + "Net4d7d1" = 461308 + "Net4d7d2" = 461808 + "Net4d8" = 528040 + } +} + +function ValidateNetNameParameter { + param($name) + $netVersionNames = @((GetNetVersionDictionary).Keys) + $netVersionNames.Contains($name) +} diff --git a/Shared/Tests/Get-NETFrameworkVersion.Tests.ps1 b/Shared/Tests/Get-NETFrameworkVersion.Tests.ps1 index f6c52841d8..abd3c57b95 100644 --- a/Shared/Tests/Get-NETFrameworkVersion.Tests.ps1 +++ b/Shared/Tests/Get-NETFrameworkVersion.Tests.ps1 @@ -132,4 +132,62 @@ Describe "Testing $scriptName" { Assert-MockCalled -CommandName Write-Host -Exactly 1 -ParameterFilter { $Object -eq "Write-CustomScriptBlock" } } } + + Context "Test By Name Results" { + + It "NET 4.5" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d5" + $result.FriendlyName = "4.5" + } + + It "NET 4.5.1" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d5d1" + $result.FriendlyName = "4.5.1" + } + + It "NET 4.5.2" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d5d2" + $result.FriendlyName = "4.5.2" + } + + It "NET 4.6" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d6" + $result.FriendlyName = "4.6" + } + + It "NET 4.6" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d6" + $result.FriendlyName = "4.6" + } + + It "NET 4.6.1" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d6d1" + $result.FriendlyName = "4.6.1" + } + + It "NET 4.6.2" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d6d2" + $result.FriendlyName = "4.6.2" + } + + It "NET 4.7" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d7" + $result.FriendlyName = "4.7" + } + + It "NET 4.7.1" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d7d1" + $result.FriendlyName = "4.7.1" + } + + It "NET 4.7.2" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d7d2" + $result.FriendlyName = "4.7.2" + } + + It "NET 4.8" { + $result = Get-NETFrameworkVersion -NetVersionShortName "Net4d8" + $result.FriendlyName = "4.8" + } + } } From a6373f1566d939923bac4d88f8b751e2651d2b45 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 15:15:04 -0600 Subject: [PATCH 31/33] Removed NetMajorVersion from HC class --- .../Analyzer/Invoke-AnalyzerOsInformation.ps1 | 15 ++++++++------- .../Invoke-AnalyzerSecurityCve-2020-1147.ps1 | 2 +- Diagnostics/HealthChecker/Helpers/Class.ps1 | 19 ------------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 index 384e9dcd49..2794b3a652 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 @@ -101,31 +101,32 @@ function Invoke-AnalyzerOsInformation { $ex2013 = "Exchange2013" $osVersion = $osInformation.BuildInformation.MajorVersion $recommendedNetVersion = $null + $netVersionDictionary = GetNetVersionDictionary Write-Verbose "Checking $($exchangeInformation.BuildInformation.MajorVersion) .NET Framework Support Versions" if ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU4")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5 + $recommendedNetVersion = $netVersionDictionary["Net4d5"] } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU13") -or (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU2")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d5d2wFix + $recommendedNetVersion = $netVersionDictionary["Net4d5d2wFix"] } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU15") -or (Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU2") -or ((Test-ExchangeBuildEqualBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU3") -and $osVersion -ne "Windows2016")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d1wFix + $recommendedNetVersion = $netVersionDictionary["Net4d6d1wFix"] } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU19") -or (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU8")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d6d2 + $recommendedNetVersion = $netVersionDictionary["Net4d6d2"] } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU21") -or (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU11")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d1 + $recommendedNetVersion = $netVersionDictionary["Net4d7d1"] } elseif ((Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2013 -CU "CU21") -or (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2016 -CU "CU13") -or (Test-ExchangeBuildLessThanBuild -CurrentExchangeBuild $currentExchangeBuild -Version $ex2019 -CU "CU2")) { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d7d2 + $recommendedNetVersion = $netVersionDictionary["Net4d7d2"] } else { - $recommendedNetVersion = [HealthChecker.NetMajorVersion]::Net4d8 + $recommendedNetVersion = $netVersionDictionary["Net4d8"] } Write-Verbose "Recommended NET Version: $recommendedNetVersion" diff --git a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 index 1ddbee73f3..df27812e3b 100644 --- a/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCve-2020-1147.ps1 @@ -23,7 +23,7 @@ function Invoke-AnalyzerSecurityCve-2020-1147 { #Workaround: N/A $dllFileBuildPartToCheckAgainst = 3630 - if ($SecurityObject.OsInformation.NETFramework.MajorVersion -eq [HealthChecker.NetMajorVersion]::Net4d8) { + if ($SecurityObject.OsInformation.NETFramework.MajorVersion -eq ((GetNetVersionDictionary)["Net4d8"])) { $dllFileBuildPartToCheckAgainst = 4190 } diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index ce23b3031b..b1f3c21085 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -6,25 +6,6 @@ using System; using System.Collections; namespace HealthChecker { - //enum for the DWORD value of the .NET frame 4 that we are on - public enum NetMajorVersion - { - Unknown = 0, - Net4d5 = 378389, - Net4d5d1 = 378675, - Net4d5d2 = 379893, - Net4d5d2wFix = 380035, - Net4d6 = 393295, - Net4d6d1 = 394254, - Net4d6d1wFix = 394294, - Net4d6d2 = 394802, - Net4d7 = 460798, - Net4d7d1 = 461308, - Net4d7d2 = 461808, - Net4d8 = 528040 - } - // End OperatingSystemInformation - //enum for the type of computer that we are public enum ServerType { From 1cc7ab73babf9cb3d364323dc592f1d96e3d8e55 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 15:23:00 -0600 Subject: [PATCH 32/33] Removed ServerType from HC class --- .../HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 | 4 ++-- .../Analyzer/Invoke-AnalyzerHardwareInformation.ps1 | 10 +++++----- .../Analyzer/Invoke-AnalyzerNicSettings.ps1 | 10 +++++----- Diagnostics/HealthChecker/Helpers/Class.ps1 | 10 ---------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 index c8d0c56e83..74e410f178 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 @@ -56,8 +56,8 @@ For further details, please review the virtualization recommendations on Microso "@ - if ($HealthServerObject.HardwareInformation.ServerType -eq [HealthChecker.ServerType]::VMWare -or - $HealthServerObject.HardwareInformation.ServerType -eq [HealthChecker.ServerType]::HyperV) { + if ($HealthServerObject.HardwareInformation.ServerType -eq "VMWare" -or + $HealthServerObject.HardwareInformation.ServerType -eq "HyperV") { $params = $baseParams + @{ Details = $VirtualizationWarning DisplayWriteType = "Yellow" diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 index 30843f77d9..c8432587d9 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerHardwareInformation.ps1 @@ -34,8 +34,8 @@ function Invoke-AnalyzerHardwareInformation { } Add-AnalyzedResultInformation @params - if ($hardwareInformation.ServerType -eq [HealthChecker.ServerType]::Physical -or - $hardwareInformation.ServerType -eq [HealthChecker.ServerType]::AmazonEC2) { + if ($hardwareInformation.ServerType -eq "Physical" -or + $hardwareInformation.ServerType -eq "AmazonEC2") { $params = $baseParams + @{ Name = "Manufacturer" Details = $hardwareInformation.Manufacturer @@ -59,7 +59,7 @@ function Invoke-AnalyzerHardwareInformation { $displayWriteType = "Green" $displayValue = $numberOfProcessors - if ($hardwareInformation.ServerType -ne [HealthChecker.ServerType]::Physical) { + if ($hardwareInformation.ServerType -ne "Physical") { $displayWriteType = "Grey" } elseif ($numberOfProcessors -gt 2) { $displayWriteType = "Red" @@ -118,7 +118,7 @@ function Invoke-AnalyzerHardwareInformation { if ($logicalValue -gt $physicalValue) { - if ($hardwareInformation.ServerType -ne [HealthChecker.ServerType]::HyperV) { + if ($hardwareInformation.ServerType -ne "HyperV") { $displayValue = "Enabled --- Error: Having Hyper-Threading enabled goes against best practices and can cause performance issues. Please disable as soon as possible." $displayTestingValue = $true $displayWriteType = "Red" @@ -128,7 +128,7 @@ function Invoke-AnalyzerHardwareInformation { $displayWriteType = "Grey" } - if ($hardwareInformation.ServerType -eq [HealthChecker.ServerType]::AmazonEC2) { + if ($hardwareInformation.ServerType -eq "AmazonEC2") { $additionalDisplayValue = "Error: For high-performance computing (HPC) application, like Exchange, Amazon recommends that you have Hyper-Threading Technology disabled in their service. More information: https://aka.ms/HC-EC2HyperThreading" } diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 index ce114c746c..75cad40b19 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerNicSettings.ps1 @@ -45,8 +45,8 @@ function Invoke-AnalyzerNicSettings { $driverDate = $adapter.DriverDate $detailsValue = $driverDate - if ($hardwareInformation.ServerType -eq [HealthChecker.ServerType]::Physical -or - $hardwareInformation.ServerType -eq [HealthChecker.ServerType]::AmazonEC2) { + if ($hardwareInformation.ServerType -eq "Physical" -or + $hardwareInformation.ServerType -eq "AmazonEC2") { if ($null -eq $driverDate -or $driverDate -eq [DateTime]::MaxValue) { @@ -125,8 +125,8 @@ function Invoke-AnalyzerNicSettings { $linkSpeed = $adapter.LinkSpeed $displayValue = "{0} --- This may not be accurate due to virtualized hardware" -f $linkSpeed - if ($hardwareInformation.ServerType -eq [HealthChecker.ServerType]::Physical -or - $hardwareInformation.ServerType -eq [HealthChecker.ServerType]::AmazonEC2) { + if ($hardwareInformation.ServerType -eq "Physical" -or + $hardwareInformation.ServerType -eq "AmazonEC2") { $displayValue = $linkSpeed } @@ -203,7 +203,7 @@ function Invoke-AnalyzerNicSettings { Add-AnalyzedResultInformation @params #Assuming that all versions of Hyper-V doesn't allow sleepy NICs - if (($hardwareInformation.ServerType -ne [HealthChecker.ServerType]::HyperV) -and ($adapter.PnPCapabilities -ne "MultiplexorNoPnP")) { + if (($hardwareInformation.ServerType -ne "HyperV") -and ($adapter.PnPCapabilities -ne "MultiplexorNoPnP")) { $displayWriteType = "Grey" $displayValue = $adapter.SleepyNicDisabled diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 index b1f3c21085..d593acf8ba 100644 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ b/Diagnostics/HealthChecker/Helpers/Class.ps1 @@ -6,16 +6,6 @@ using System; using System.Collections; namespace HealthChecker { - //enum for the type of computer that we are - public enum ServerType - { - VMWare, - AmazonEC2, - HyperV, - Physical, - Unknown - } - //HTML & display classes public class HtmlServerValues { From ba9e4ffb71a402087386fcfa086cfa5e9cbbac63 Mon Sep 17 00:00:00 2001 From: David Paulson Date: Fri, 10 Feb 2023 15:53:56 -0600 Subject: [PATCH 33/33] Removed last of class from HC --- .../Add-AnalyzedResultInformation.ps1 | 31 +++++-- .../Get-DisplayResultsGroupingKey.ps1 | 12 +-- .../Analyzer/Invoke-AnalyzerEngine.ps1 | 7 +- .../Get-FIPFSScanEngineVersionState.Tests.ps1 | 1 - Diagnostics/HealthChecker/HealthChecker.ps1 | 1 - Diagnostics/HealthChecker/Helpers/Class.ps1 | 85 ------------------- ...thCheckerTests.ImportCode.NotPublished.ps1 | 1 - .../Writers/Write-ResultsToScreen.ps1 | 8 +- 8 files changed, 42 insertions(+), 104 deletions(-) delete mode 100644 Diagnostics/HealthChecker/Helpers/Class.ps1 diff --git a/Diagnostics/HealthChecker/Analyzer/Add-AnalyzedResultInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Add-AnalyzedResultInformation.ps1 index 5643e71072..7df5d9d244 100644 --- a/Diagnostics/HealthChecker/Analyzer/Add-AnalyzedResultInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Add-AnalyzedResultInformation.ps1 @@ -6,7 +6,7 @@ function Add-AnalyzedResultInformation { param( # Main object that we are manipulating and adding entries to [Parameter(Mandatory = $true, ValueFromPipeline = $true)] - [HealthChecker.AnalyzedInformation]$AnalyzedInformation, + [object]$AnalyzedInformation, # The value of the display entry [object]$Details, @@ -92,11 +92,21 @@ function Add-AnalyzedResultInformation { if ($AddDisplayResultsLineInfo) { if (!($AnalyzedInformation.DisplayResults.ContainsKey($DisplayGroupingKey))) { Write-Verbose "Adding Display Grouping Key: $($DisplayGroupingKey.Name)" - [System.Collections.Generic.List[HealthChecker.DisplayResultsLineInfo]]$list = New-Object System.Collections.Generic.List[HealthChecker.DisplayResultsLineInfo] + [System.Collections.Generic.List[object]]$list = New-Object System.Collections.Generic.List[object] $AnalyzedInformation.DisplayResults.Add($DisplayGroupingKey, $list) } - $lineInfo = New-Object HealthChecker.DisplayResultsLineInfo + $lineInfo = [PSCustomObject]@{ + DisplayValue = [string]::Empty + Name = [string]::Empty + TestingName = [string]::Empty # Used for pestering testing + CustomName = [string]::Empty # Used for security vulnerability + TabNumber = 0 + TestingValue = $null # Used for pester testing down the road + CustomValue = $null # Used for security vulnerability + OutColumns = $null # Used for colorized format table option + WriteType = [string]::Empty + } if ($null -ne $OutColumns) { $lineInfo.OutColumns = $OutColumns @@ -148,13 +158,20 @@ function Add-AnalyzedResultInformation { $AnalyzedInformation.DisplayResults[$DisplayGroupingKey].Add($lineInfo) } + $htmlDetailRow = [PSCustomObject]@{ + Name = [string]::Empty + DetailValue = [string]::Empty + TableValue = $null + Class = [string]::Empty + } + if ($AddHtmlDetailRow) { if (!($analyzedResults.HtmlServerValues.ContainsKey("ServerDetails"))) { - [System.Collections.Generic.List[HealthChecker.HtmlServerInformationRow]]$list = New-Object System.Collections.Generic.List[HealthChecker.HtmlServerInformationRow] + [System.Collections.Generic.List[object]]$list = New-Object System.Collections.Generic.List[object] $AnalyzedInformation.HtmlServerValues.Add("ServerDetails", $list) } - $detailRow = New-Object HealthChecker.HtmlServerInformationRow + $detailRow = $htmlDetailRow if ($displayWriteType -ne "Grey") { $detailRow.Class = $displayWriteType @@ -179,11 +196,11 @@ function Add-AnalyzedResultInformation { if ($AddHtmlOverviewValues) { if (!($analyzedResults.HtmlServerValues.ContainsKey("OverviewValues"))) { - [System.Collections.Generic.List[HealthChecker.HtmlServerInformationRow]]$list = New-Object System.Collections.Generic.List[HealthChecker.HtmlServerInformationRow] + [System.Collections.Generic.List[object]]$list = New-Object System.Collections.Generic.List[object] $AnalyzedInformation.HtmlServerValues.Add("OverviewValues", $list) } - $overviewValue = New-Object HealthChecker.HtmlServerInformationRow + $overviewValue = $htmlDetailRow if ($displayWriteType -ne "Grey") { $overviewValue.Class = $displayWriteType diff --git a/Diagnostics/HealthChecker/Analyzer/Get-DisplayResultsGroupingKey.ps1 b/Diagnostics/HealthChecker/Analyzer/Get-DisplayResultsGroupingKey.ps1 index d072493114..55b85d3a29 100644 --- a/Diagnostics/HealthChecker/Analyzer/Get-DisplayResultsGroupingKey.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Get-DisplayResultsGroupingKey.ps1 @@ -8,10 +8,10 @@ function Get-DisplayResultsGroupingKey { [int]$DisplayOrder, [int]$DefaultTabNumber = 1 ) - $obj = New-Object HealthChecker.DisplayResultsGroupingKey - $obj.Name = $Name - $obj.DisplayGroupName = $DisplayGroupName - $obj.DisplayOrder = $DisplayOrder - $obj.DefaultTabNumber = $DefaultTabNumber - return $obj + return [PSCustomObject]@{ + Name = $Name + DisplayGroupName = $DisplayGroupName + DisplayOrder = $DisplayOrder + DefaultTabNumber = $DefaultTabNumber + } } diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 index 74e410f178..c1c34084e5 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerEngine.ps1 @@ -21,8 +21,11 @@ function Invoke-AnalyzerEngine { ) Write-Verbose "Calling: $($MyInvocation.MyCommand)" - $analyzedResults = New-Object HealthChecker.AnalyzedInformation - $analyzedResults.HealthCheckerExchangeServer = $HealthServerObject + $analyzedResults = [PSCustomObject]@{ + HealthCheckerExchangeServer = $HealthServerObject + HtmlServerValues = @{} + DisplayResults = @{} + } #Display Grouping Keys $order = 1 diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 index 1a06498248..f929b01d5b 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Tests/Get-FIPFSScanEngineVersionState.Tests.ps1 @@ -8,7 +8,6 @@ param() BeforeAll { $Script:parentPath = (Split-Path -Parent $PSScriptRoot) $Script:Server = $env:COMPUTERNAME - . $Script:parentPath\..\..\Helpers\Class.ps1 . $Script:parentPath\Get-FIPFSScanEngineVersionState.ps1 function Invoke-CatchActions { diff --git a/Diagnostics/HealthChecker/HealthChecker.ps1 b/Diagnostics/HealthChecker/HealthChecker.ps1 index f55a04d355..83b7668745 100644 --- a/Diagnostics/HealthChecker/HealthChecker.ps1 +++ b/Diagnostics/HealthChecker/HealthChecker.ps1 @@ -158,7 +158,6 @@ begin { . $PSScriptRoot\Helpers\Get-ExportedHealthCheckerFiles.ps1 . $PSScriptRoot\Helpers\Invoke-ConfirmExchangeShell.ps1 . $PSScriptRoot\Helpers\Invoke-SetOutputInstanceLocation.ps1 - . $PSScriptRoot\Helpers\Class.ps1 . $PSScriptRoot\Writers\Write-ResultsToScreen.ps1 . $PSScriptRoot\Writers\Write-Functions.ps1 . $PSScriptRoot\Features\Get-HtmlServerReport.ps1 diff --git a/Diagnostics/HealthChecker/Helpers/Class.ps1 b/Diagnostics/HealthChecker/Helpers/Class.ps1 deleted file mode 100644 index d593acf8ba..0000000000 --- a/Diagnostics/HealthChecker/Helpers/Class.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -$healthCheckerCustomClass = @" -using System; -using System.Collections; - namespace HealthChecker - { - //HTML & display classes - public class HtmlServerValues - { - public System.Array OverviewValues; - public System.Array ActionItems; //use HtmlServerActionItemRow - public System.Array ServerDetails; // use HtmlServerInformationRow - } - - public class HtmlServerActionItemRow - { - public string Setting; - public string DetailValue; - public string RecommendedDetails; - public string MoreInformation; - public string Class; - } - - public class HtmlServerInformationRow - { - public string Name; - public string DetailValue; - public object TableValue; - public string Class; - } - - public class DisplayResultsLineInfo - { - public string DisplayValue; - public string Name; - public string TestingName; // Used for pestering testing - public string CustomName; // Used for security vulnerability - public int TabNumber; - public object TestingValue; //Used for pester testing down the road. - public object CustomValue; // Used for security vulnerability - public object OutColumns; //used for colorized format table option. - public string WriteType; - - public string Line - { - get - { - if (String.IsNullOrEmpty(this.Name)) - { - return this.DisplayValue; - } - - return String.Concat(this.Name, ": ", this.DisplayValue); - } - } - } - - public class DisplayResultsGroupingKey - { - public string Name; - public int DefaultTabNumber; - public bool DisplayGroupName; - public int DisplayOrder; - } - - public class AnalyzedInformation - { - public object HealthCheckerExchangeServer; - public Hashtable HtmlServerValues = new Hashtable(); - public Hashtable DisplayResults = new Hashtable(); - } - } -"@ - -try { - #Enums and custom data types - if (-not($ScriptUpdateOnly)) { - Add-Type -TypeDefinition $healthCheckerCustomClass -ErrorAction Stop - } -} catch { - Write-Warning "There was an error trying to add custom classes to the current PowerShell session. You need to close this session and open a new one to have the script properly work." - exit -} diff --git a/Diagnostics/HealthChecker/Tests/HealthCheckerTests.ImportCode.NotPublished.ps1 b/Diagnostics/HealthChecker/Tests/HealthCheckerTests.ImportCode.NotPublished.ps1 index 5d0103ad74..8da6ad8f46 100644 --- a/Diagnostics/HealthChecker/Tests/HealthCheckerTests.ImportCode.NotPublished.ps1 +++ b/Diagnostics/HealthChecker/Tests/HealthCheckerTests.ImportCode.NotPublished.ps1 @@ -7,7 +7,6 @@ [CmdletBinding()] param() $Script:parentPath = (Split-Path -Parent $PSScriptRoot) -. $PSScriptRoot\..\Helpers\Class.ps1 . $PSScriptRoot\..\..\..\Shared\PesterLoadFunctions.NotPublished.ps1 . $PSScriptRoot\..\..\..\.build\Load-Module.ps1 diff --git a/Diagnostics/HealthChecker/Writers/Write-ResultsToScreen.ps1 b/Diagnostics/HealthChecker/Writers/Write-ResultsToScreen.ps1 index f6dc712672..4ed3ec0fac 100644 --- a/Diagnostics/HealthChecker/Writers/Write-ResultsToScreen.ps1 +++ b/Diagnostics/HealthChecker/Writers/Write-ResultsToScreen.ps1 @@ -34,7 +34,13 @@ function Write-ResultsToScreen { 1..($line.TabNumber) | ForEach-Object { $tab = $tab + "`t" } } - $writeValue = "{0}{1}" -f $tab, $line.Line + if ([string]::IsNullOrEmpty($line.Name)) { + $displayLine = $line.DisplayValue + } else { + $displayLine = [string]::Concat($line.Name, ": ", $line.DisplayValue) + } + + $writeValue = "{0}{1}" -f $tab, $displayLine switch ($line.WriteType) { "Grey" { Write-Grey($writeValue) } "Yellow" { Write-Yellow($writeValue) }