Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,31 @@ function Invoke-AnalyzerFrequentConfigurationIssues {
$_.Location -like "*FrontEnd\HttpProxy*") {
return $_
}
} |
Where-Object {
# these are locations that don't by default have configuration files.
$_.Location -notlike "*\ClientAccess\web.config" -and $_.Location -notlike "*\ClientAccess\exchweb\EWS\bin\web.config" -and
$_.Location -notlike "*\ClientAccess\Autodiscover\bin\web.config" -and $_.Location -notlike "*\ClientAccess\Autodiscover\help\web.config"
}

$missingConfigFile = $iisConfigurationSettings | Where-Object { $_.Exist -eq $false }
$defaultVariableDetected = $iisConfigurationSettings | Where-Object { $_.DefaultVariable -eq $true }
$binSearchFoldersNotFound = $iisConfigurationSettings | Where-Object { $_.BinSearchFoldersNotFound -eq $true }
$defaultVariableDetected = $iisConfigurationSettings | Where-Object { $null -ne ($_.Content | Select-String "%ExchangeInstallDir%") }
$binSearchFoldersNotFound = $iisConfigurationSettings |
Where-Object { $_.Location -like "*\ClientAccess\ecp\web.config" -and $_.Exist -eq $true } |
Where-Object {
$binSearchFolders = $_.Content | Select-String "BinSearchFolders" | Select-Object -ExpandProperty Line
$startIndex = $binSearchFolders.IndexOf("value=`"") + 7
$paths = $binSearchFolders.Substring($startIndex, $binSearchFolders.LastIndexOf("`"") - $startIndex).Split(";").Trim().ToLower()
$paths | ForEach-Object { Write-Verbose "BinSearchFolder: $($_)" }
$installPath = $exchangeInformation.RegistryValues.MisInstallPath
foreach ($binTestPath in @("bin", "bin\CmdletExtensionAgents", "ClientAccess\Owa\bin")) {
$testPath = [System.IO.Path]::Combine($installPath, $binTestPath).ToLower()
Write-Verbose "Testing path: $testPath"
if (-not ($paths.Contains($testPath))) {
return $_
}
}
}

if ($null -ne $missingConfigFile) {
$params = $baseParams + @{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
. $PSScriptRoot\..\..\..\..\Shared\ErrorMonitorFunctions.ps1
. $PSScriptRoot\..\..\..\..\Shared\Get-ExchangeBuildVersionInformation.ps1
. $PSScriptRoot\..\..\..\..\Shared\Get-ExchangeSettingOverride.ps1
. $PSScriptRoot\..\..\..\..\Shared\Invoke-ScriptBlockHandler.ps1
. $PSScriptRoot\IISInformation\Get-ExchangeAppPoolsInformation.ps1
. $PSScriptRoot\IISInformation\Get-ExchangeServerIISSettings.ps1
. $PSScriptRoot\Get-ExchangeAdPermissions.ps1
Expand Down Expand Up @@ -455,13 +454,8 @@ function Get-ExchangeInformation {
Write-Verbose "AMSI Interface is not available on this OS / Exchange server role"
}

$serverExchangeInstallDirectory = Invoke-ScriptBlockHandler -ComputerName $Script:Server `
-ScriptBlockDescription "Getting Exchange Install Directory" `
-CatchActionFunction ${Function:Invoke-CatchActions} `
-ScriptBlock {
(Get-ItemProperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath
}
$serverExchangeBinDirectory = [System.Io.Path]::Combine($serverExchangeInstallDirectory, "Bin\")
$exchangeInformation.RegistryValues = Get-ExchangeRegistryValues -MachineName $Script:Server -CatchActionFunction ${Function:Invoke-CatchActions}
$serverExchangeBinDirectory = [System.Io.Path]::Combine($exchangeInformation.RegistryValues.MisInstallPath, "Bin\")
Write-Verbose "Found Exchange Bin: $serverExchangeBinDirectory"

if ($buildInformation.ServerRole -ne [HealthChecker.ExchangeServerRole]::Edge) {
Expand All @@ -480,7 +474,6 @@ function Get-ExchangeInformation {

$exchangeServerIISParams = @{
ComputerName = $Script:Server
ExchangeInstallPath = $serverExchangeInstallDirectory
IsLegacyOS = ($OSMajorVersion -lt [HealthChecker.OSServerVersion]::Windows2016)
CatchActionFunction = ${Function:Invoke-CatchActions}
}
Expand Down Expand Up @@ -528,8 +521,6 @@ function Get-ExchangeInformation {
}

$buildInformation.FIPFSUpdateIssue = Get-FIPFSScanEngineVersionState @fipfsParams

$exchangeInformation.RegistryValues = Get-ExchangeRegistryValues -MachineName $Script:Server -CatchActionFunction ${Function:Invoke-CatchActions}
$exchangeInformation.ServerMaintenance = Get-ExchangeServerMaintenanceState -ComponentsToSkip "ForwardSyncDaemon", "ProvisioningRps"
$exchangeInformation.SettingOverrides = Get-ExchangeSettingOverride -Server $Script:Server -CatchActionFunction ${Function:Invoke-CatchActions}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ function Get-ExchangeRegistryValues {
GetValue = "DisableAsyncNotification"
}

$installDirectoryParams = $baseParams + @{
SubKey = "SOFTWARE\Microsoft\ExchangeServer\v15\Setup"
GetValue = "MsiInstallPath"
}

return [PSCustomObject]@{
CtsProcessorAffinityPercentage = [int](Get-RemoteRegistryValue @ctsParams)
FipsAlgorithmPolicyEnabled = [int](Get-RemoteRegistryValue @fipsParams)
DisableGranularReplication = [int](Get-RemoteRegistryValue @blockReplParams)
DisableAsyncNotification = [int](Get-RemoteRegistryValue @disableAsyncParams)
MisInstallPath = [string](Get-RemoteRegistryValue @installDirectoryParams)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,78 +7,62 @@ function Get-ExchangeIISConfigSettings {
[CmdletBinding()]
param(
[string]$MachineName,
[string]$ExchangeInstallPath,
[string[]]$FilePath,
[scriptblock]$CatchActionFunction
)
begin {
Write-Verbose "Calling: $($MyInvocation.MyCommand)"
Write-Verbose "Passed ExchangeInstallPath: $ExchangeInstallPath"
function GetExchangeIISConfigSettings {
param(
[string]$ExchangeInstallPath
[string[]]$FilePath
)
$iisConfigLocations = @("ClientAccess\Autodiscover\web.config",
"ClientAccess\ecp\web.config",
"ClientAccess\exchweb\ews\web.config",
"ClientAccess\mapi\emsmdb\web.config",
"ClientAccess\mapi\nspi\web.config",
"ClientAccess\OAB\web.config",
"ClientAccess\Owa\web.config",
"ClientAccess\PowerShell\web.config",
"ClientAccess\PowerShell-Proxy\web.config",
"ClientAccess\RpcProxy\web.config",
"ClientAccess\Sync\web.config",
"FrontEnd\HttpProxy\autodiscover\web.config",
"FrontEnd\HttpProxy\ecp\web.config",
"FrontEnd\HttpProxy\ews\web.config",
"FrontEnd\HttpProxy\mapi\web.config",
"FrontEnd\HttpProxy\oab\web.config",
"FrontEnd\HttpProxy\owa\web.config",
"FrontEnd\HttpProxy\powershell\web.config",
"FrontEnd\HttpProxy\pushnotifications\web.config",
"FrontEnd\HttpProxy\ReportingWebService\web.config",
"FrontEnd\HttpProxy\rpc\web.config",
"FrontEnd\HttpProxy\sync\web.config",
"ClientAccess\SharedWebConfig.config",
"FrontEnd\HttpProxy\SharedWebConfig.config") |
ForEach-Object { [System.IO.Path]::Combine($ExchangeInstallPath, $_) }
$iisConfigLocations += "$env:SystemDrive\inetpub\wwwroot\web.config"
$binSearchFolderPaths = @("bin", "bin\CmdletExtensionAgents", "ClientAccess\Owa\bin")

$results = New-Object 'System.Collections.Generic.List[object]'
$sharedConfigure = @()
$ca = "ClientAccess\"
$hp = "HttpProxy\"
$sharedWebConfig = "SharedWebConfig.config"

foreach ($location in $FilePath) {

foreach ($location in $iisConfigLocations) {
$binSearchFoldersNotFound = $false
Write-Verbose "Working on location: $location"
$exist = Test-Path $location
$defaultVariable = $false
$content = $null
$sharedLocation = $null

if ($exist) {
$defaultVariable = $null -ne (Get-ChildItem $location | Select-String "%ExchangeInstallDir%")
Write-Verbose "File exists. Getting content"
$content = Get-Content $location
}
# not sure if we need to check for this, because I think the %ExchangeInstallDir% will be set still
# but going to add this check as well either way.
if ($location -like "*\ClientAccess\ecp\web.config" -and
$exist) {
$linkedConfiguration = ($content | Select-String linkedConfiguration).Line

if ($null -ne $linkedConfiguration) {
Write-Verbose "Found linkedConfiguration"
$clientAccessSharedIndex = $location.IndexOf($ca)
$httpProxySharedIndex = $location.IndexOf($hp)

$BinSearchFolders = Get-ChildItem $location | Select-String "BinSearchFolders" | Select-Object -ExpandProperty Line
$startIndex = $BinSearchFolders.IndexOf("value=`"") + 7
$paths = $BinSearchFolders.Substring($startIndex, $BinSearchFolders.LastIndexOf("`"") - $startIndex).Split(";").Trim().ToLower()
$paths | ForEach-Object { Write-Verbose "BinSearchFolder: $($_)" }
foreach ($binTestPath in $binSearchFolderPaths) {
$testPath = [System.IO.Path]::Combine($ExchangeInstallPath, $binTestPath).ToLower()
Write-Verbose "Testing path: $testPath"
if (-not ($paths.Contains($testPath))) {
$binSearchFoldersNotFound = $true
if ($clientAccessSharedIndex -ne -1) {
$sharedLocation = [System.IO.Path]::Combine($location.Substring(0, $clientAccessSharedIndex + $ca.Length), $sharedWebConfig)
} elseif ($httpProxySharedIndex -ne -1) {
$sharedLocation = [System.IO.Path]::Combine($location.Substring(0, $httpProxySharedIndex + $hp.Length), $sharedWebConfig)
}
}

if ($null -ne $sharedLocation -and
(-not ($sharedConfigure.Contains($sharedLocation)))) {
Write-Verbose "Adding Shared Location of: $sharedLocation"
$sharedConfigure += $sharedLocation
$results.Add([PSCustomObject]@{
Location = $sharedLocation
Content = if (Test-Path $sharedLocation) { Get-Content $sharedLocation } else { $null }
Exist = $(Test-Path $sharedLocation)
})
}
}

$results.Add([PSCustomObject]@{
Location = $location
Content = $content
Exist = $exist
DefaultVariable = $defaultVariable
BinSearchFoldersNotFound = $binSearchFoldersNotFound
Location = $location
Content = $content
Exist = $exist
})
}
return $results
Expand All @@ -87,7 +71,7 @@ function Get-ExchangeIISConfigSettings {
$params = @{
ComputerName = $MachineName
ScriptBlock = ${Function:GetExchangeIISConfigSettings}
ArgumentList = $ExchangeInstallPath
ArgumentList = $FilePath
CatchActionFunction = $CatchActionFunction
}
return Invoke-ScriptBlockHandler @params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,36 @@
# Licensed under the MIT License.

. $PSScriptRoot\Get-ExchangeIISConfigSettings.ps1
. $PSScriptRoot\Get-IISWebApplication.ps1
. $PSScriptRoot\Get-IISWebSite.ps1
. $PSScriptRoot\..\..\..\..\..\Shared\Invoke-ScriptBlockHandler.ps1
. $PSScriptRoot\..\..\..\..\..\Shared\IISFunctions\Get-ApplicationHostConfig.ps1
. $PSScriptRoot\..\..\..\..\..\Shared\IISFunctions\Get-IISModules.ps1

function Get-ExchangeServerIISSettings {
param(
[string]$ComputerName,
[string]$ExchangeInstallPath,
[bool]$IsLegacyOS = $false,
[scriptblock]$CatchActionFunction
)
process {
Write-Verbose "Calling: $($MyInvocation.MyCommand)"

$params = @{
ComputerName = $ComputerName
CatchActionFunction = $CatchActionFunction
}

$webSite = Invoke-ScriptBlockHandler @params -ScriptBlock ${Function:Get-IISWebSite}
$webApplication = Invoke-ScriptBlockHandler @params -ScriptBlock ${Function:Get-IISWebApplication}

$configurationFiles = @($webSite.PhysicalPath)
$configurationFiles += $webApplication.PhysicalPath | Select-Object -Unique
$configurationFiles = $configurationFiles | ForEach-Object { [System.IO.Path]::Combine($_, "web.config") }

$iisConfigParams = @{
MachineName = $ComputerName
ExchangeInstallPath = $ExchangeInstallPath
FilePath = $configurationFiles
CatchActionFunction = $CatchActionFunction
}
Write-Verbose "Trying to query the IIS configuration settings"
Expand All @@ -42,6 +56,8 @@ function Get-ExchangeServerIISSettings {
applicationHostConfig = $applicationHostConfig
IISModulesInformation = $iisModulesInformation
IISConfigurationSettings = $iisConfigurationSettings
IISWebSite = $webSite
IISWebApplication = $webApplication
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

function Get-IISWebApplication {
$webApplications = Get-WebApplication
$returnList = New-Object 'System.Collections.Generic.List[object]'

foreach ($webApplication in $webApplications) {
$returnList.Add([PSCustomObject]@{
Path = $webApplication.Path
ApplicationPool = $webApplication.applicationPool
EnabledProtocols = $webApplication.enabledProtocols
ServiceAutoStartEnabled = $webApplication.serviceAutoStartEnabled
ServiceAutoStartProvider = $webApplication.serviceAutoStartProvider
PreloadEnabled = $webApplication.preloadEnabled
PreviouslyEnabledProtocols = $webApplication.previouslyEnabledProtocols
ServiceAutoStartMode = $webApplication.serviceAutoStartMode
VirtualDirectoryDefaults = $webApplication.virtualDirectoryDefaults
Collection = $webApplication.Collection
Location = $webApplication.Location
ItemXPath = $webApplication.ItemXPath
PhysicalPath = $webApplication.PhysicalPath.Replace("%windir%", $env:windir).Replace("%SystemDrive%", $env:SystemDrive)
})
}

return $returnList
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

function Get-IISWebSite {
$webSites = Get-WebSite
$bindings = Get-WebBinding
$returnList = New-Object 'System.Collections.Generic.List[object]'

foreach ($site in $webSites) {
$siteBindings = $bindings |
Where-Object { $_.ItemXPath -like "*@name='$($site.name)' and @id='$($site.id)'*" }
$returnList.Add([PSCustomObject]@{
Name = $site.Name
Id = $site.Id
State = $site.State
Bindings = $siteBindings
Limits = $site.Limits
LogFile = $site.logFile
TraceFailedRequestsLogging = $site.traceFailedRequestsLogging
Hsts = $site.hsts
ApplicationDefaults = $site.applicationDefaults
VirtualDirectoryDefaults = $site.virtualDirectoryDefaults
Collection = $site.collection
ApplicationPool = $site.applicationPool
EnabledProtocols = $site.enabledProtocols
PhysicalPath = $site.physicalPath.Replace("%windir%", $env:windir).Replace("%SystemDrive%", $env:SystemDrive)
}
)
}
return $returnList
}
Loading