Skip to content

Commit

Permalink
Merge pull request #2085 from microsoft/main
Browse files Browse the repository at this point in the history
Release 5-2-24
  • Loading branch information
dpaulson45 authored May 2, 2024
2 parents 4ff2634 + ce97d7b commit db724bd
Show file tree
Hide file tree
Showing 15 changed files with 132 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ function Invoke-AnalyzerOsInformation {
}
Add-AnalyzedResultInformation @params
}

$params = $baseParams + @{
Details = "More Information: https://aka.ms/HC-NetFrameworkSupport"
DisplayWriteType = "Yellow"
DisplayCustomTabNumber = 2
}
Add-AnalyzedResultInformation @params
}

$displayValue = [string]::Empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function Get-ExchangeAppPoolsInformation {
$FilePath
)
if (Test-Path $FilePath) {
return (Get-Content $FilePath -Raw).Trim()
return (Get-Content $FilePath -Raw -Encoding UTF8).Trim()
}
return [string]::Empty
} `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function Get-ExchangeServerIISSettings {
$content = $null
try {
if ($exist) {
$content = (Get-Content $_ -Raw).Trim()
$content = (Get-Content $_ -Raw -Encoding UTF8).Trim()
[xml]$content | Out-Null # test to make sure it is valid
$validWebConfig = $true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function Get-IISWebApplication {
$webConfigExists = Test-Path $configurationFilePath

if ($webConfigExists) {
$webConfigContent = (Get-Content $configurationFilePath -Raw).Trim()
$webConfigContent = (Get-Content $configurationFilePath -Raw -Encoding UTF8).Trim()

try {
$linkedConfigurationLine = ([xml]$webConfigContent).configuration.assemblyBinding.linkedConfiguration.href
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function Get-IISWebSite {
$customHeaderHsts = $null

if ($webConfigExists) {
$webConfigContent = (Get-Content $configurationFilePath -Raw).Trim()
$webConfigContent = (Get-Content $configurationFilePath -Raw -Encoding UTF8).Trim()

try {
$webConfigContentXml = [xml]$webConfigContent
Expand Down
104 changes: 73 additions & 31 deletions Diagnostics/HealthChecker/Features/Get-HealthCheckerData.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,58 @@ function Get-HealthCheckerData {
return $false
}

function ExportHealthCheckerXml {
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)]
[object]$SaveDataObject,

[Parameter(Mandatory = $true)]
[hashtable]$ProgressParams
)
Write-Verbose "Calling: $($MyInvocation.MyCommand)"
$dataExported = $false

try {
$currentErrors = $Error.Count
$ProgressParams.Status = "Exporting Data"
Write-Progress @ProgressParams
$SaveDataObject | Export-Clixml -Path $Script:OutXmlFullPath -Encoding UTF8 -Depth 2 -ErrorAction Stop -Force
Write-Verbose "Successfully export out the data"
$dataExported = $true
} catch {
try {
Write-Verbose "Failed to Export-Clixml. Inner Exception: $_"
Write-Verbose "Converting HealthCheckerExchangeServer to json."
$outputXml = [PSCustomObject]@{
HealthCheckerExchangeServer = $null
HtmlServerValues = $null
DisplayResults = $null
}

if ($null -ne $SaveDataObject.HealthCheckerExchangeServer) {
$jsonHealthChecker = $SaveDataObject.HealthCheckerExchangeServer | ConvertTo-Json -Depth 6 -ErrorAction Stop
$outputXml.HtmlServerValues = $SaveDataObject.HtmlServerValues
$outputXml.DisplayResults = $SaveDataObject.DisplayResults
} else {
$jsonHealthChecker = $SaveDataObject | ConvertTo-Json -Depth 6 -ErrorAction Stop
}

$outputXml.HealthCheckerExchangeServer = $jsonHealthChecker | ConvertFrom-Json -ErrorAction Stop
$outputXml | Export-Clixml -Path $Script:OutXmlFullPath -Encoding UTF8 -Depth 2 -ErrorAction Stop -Force
Write-Verbose "Successfully export out the data after the convert"
$dataExported = $true
} catch {
Write-Red "Failed to Export-Clixml. Unable to export the data."
}
} finally {
# This prevents the need to call Invoke-CatchActions
Invoke-ErrorCatchActionLoopFromIndex $currentErrors
}
return $dataExported
}

Write-Verbose "Calling: $($MyInvocation.MyCommand)"
$paramWriteProgress = @{
Id = 1
Expand Down Expand Up @@ -96,10 +148,20 @@ function Get-HealthCheckerData {

try {
Invoke-SetOutputInstanceLocation -Server $serverName -FileName "HealthChecker" -IncludeServerName $true
Write-HostLog "Exchange Health Checker version $BuildVersion"

if (-not $Script:VulnerabilityReport) {
# avoid having vulnerability report having a txt file with nothing in it besides the Exchange Health Checker Version
Write-HostLog "Exchange Health Checker version $BuildVersion"
}

$HealthObject = $null
$HealthObject = Get-HealthCheckerExchangeServer -ServerName $serverNameParam
$HealthObject.OrganizationInformation = $organizationInformation

# If we successfully got the data, we want to export it out right away.
# This then allows if an exception does occur in the analysis stage,
# we then have the data output that is reproducing a problem in that section of code that we can debug.
$dataExported = ExportHealthCheckerXml -SaveDataObject $HealthObject -ProgressParams $paramWriteProgress
$paramWriteProgress.Status = "Analyzing Data"
Write-Progress @paramWriteProgress
$analyzedResults = Invoke-AnalyzerEngine -HealthServerObject $HealthObject
Expand All @@ -113,41 +175,21 @@ function Get-HealthCheckerData {
} catch {
Write-Red "Failed to Health Checker against $serverName"
$failedServerList.Add($serverName)
# Try to handle the issue so we don't get a false positive report.
Invoke-CatchActions
continue
}

$currentErrors = $Error.Count
$paramWriteProgress.Status = "Exporting Data"
Write-Progress @paramWriteProgress

try {
$analyzedResults | Export-Clixml -Path $Script:OutXmlFullPath -Encoding UTF8 -Depth 2 -ErrorAction Stop
Write-Verbose "Successfully export out the data"
} catch {
try {
Write-Verbose "Failed to Export-Clixml. Inner Exception: $_"
Write-Verbose "Converting HealthCheckerExchangeServer to json."
$jsonHealthChecker = $analyzedResults.HealthCheckerExchangeServer | ConvertTo-Json -Depth 6 -ErrorAction Stop

$testOutputXml = [PSCustomObject]@{
HealthCheckerExchangeServer = $jsonHealthChecker | ConvertFrom-Json -ErrorAction Stop
HtmlServerValues = $analyzedResults.HtmlServerValues
DisplayResults = $analyzedResults.DisplayResults
}

$testOutputXml | Export-Clixml -Path $Script:OutXmlFullPath -Encoding UTF8 -Depth 2 -ErrorAction Stop
Write-Verbose "Successfully export out the data after the convert"
} catch {
Write-Red "Failed to Export-Clixml. Unable to export the data."
if ($null -eq $HealthObject) {
# Try to handle the issue so we don't get a false positive report.
Invoke-CatchActions
}
continue
} finally {
# This prevents the need to call Invoke-CatchActions
Invoke-ErrorCatchActionLoopFromIndex $currentErrors

if ($null -ne $analyzedResults) {
# Export out the analyzed data, as this is needed for Build HTML Report.
$dataExported = ExportHealthCheckerXml -SaveDataObject $analyzedResults -ProgressParams $paramWriteProgress
}

# for now don't want to display that we output the information if ReturnDataCollectionOnly is false
if (-not $ReturnDataCollectionOnly) {
if ($dataExported -and -not $ReturnDataCollectionOnly) {
Write-Grey("Output file written to {0}" -f $Script:OutputFullPath)
Write-Grey("Exported Data Object Written to {0} " -f $Script:OutXmlFullPath)
}
Expand Down
12 changes: 12 additions & 0 deletions Diagnostics/HealthChecker/Features/Invoke-VulnerabilityReport.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@
function Invoke-VulnerabilityReport {

Write-Verbose "Calling: $($MyInvocation.MyCommand)"
$currentErrors = $Error.Count

if ((-not $SkipVersionCheck) -and
(Test-ScriptVersion -AutoUpdate -VersionsUrl "https://aka.ms/HC-VersionsUrl")) {
Write-Yellow "Script was updated. Please rerun the command."
return
} else {
$Script:DisplayedScriptVersionAlready = $true
Write-Green "Exchange Health Checker version $BuildVersion"
}

Invoke-ErrorCatchActionLoopFromIndex $currentErrors
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
Set-ADServerSettings -ViewEntireForest $true
$exchangeServers = @(Get-ExchangeServer)
Expand Down
3 changes: 2 additions & 1 deletion Diagnostics/HealthChecker/Helpers/Get-ErrorsThatOccurred.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ function Get-ErrorsThatOccurred {
}

if ($Error.Count -gt 0) {
Write-Grey(" "); Write-Grey(" ")
Write-Host ""
Write-Host ""
function Write-Errors {
Write-Verbose "`r`n`r`nErrors that occurred that wasn't handled"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,27 @@ function Get-ExportedHealthCheckerFiles {

$groupResults |
ForEach-Object {
if ($_.Count -gt 1) {
$groupData = $_.Group
$fileName = ($groupData | Sort-Object FileName -Descending | Select-Object -First 1).FileObject.VersionInfo.FileName
} else {
$fileName = ($_.Group).FileObject.VersionInfo.FileName
}
$sortedGroup = $_.Group | Sort-Object FileName -Descending
$index = 0
$continueLoop = $true

$data = Import-Clixml -Path $fileName
if ($null -ne $data) {
$importedItems.Add($data)
}
do {
$fileName = $sortedGroup[$index].FileObject.VersionInfo.FileName
$data = Import-Clixml -Path $fileName

if ($null -ne $data -and
$null -ne $data.HealthCheckerExchangeServer) {
Write-Verbose "For Server $($_.Group[0].ServerName) using file: $fileName"
$importedItems.Add($data)
$continueLoop = $false
} else {
$index++
if ($index -ge $_.Count) {
$continueLoop = $false
Write-Red "Failed to find proper Health Checker data to import for server $($_.Group[0].ServerName)"
}
}
} while ($continueLoop)
}
}
end {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
Mock Get-ExSetupFileVersionInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\ExSetup1.xml" }
Mock Get-WebSite -ParameterFilter { $Name -eq "Default Web Site" } -MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetWebSite_DefaultWebSite1.xml" }
Mock Get-WebConfigFile -ParameterFilter { $PSPath -eq "IIS:\Sites\Default Web Site" } -MockWith { return [PSCustomObject]@{ FullName = "$Script:MockDataCollectionRoot\Exchange\IIS\DefaultWebSite_web2.config" } }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw -Encoding UTF8 }
Mock Get-DynamicDistributionGroup { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetDynamicDistributionGroupPfMailboxes1.xml" }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Get TokenCacheModule version information" } -MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\IIS\GetVersionInformationCachToknPatched.xml" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
# Needs to be like this to match the filter
Mock Get-WebConfigFile -ParameterFilter { $PSPath -eq "IIS:\Sites\Exchange Back End/ecp" } -MockWith { return [PSCustomObject]@{ FullName = "$Script:MockDataCollectionRoot\Exchange\IIS\ClientAccess\ecp\web.config" } }
Mock Get-WebConfigFile -ParameterFilter { $PSPath -eq "IIS:\Sites\Default Web Site/ecp" } -MockWith { return [PSCustomObject]@{ FullName = "$Script:MockDataCollectionRoot\Exchange\IIS\DefaultWebSite_web.config" } }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost1.config" -Raw }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost1.config" -Raw -Encoding UTF8 }
Mock Get-ExchangeDiagnosticInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetExchangeDiagnosticInfo1.xml" }
Mock Get-IISModules { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetIISModulesNoTokenCacheModule.xml" }
Mock Get-Service {
Expand Down Expand Up @@ -221,9 +221,9 @@ Describe "Testing Health Checker by Mock Data Imports" {
Mock Get-AcceptedDomain { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\GetAcceptedDomain_Bad.xml" }
Mock Get-DnsClient { return Import-Clixml "$Script:MockDataCollectionRoot\OS\GetDnsClient1.xml" }
Mock Get-ExSetupFileVersionInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\ExSetup1.xml" }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost1.config" -Raw }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Runtime\1.0\noderunner.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\noderunner.exe1.config" -Raw }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\EdgeTransport.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\EdgeTransport.exe1.config" -Raw }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost1.config" -Raw -Encoding UTF8 }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Runtime\1.0\noderunner.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\noderunner.exe1.config" -Raw -Encoding UTF8 }
Mock Get-Content -ParameterFilter { $Path -eq "C:\Program Files\Microsoft\Exchange Server\V15\Bin\EdgeTransport.exe.config" } -MockWith { Get-Content "$Script:MockDataCollectionRoot\Exchange\EdgeTransport.exe1.config" -Raw -Encoding UTF8 }

SetDefaultRunOfHealthChecker "Debug_Scenario2_Results.xml"
}
Expand Down Expand Up @@ -309,7 +309,7 @@ Describe "Testing Health Checker by Mock Data Imports" {
Mock Get-WmiObjectHandler -ParameterFilter { $Class -eq "Win32_Processor" } `
-MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\Hardware\Physical_Win32_Processor1.xml" }
Mock Get-ExSetupFileVersionInfo { return Import-Clixml "$Script:MockDataCollectionRoot\Exchange\ExSetup1.xml" }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\applicationHost2.config" -Raw -Encoding UTF8 }

SetDefaultRunOfHealthChecker "Debug_Scenario3_Physical_Results.xml"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Describe "Exchange 2019 Scenarios testing 2" {
BeforeAll {
Mock Get-WmiObjectHandler -ParameterFilter { $Class -eq "Win32_PageFileSetting" } `
-MockWith { return Import-Clixml "$Script:MockDataCollectionRoot\OS\Win32_PageFileWellConfigured.xml" }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\BadApplicationHost.config" -Raw }
Mock Invoke-ScriptBlockHandler -ParameterFilter { $ScriptBlockDescription -eq "Getting applicationHost.config" } -MockWith { return Get-Content "$Script:MockDataCollectionRoot\Exchange\IIS\BadApplicationHost.config" -Raw -Encoding UTF8 }
Mock Get-WebApplication -MockWith { throw "Error - Pester" }
Mock Get-WebSite -ParameterFilter { $null -eq $Name } -MockWith { throw "Error - Pester" }
Mock Get-WebSite -ParameterFilter { $Name -eq "Default Web Site" } -MockWith { throw "Error - Pester" }
Expand Down
Loading

0 comments on commit db724bd

Please sign in to comment.