diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index f625d9ceac..b1162a0225 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -23,6 +23,8 @@ function Invoke-AnalyzerExchangeInformation { $hardwareInformation = $HealthServerObject.HardwareInformation $getWebServicesVirtualDirectory = $exchangeInformation.VirtualDirectories.GetWebServicesVirtualDirectory | Where-Object { $_.Name -eq "EWS (Default Web Site)" } + $getWebServicesVirtualDirectoryBE = $exchangeInformation.VirtualDirectories.GetWebServicesVirtualDirectory | + Where-Object { $_.Name -eq "EWS (Exchange Back End)" } $baseParams = @{ AnalyzedInformation = $AnalyzeResults @@ -299,12 +301,31 @@ function Invoke-AnalyzerExchangeInformation { if (-not ([string]::IsNullOrWhiteSpace($getWebServicesVirtualDirectory.InternalNLBBypassUrl))) { $params = $baseParams + @{ Name = "EWS Internal Bypass URL Set" - Details = "$($getWebServicesVirtualDirectory.InternalNLBBypassUrl) - Can cause issues after KB 5001779" + Details = "$($getWebServicesVirtualDirectory.InternalNLBBypassUrl) - Can cause issues after KB 5001779" + + "`r`n`t`tThe Web Services Virtual Directory has a value set for InternalNLBBypassUrl which can cause problems with Exchange." + + "`r`n`t`tSet the InternalNLBBypassUrl to NULL to correct this." DisplayWriteType = "Red" } Add-AnalyzedResultInformation @params } + if ($null -ne $getWebServicesVirtualDirectoryBE -and + $null -ne $getWebServicesVirtualDirectoryBE.InternalNLBBypassUrl) { + Write-Verbose "Checking EWS Internal NLB Bypass URL for the BE" + $expectedValue = "https://$($exchangeInformation.GetExchangeServer.Fqdn.ToString()):444/ews/exchange.asmx" + + if ($getWebServicesVirtualDirectoryBE.InternalNLBBypassUrl.ToString() -ne $expectedValue) { + $params = $baseParams + @{ + Name = "EWS Internal Bypass URL Incorrectly Set on BE" + Details = "Error: '$expectedValue' is the expected value for this." + + "`r`n`t`tAnything other than the expected value, will result in connectivity issues." + DisplayWriteType = "Red" + } + + Add-AnalyzedResultInformation @params + } + } + Write-Verbose "Working on results from Test-ServiceHealth" $servicesNotRunning = $exchangeInformation.ExchangeServicesNotRunning diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 index a6dfcd7286..11ad4b3b62 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1 @@ -112,12 +112,13 @@ function Invoke-AnalyzerIISInformation { $sbStarted = { param($o, $p) if ($p -eq "State") { if ($o."$p" -eq "Started") { "Green" } else { "Red" } } } $params = $baseParams + @{ - OutColumns = ([PSCustomObject]@{ + OutColumns = ([PSCustomObject]@{ DisplayObject = $outputObjectDisplayValue ColorizerFunctions = @($sbStarted) IndentSpaces = 8 }) - AddHtmlDetailRow = $false + OutColumnsColorTests = @($sbStarted) + HtmlName = "IIS Sites Information" } Add-AnalyzedResultInformation @params @@ -270,12 +271,13 @@ function Invoke-AnalyzerIISInformation { $sbRestart = { param($o, $p) if ($p -eq "RestartConditionSet") { if ($o."$p") { "Red" } else { "Green" } } } $params = $baseParams + @{ - OutColumns = ([PSCustomObject]@{ + OutColumns = ([PSCustomObject]@{ DisplayObject = $outputObjectDisplayValue ColorizerFunctions = @($sbStarted, $sbRestart) IndentSpaces = 8 }) - AddHtmlDetailRow = $false + OutColumnsColorTests = @($sbStarted, $sbRestart) + HtmlName = "Application Pool Information" } Add-AnalyzedResultInformation @params @@ -319,19 +321,19 @@ function Invoke-AnalyzerIISInformation { } $params = $baseParams + @{ - OutColumns = ([PSCustomObject]@{ + OutColumns = ([PSCustomObject]@{ DisplayObject = $outputObjectDisplayValue ColorizerFunctions = @($sbColorizer) IndentSpaces = 8 }) - AddHtmlDetailRow = $false + OutColumnsColorTests = @($sbColorizer) + HtmlName = "Application Pools Restarts" } Add-AnalyzedResultInformation @params $params = $baseParams + @{ Details = "Error: The above app pools currently have the periodic restarts set. This restart will cause disruption to end users." DisplayWriteType = "Red" - AddHtmlDetailRow = $false } Add-AnalyzedResultInformation @params } @@ -429,11 +431,11 @@ function Invoke-AnalyzerIISInformation { } $params = $baseParams + @{ - OutColumns = ([PSCustomObject]@{ + OutColumns = ([PSCustomObject]@{ DisplayObject = $iisVirtualDirectoriesDisplay IndentSpaces = 8 }) - AddHtmlDetailRow = $false + HtmlName = "Virtual Directory Locations" } Add-AnalyzedResultInformation @params @@ -492,7 +494,9 @@ function Invoke-AnalyzerIISInformation { # Use 'DisplayKey' for the display results. $alreadyDisplayedUrlRewriteRules = @{} $alreadyDisplayedUrlKey = "DisplayKey" + $urlMatchProblem = "UrlMatchProblem" $alreadyDisplayedUrlRewriteRules.Add($alreadyDisplayedUrlKey, (New-Object System.Collections.Generic.List[object])) + $alreadyDisplayedUrlRewriteRules.Add($urlMatchProblem, (New-Object System.Collections.Generic.List[string])) foreach ($key in $urlRewriteRules.Keys) { $currentSection = $urlRewriteRules[$key] @@ -511,6 +515,7 @@ function Invoke-AnalyzerIISInformation { #multiple match type possibilities, but should only be one per rule. $propertyType = ($rule.match | Get-Member | Where-Object { $_.MemberType -eq "Property" }).Name + $isUrlMatchProblem = $propertyType -eq "url" -and $rule.match.$propertyType -eq "*" $matchProperty = "$propertyType - $($rule.match.$propertyType)" $displayObject = [PSCustomObject]@{ @@ -524,6 +529,10 @@ function Invoke-AnalyzerIISInformation { if (-not ($alreadyDisplayedUrlRewriteRules.ContainsKey((($displayObject.RewriteRuleName))))) { $alreadyDisplayedUrlRewriteRules.Add($displayObject.RewriteRuleName, $displayObject) $alreadyDisplayedUrlRewriteRules[$alreadyDisplayedUrlKey].Add($displayObject) + + if ($isUrlMatchProblem) { + $alreadyDisplayedUrlRewriteRules[$urlMatchProblem].Add($rule.Name) + } } } } @@ -538,6 +547,18 @@ function Invoke-AnalyzerIISInformation { AddHtmlDetailRow = $false } Add-AnalyzedResultInformation @params + + if ($alreadyDisplayedUrlRewriteRules[$urlMatchProblem].Count -gt 0) { + $params = $baseParams + @{ + Name = "Misconfigured URL Rewrite Rule - URL Match Problem Rules" + Details = "$([string]::Join(",", $alreadyDisplayedUrlRewriteRules[$urlMatchProblem]))" + + "`r`n`t`tURL Match is set only a wild card which will result in a HTTP 500." + + "`r`n`t`tIf the rule is required, the URL match should be '.*' to avoid issues." + DisplayWriteType = "Red" + } + + Add-AnalyzedResultInformation @params + } } if ($null -ne $missingWebApplicationConfigFile) { diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 index e49fd53613..2b9f3680d0 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1 @@ -332,7 +332,9 @@ function Invoke-AnalyzerOsInformation { if (($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne "None") -and ($exchangeInformation.GetExchangeServer.IsEdgeServer -eq $false) -and - ($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne $exchangeInformation.GetExchangeServer.InternetWebProxy.Authority)) { + ($null -ne $exchangeInformation.GetExchangeServer.InternetWebProxy) -and + ($osInformation.NetworkInformation.HttpProxy.ProxyAddress -ne + "$($exchangeInformation.GetExchangeServer.InternetWebProxy.Host):$($exchangeInformation.GetExchangeServer.InternetWebProxy.Port)")) { $params = $baseParams + @{ Details = "Error: Exchange Internet Web Proxy doesn't match OS Web Proxy." DisplayWriteType = "Red" diff --git a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HttpProxySetting.ps1 b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HttpProxySetting.ps1 index a6be0ee705..02cabbae95 100644 --- a/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HttpProxySetting.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ServerInformation/Get-HttpProxySetting.ps1 @@ -15,25 +15,28 @@ function Get-HttpProxySetting { [Parameter(Mandatory = $true)][string]$RegistryLocation ) $connections = Get-ItemProperty -Path $RegistryLocation + $byteLength = 4 + $proxyStartLocation = 16 + $proxyLength = 0 $proxyAddress = [string]::Empty $byPassList = [string]::Empty if (($null -ne $connections) -and ($Connections | Get-Member).Name -contains "WinHttpSettings") { - $onProxy = $true + try { + $bytes = $Connections.WinHttpSettings + $proxyLength = [System.BitConverter]::ToInt32($bytes, $proxyStartLocation - $byteLength) - foreach ($Byte in $Connections.WinHttpSettings) { - if ($onProxy -and - $Byte -ge 42) { - $proxyAddress += [CHAR]$Byte - } elseif (-not $onProxy -and - $Byte -ge 42) { - $byPassList += [CHAR]$Byte - } elseif (-not ([string]::IsNullOrEmpty($proxyAddress)) -and - $onProxy -and - $Byte -eq 0) { - $onProxy = $false + if ($proxyLength -gt 0) { + $proxyAddress = [System.Text.Encoding]::UTF8.GetString($bytes, $proxyStartLocation, $proxyLength) + $byPassListLength = [System.BitConverter]::ToInt32($bytes, $proxyStartLocation + $proxyLength) + + if ($byPassListLength -gt 0) { + $byPassList = [System.Text.Encoding]::UTF8.GetString($bytes, $byteLength + $proxyStartLocation + $proxyLength, $byPassListLength) + } } + } catch { + Write-Verbose "Failed to properly get HTTP Proxy information. Inner Exception: $_" } } diff --git a/docs/Diagnostics/HealthChecker/IISInformation.md b/docs/Diagnostics/HealthChecker/IISInformation.md new file mode 100644 index 0000000000..d1640e61a6 --- /dev/null +++ b/docs/Diagnostics/HealthChecker/IISInformation.md @@ -0,0 +1,40 @@ +# Exchange IIS Information + +## Description + +We show some general information about your Exchange Server from the IIS perspective. This goes into detail to make sure that Sites and App Pools are started, which might not be easy to spot at a quick look a the server. It will also call out some common misconfiguration issues, that will cause problems with client connectivity. + + +## Sites + +This provides the sites that we found and the following information: + +- State (Started or Stopped) +- HSTS Enabled (Only supported on `Default Web Site`) +- Protocol - Binding - Certificate ( Which protocol is binding to which port and with what certificate if any) + +**NOTE:** HSTS if enabled on the Back End will call out an issue. + +## App Pools + +This provides the application pools on the server with the following information: + +- State (Started or Stopped) +- GCServerEnabled (Garbage Collection Server Enabled - Depends on the RAM on the server if this should be enabled or not on the server. If it should be, Health Checker should call it out.) +- RestartConditionSet ( If there is an IIS setting that will automatically restart the App Pool. This is not recommended and will cause issues with client connectivity ) + +## Virtual Directory Locations + +This provides the different locations that you use for different connection endpoints with the following information: + +- Extended Protection ( The current value ) +- Ssl Flags ( If enabled and/or Cert based ) +- IP Filtering Enabled ( If any IP filtering is enabled ) +- URL Rewrite ( Names of each rule applied at the location ) +- Authentication ( Provides each type of authentication that is enabled for the location. If anonymous `default setting` will be provided if that is enabled Out of the Box on the server ) + +**NOTE:** For each of the URL Rewrite rules, we will display additional information about the rule to let you know what it is doing. It is also recommended to remove any mitigation rules that you might have applied if you have the security fix installed on the server. + +### Included in HTML Report? + +Yes diff --git a/mkdocs.yml b/mkdocs.yml index 69eac08311..c1b7eb746c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - DownloadDomainCheck: Diagnostics/HealthChecker/DownloadDomainCheck.md - OpenRelayDomainCheck: Diagnostics/HealthChecker/OpenRelayDomain.md - FIPFSCheck: Diagnostics/HealthChecker/FIPFSCheck.md + - IISInformation: Diagnostics/HealthChecker/IISInformation.md - IISWebConfigCheck: Diagnostics/HealthChecker/IISWebConfigCheck.md - HCScheduledTask: Diagnostics/HealthChecker/RunHCViaSchedTask.md - ADSiteCount: Diagnostics/HealthChecker/ADSiteCount.md