Skip to content

Commit c68113d

Browse files
Merge branch 'main' into fix-onpremauth-changes-clean
2 parents c050c31 + 25b2e41 commit c68113d

53 files changed

Lines changed: 3727 additions & 67 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.build/cspell-words.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ Eventlog
4141
evtx
4242
Exchweb
4343
exfiltration
44+
exopf
45+
exov
4446
fabrikam
4547
FIPFS
4648
fips
@@ -81,6 +83,7 @@ ldifde
8183
Liant
8284
Linq
8385
LOCALAPPDATA
86+
lockdown
8487
logman
8588
lsass
8689
Lync
@@ -89,6 +92,9 @@ Mbps
8992
mbxs
9093
Mddhhmm
9194
Mddhhmmss
95+
mepf
96+
mepfdns
97+
mepfs
9298
meso
9399
mesos
94100
mfcmapi
@@ -151,6 +157,7 @@ Sids
151157
Snapin
152158
SPDLT
153159
STMP
160+
subfolders
154161
syncall
155162
tcpip
156163
TDSDSA
@@ -159,6 +166,7 @@ UCMA
159166
unconfigured
160167
unrequired
161168
USERDNSDOMAIN
169+
validatemepf
162170
Vianet
163171
Visio
164172
vmxnet

.github/CODEOWNERS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
# EXO PF Team
1717
/PublicFolders/Migration/ @vishmittal @microsoft/css-exchange-admins
18-
/PublicFolders/Hybrid/ @vishmittal @microsoft/css-exchange-admins
18+
/PublicFolders/MailPublicFolderSync/ @vishmittal @microsoft/css-exchange-admins
1919
/PublicFolders/Update-PublicFolderPermissions.ps1 @vishmittal @microsoft/css-exchange-admins
2020
/docs/PublicFolders/Migration/ @vishmittal @microsoft/css-exchange-admins
21-
/docs/PublicFolders/Hybrid/ @vishmittal @microsoft/css-exchange-admins
21+
/docs/PublicFolders/MailPublicFolderSync/ @vishmittal @microsoft/css-exchange-admins
2222
/docs/PublicFolders/Update-PublicFolderPermissions.md @vishmittal @microsoft/css-exchange-admins

Diagnostics/HealthChecker/Analyzer/Get-URLRewriteRule.ps1

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,21 @@ function Get-URLRewriteRule {
3737
$appHostConfigLocations = $ApplicationHostConfig.configuration.Location.path
3838
}
3939
process {
40-
foreach ($key in $WebConfigContent.Keys) {
40+
# Build combined location list: WebConfigContent keys + appHost-only locations.
41+
# Some IIS locations (e.g., EAS/Proxy) exist only in applicationHost.config and have
42+
# no web.config entry from Get-WebApplication. We still need to walk up inheritance for them.
43+
$allLocations = [System.Collections.Generic.List[string]]::new()
44+
foreach ($wcKey in $WebConfigContent.Keys) {
45+
$allLocations.Add($wcKey)
46+
}
47+
foreach ($appHostPath in $appHostConfigLocations) {
48+
if (-not [string]::IsNullOrEmpty($appHostPath) -and
49+
-not $WebConfigContent.ContainsKey($appHostPath)) {
50+
$allLocations.Add($appHostPath)
51+
}
52+
}
53+
54+
foreach ($key in $allLocations) {
4155
Write-Verbose "Working on key: $key"
4256
$continue = $true
4357
$clearInbound = $false

Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,13 @@ function Invoke-AnalyzerExchangeInformation {
335335
}
336336
}
337337
} else {
338-
$displayMissingGroups.Add("Unable to determine Local System Membership as the results were blank.")
338+
if ($null -ne $exchangeInformation.ADComputerObject.LocalGroupMemberException -and
339+
$exchangeInformation.ADComputerObject.LocalGroupMemberException.Exception -is [System.InvalidOperationException] -and
340+
$HealthServerObject.OSInformation.BuildInformation.BuildVersion -lt [System.Version]"10.0.26100") {
341+
$displayMissingGroups.Add("Unable to determine Local System Membership. This can occur when orphaned SIDs exist in the local Administrators group.")
342+
} else {
343+
$displayMissingGroups.Add("Unable to determine Local System Membership as the results were blank.")
344+
}
339345
}
340346

341347
if ($null -ne $exchangeInformation.ADComputerObject.ADGroupMembership -and

Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerIISInformation.ps1

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,14 @@ function Invoke-AnalyzerIISInformation {
612612
$currentSection = $urlRewriteRules[$key]
613613

614614
if ($currentSection.Count -ne 0) {
615+
# Collect <remove> entries so inherited rules that are removed at a lower level are excluded.
616+
$excludeRules = @()
617+
foreach ($section in $currentSection) {
618+
if ($null -ne $section.Remove) {
619+
$excludeRules += $section.Remove.Name
620+
}
621+
}
622+
615623
foreach ($rule in $currentSection.rule) {
616624

617625
if ($null -eq $rule) {
@@ -621,12 +629,24 @@ function Invoke-AnalyzerIISInformation {
621629
# skip over disabled rules.
622630
Write-Verbose "skipping over disabled rule: $($rule.Name) for vDir '$key'"
623631
continue
632+
} elseif ($rule.Name -in $excludeRules) {
633+
Write-Verbose "skipping removed rule: $($rule.Name) for vDir '$key'"
634+
continue
624635
}
625636

626637
#multiple match type possibilities, but should only be one per rule.
627-
$propertyType = ($rule.match | Get-Member | Where-Object { $_.MemberType -eq "Property" }).Name
628-
$isUrlMatchProblem = $propertyType -eq "url" -and $rule.match.$propertyType -eq "*"
629-
$matchProperty = "$propertyType - $($rule.match.$propertyType)"
638+
$allProperties = @(($rule.match | Get-Member | Where-Object { $_.MemberType -eq "Property" }).Name)
639+
# When <match> has extra attributes (negate, ignoreCase), Get-Member returns multiple properties.
640+
# Filter to the actual match target property for display and the URL Match Problem check.
641+
$propertyType = ($allProperties | Where-Object { $_ -eq "url" -or $_ -eq "serverVariable" } | Select-Object -First 1)
642+
643+
if ($null -eq $propertyType) {
644+
$propertyType = $allProperties | Select-Object -First 1
645+
}
646+
647+
$matchValue = $rule.match.$propertyType
648+
$isUrlMatchProblem = $propertyType -eq "url" -and $matchValue -eq "*"
649+
$matchProperty = "$propertyType - $matchValue"
630650

631651
$displayObject = [PSCustomObject]@{
632652
RewriteRuleName = $rule.name
@@ -682,6 +702,13 @@ function Invoke-AnalyzerIISInformation {
682702
$currentSection = $urlOutboundRewriteRules[$key]
683703

684704
if ($currentSection.Count -ne 0) {
705+
$excludeOutboundRules = @()
706+
foreach ($section in $currentSection) {
707+
if ($null -ne $section.Remove) {
708+
$excludeOutboundRules += $section.Remove.Name
709+
}
710+
}
711+
685712
foreach ($rule in $currentSection.rule) {
686713

687714
if ($null -eq $rule) {
@@ -690,6 +717,9 @@ function Invoke-AnalyzerIISInformation {
690717
} elseif ($rule.enabled -eq "false") {
691718
Write-Verbose "skipping over disabled outbound rule: $($rule.Name) for vDir '$key'"
692719
continue
720+
} elseif ($rule.Name -in $excludeOutboundRules) {
721+
Write-Verbose "skipping removed outbound rule: $($rule.Name) for vDir '$key'"
722+
continue
693723
}
694724

695725
$displayObject = [PSCustomObject]@{

Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerOsInformation.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,15 +400,15 @@ function Invoke-AnalyzerOsInformation {
400400
$displayWriteType2012 = "Green"
401401
$displayValue2012 = "$($installed2012.DisplayVersion) Version is current"
402402
} elseif (Test-VisualCRedistributableInstalled -Year 2012 -Installed $osInformation.VcRedistributable) {
403-
$displayValue2012 = "Redistributable ($($installed2012.DisplayVersion)) is outdated"
403+
$displayValue2012 = "Redistributable is outdated ($($installed2012.DisplayVersion)). Update the Visual C++ 2012 version."
404404
$displayWriteType2012 = "Yellow"
405405
}
406406

407407
if (Test-VisualCRedistributableUpToDate -Year 2013 -Installed $osInformation.VcRedistributable) {
408408
$displayWriteType2013 = "Green"
409409
$displayValue2013 = "$($installed2013.DisplayVersion) Version is current"
410410
} elseif (Test-VisualCRedistributableInstalled -Year 2013 -Installed $osInformation.VcRedistributable) {
411-
$displayValue2013 = "Redistributable ($($installed2013.DisplayVersion)) is outdated"
411+
$displayValue2013 = "Redistributable is outdated ($($installed2013.DisplayVersion)). Update the Visual C++ 2013 version."
412412
$displayWriteType2013 = "Yellow"
413413
}
414414
}
@@ -435,7 +435,7 @@ function Invoke-AnalyzerOsInformation {
435435
$displayWriteType2012 -eq "Yellow") {
436436

437437
$params = $baseParams + @{
438-
Details = "Note: For more information about the latest C++ Redistributable please visit: https://aka.ms/HC-LatestVC`r`n`t`tThis is not a requirement to upgrade, only a notification to bring to your attention."
438+
Details = "Note: Exchange requires the Visual C++ 2012 and 2013 Redistributable specifically. These are not replaced by newer versions.`r`n`t`tFor more information please visit: https://aka.ms/HC-LatestVC"
439439
DisplayWriteType = "Yellow"
440440
DisplayCustomTabNumber = 2
441441
}

Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityCveCheck.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ function Invoke-AnalyzerSecurityCveCheck {
144144
"Oct25SU" = (NewCveEntry @("CVE-2025-59249") @($ex2016, $ex2019, $exSE))
145145
"Dec25SU" = (NewCveEntry @("CVE-2025-64666", "CVE-2025-64667") @($ex2016, $ex2019, $exSE))
146146
"Feb26SU" = (NewCveEntry @("CVE-2026-21527") @($ex2016, $ex2019, $exSE))
147+
"Jun26SU" = (NewCveEntry @("CVE-2026-42897", "CVE-2026-45500", "CVE-2026-45501", "CVE-2026-45502", "CVE-2026-45503", "CVE-2026-45504", "CVE-2026-47631") @($ex2016, $ex2019, $exSE))
147148
}
148149

149150
# Need to organize the list so oldest CVEs come out first.

Diagnostics/HealthChecker/Analyzer/Security/Invoke-AnalyzerSecurityMitigationService.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ function Invoke-AnalyzerSecurityMitigationService {
129129
}
130130

131131
$params = $baseParams + @{
132-
Details = "Run: 'Get-Mitigations.ps1' from: '$ExScripts' to learn more."
132+
Details = "Run: 'Get-Mitigations.ps1' from: '$([System.IO.Path]::Combine($exchangeInformation.RegistryValues.MsiInstallPath, "Scripts"))' to learn more."
133133
DisplayCustomTabNumber = 2
134134
}
135135
Add-AnalyzedResultInformation @params

Diagnostics/HealthChecker/Analyzer/Tests/Get-URLRewriteRule.Tests.ps1

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,32 @@ Describe "Get-URLRewriteRule" {
9696
}
9797
}
9898

99+
Context "AppHost-only locations (no web.config entry)" {
100+
101+
It "Should process Proxy location that only exists in appHost" {
102+
# EAS/Proxy exists in applicationHost.config but is not returned by Get-WebApplication
103+
# so it has no entry in $webConfigContent. The fix adds it from appHost locations.
104+
$Script:result.Inbound.ContainsKey("Default Web Site/Microsoft-Server-ActiveSync/Proxy") | Should -Be $true
105+
$Script:result.Outbound.ContainsKey("Default Web Site/Microsoft-Server-ActiveSync/Proxy") | Should -Be $true
106+
}
107+
108+
It "Should inherit parent rules for appHost-only Proxy location" {
109+
# Proxy has no rules at its own appHost level. Walk-up should reach DWS web.config
110+
# (CVE-2022-41040) and DWS appHost (disabled HTTPS redirect, AppHost Only Rule) and global.
111+
$proxyRules = $Script:result.Inbound["Default Web Site/Microsoft-Server-ActiveSync/Proxy"]
112+
$proxyRuleNames = @($proxyRules.rule.name | Where-Object { $null -ne $_ })
113+
$proxyRuleNames | Should -Contain "CVE-2022-41040 Mitigation"
114+
$proxyRuleNames | Should -Contain "Global Block Bad User Agents"
115+
}
116+
117+
It "Should not duplicate keys that exist in both WebConfigContent and appHost" {
118+
# "Default Web Site" exists in both $webConfigContent and appHost locations.
119+
# It should appear exactly once in the result, not duplicated.
120+
$dwsCount = @($Script:result.Inbound.Keys | Where-Object { $_ -eq "Default Web Site" }).Count
121+
$dwsCount | Should -Be 1
122+
}
123+
}
124+
99125
Context "Clear stops inheritance" {
100126

101127
It "Should stop at clear in appHost location for Default Web Site/mapi" {

Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Invoke-JobExchangeInformationLocal.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ function Invoke-JobExchangeInformationLocal {
124124
$localGroupMember = Get-LocalGroupMember -SID "S-1-5-32-544" -ErrorAction Stop
125125
} catch {
126126
Write-Verbose "Failed to run Get-LocalGroupMember. Inner Exception: $_"
127+
$localGroupMemberException = $_
127128
Invoke-CatchActions
128129
}
129130
}
@@ -210,6 +211,7 @@ function Invoke-JobExchangeInformationLocal {
210211
IanaTimeZoneMappingsRaw = $ianaTimeZoneMappingContent
211212
FileContentInformation = $fileContentInformation
212213
LocalGroupMember = $localGroupMember
214+
LocalGroupMemberException = $localGroupMemberException
213215
RemoteJob = $true -eq $PSSenderInfo
214216
JobHandledErrors = $jobHandledErrors
215217
AllErrors = $Error

0 commit comments

Comments
 (0)