Summary
Three Pester tests fail in the ReleaseAutomationTest comparison of 7.7.0-preview.1 against the 7.6.0-rc.1 baseline on portable (ZIP/TAR) and several non-portable distribution lanes. All three are downstream of PR #26565 ("Refactor the module path construction code", commit 592668bd0), which is in release/v7.7.0-preview.1 but is not in v7.6.0-rc.1 (verified: git merge-base --is-ancestor 592668bd0 v7.6.0-rc.1 returns 1).
| Test ID |
Test |
File |
Origin |
| 103778 |
ConsoleHost - SettingsFile - PSModulePath - Verify PowerShell PSModulePath should contain paths from config file (Windows) |
test/powershell/Host/ConsoleHost.Tests.ps1#L402 |
New test added by PR #26565 |
| 103842 |
Non-Windows equivalent of 103778 (same It block, run on Linux/macOS lanes) |
test/powershell/Host/ConsoleHost.Tests.ps1#L402 |
New test added by PR #26565 |
| 108309 |
Import-Module with WinCompat - WinCompat process does not inherit PowerShell-Core-specific paths |
test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1#L727 |
Pre-existing since PR #7183 (2018); newly fails in preview.1 |
Lanes affected (one or more of these tests fail per lane):
WindowsServer2016ZIP - Unelevated
ubuntu22 TAR
mariner ARM64
macOS TAR, macOS
linux ARM32
debian12
azurelinux30
First failing build: ReleaseAutomationTest-27557-ps-671171.
These tests were previously tracked as Case 2 of issue #27343 and are split out here because the root cause is unrelated to PR #27305 (the original framing of #27343).
Background: what PR #26565 changed
Commit 592668bd0 rewrote ModuleIntrinsics.GetModulePath and replaced the helper AddToPath (with PathContainsSubstring) with UpdatePath, which uses HashSet<string> plus Path.TrimEndingDirectorySeparator for dedup and advances insertPosition after each insert. It also added a static static ModuleIntrinsics() { SetModulePath(); } initializer.
The "EVT.Process exists" branch in preview.1's GetModulePath is:
string systemModulePathToUse = string.IsNullOrEmpty(hklmMachineModulePath)
? psHomeModulePath
: hklmMachineModulePath;
int insertIndex = 0;
currentProcessModulePath = UpdatePath(currentProcessModulePath, personalModulePathToUse, ref insertIndex);
currentProcessModulePath = UpdatePath(currentProcessModulePath, sharedModulePath, ref insertIndex);
currentProcessModulePath = UpdatePath(currentProcessModulePath, systemModulePathToUse, ref insertIndex);
When hklmMachineModulePath is non-empty, systemModulePathToUse = hklmMachineModulePath and psHomeModulePath (i.e., $PSHOME/Modules) is never added to the process PSModulePath. The same logical branch exists on Linux/macOS via the equivalent OS-level system module path.
PR #26565 also added the new test Verify PowerShell PSModulePath should contain paths from config file (test 103778 / 103842) that asserts $PSHOME/Modules is already present at IndexOf > 0 in $env:PSModulePath. That assertion is incompatible with portable distributions where $PSHOME is a user-local path not registered in the OS-level PSModulePath.
Why each test fails
Tests 103778 (Windows) and 103842 (non-Windows)
# BeforeAll: write settings file with PSModulePath = "$PSHOME/Modules<sep>$TestDrive/NonExist"
$psModulePath = & $powershell -NoProfile -SettingsFile $CustomSettingsFile -Command '$env:PSModulePath'
# Assertion:
$index = $psModulePath.IndexOf("$mPath1$pathSep", [StringComparison]::OrdinalIgnoreCase)
$index | Should -BeGreaterThan 0 # FAILS - $PSHOME/Modules ends up at position 0
Failure mechanics on a portable distribution:
- Child pwsh inherits parent
$env:PSModulePath = <personal><sep><shared><sep><OS-defaults> and does not contain the ZIP/TAR-extracted $PSHOME/Modules.
- Settings-file
PSModulePath is read as hkcuUserModulePath = "$PSHOME/Modules<sep>$TestDrive/NonExist".
GetModulePath "Process exists" branch sets personalModulePathToUse = hkcuUserModulePath.
UpdatePath(current, "$PSHOME/Modules<sep>$TestDrive/NonExist", ref insertIndex=0):
$PSHOME/Modules is NOT in initialPaths -> inserted at position 0.
$TestDrive/NonExist is NOT in initialPaths -> inserted at position 1.
- Final
PSModulePath starts with $PSHOME/Modules<sep>$TestDrive/NonExist<sep>....
IndexOf("$PSHOME/Modules<sep>") = 0 -> Should -BeGreaterThan 0 fails.
StartsWith("$TestDrive/NonExist<sep>") = false -> later assertion also fails.
The BeforeAll comment in the test literally states: "$mPath1 already exists in the value of env PSModulePath, so it won''t be added again." That precondition does not hold on portable distributions. Since the It block is shared across platforms, it manifests as test 103778 on Windows lanes and 103842 on non-Windows lanes.
Test 108309
$pscoreSystemPath = Join-Path -Path $PSHOME -ChildPath 'Modules'
$pscorePaths = $env:psmodulepath
$pscorePaths | Should -BeLike "*$pscoreSystemPath*" # FAILS
Same root assumption - the test requires $PSHOME/Modules to be in $env:PSModulePath. On portable distributions this is not guaranteed.
This test is 7+ years old. It is reported as a "New Failure" by the comparator because it likely passed on the rc.1 baseline (rc.1 uses the older AddToPath path-construction code which had different ordering/dedup semantics) and now fails on preview.1 after PR #26565. Open verification item: confirm the rc.1 ReleaseAutomationTest result for 108309 on each affected lane.
Suggested resolution
Test side (required regardless): make the assertions portable-distribution-aware.
For tests 103778 / 103842 (test/powershell/Host/ConsoleHost.Tests.ps1):
Option A - have BeforeAll ensure the precondition the test was written against:
BeforeAll {
$CustomSettingsFile = Join-Path -Path $TestDrive -ChildPath 'powershell.test.json'
$mPath1 = Join-Path $PSHOME 'Modules'
$mPath2 = Join-Path $TestDrive 'NonExist'
$pathSep = [System.IO.Path]::PathSeparator
# Test assumes $PSHOME/Modules is already in $env:PSModulePath.
# On ZIP/TAR/portable distributions this may not hold; ensure it.
$contains = $env:PSModulePath -split [regex]::Escape($pathSep) |
Where-Object { [string]::Equals($_, $mPath1, 'OrdinalIgnoreCase') }
if (-not $contains) {
$script:savedPSModulePath = $env:PSModulePath
$env:PSModulePath = "$mPath1$pathSep$env:PSModulePath"
}
$ModulePath = "${mPath1}${pathSep}${mPath2}".Replace(''\'', "\\")
Set-Content -Path $CustomSettingsfile -Value "{`"Microsoft.PowerShell:ExecutionPolicy`":`"Unrestricted`", `"PSModulePath`": `"$ModulePath`" }" -ErrorAction Stop
}
AfterAll {
if ($script:savedPSModulePath) {
$env:PSModulePath = $script:savedPSModulePath
}
}
Option B - skip when the precondition does not hold:
It "Verify PowerShell PSModulePath should contain paths from config file" {
if (($env:PSModulePath -split [regex]::Escape([IO.Path]::PathSeparator)) -notcontains $mPath1) {
Set-ItResult -Skipped -Because ''$PSHOME/Modules is not in $env:PSModulePath (portable distribution); test precondition does not hold.''
return
}
# ... existing assertions ...
}
For test 108309 (test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1):
It ''WinCompat process does not inherit PowerShell-Core-specific paths'' {
$pscoreUserPath = Join-Path -Path $HOME -ChildPath "Documents/PowerShell/Modules"
$pscoreSharedPath = Join-Path -Path $env:ProgramFiles -ChildPath "PowerShell/Modules"
$pscoreSystemPath = Join-Path -Path $PSHOME -ChildPath ''Modules''
$pscorePaths = $env:psmodulepath
$pscorePaths | Should -BeLike "*$pscoreUserPath*"
$pscorePaths | Should -BeLike "*$pscoreSharedPath*"
if ($pscorePaths -like "*$pscoreSystemPath*") {
$pscorePaths | Should -BeLike "*$pscoreSystemPath*"
}
# else: tolerated - portable/ZIP/TAR distributions do not put $PSHOME/Modules in $env:PSModulePath.
# Remaining WinCompat exclusion assertions still run unchanged.
# ...
}
Product side (only if 108309 was Passed on rc.1): investigate whether the AddToPath -> UpdatePath rewrite in PR #26565 changed the effective PSModulePath shape on portable distributions and, if so, restore the previous behavior or explicitly add psHomeModulePath to the system path even when HKLM (or its OS-level equivalent) is non-empty.
Branch strategy
Per .github/instructions/code-review-branch-strategy.instructions.md: PR #26565 is on master and on release/v7.7.0-preview.1. Fix the test files on master first; backport to release branches as needed. Do not add ZIP/TAR-specific workarounds only on the release branch.
Files affected
test/powershell/Host/ConsoleHost.Tests.ps1 (lines 391-413) - tests 103778 / 103842
test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1 (line 727) - test 108309
src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs - product-side, only if 108309 regression on rc.1 is confirmed
Related
Summary
Three Pester tests fail in the
ReleaseAutomationTestcomparison of 7.7.0-preview.1 against the 7.6.0-rc.1 baseline on portable (ZIP/TAR) and several non-portable distribution lanes. All three are downstream of PR #26565 ("Refactor the module path construction code", commit592668bd0), which is inrelease/v7.7.0-preview.1but is not inv7.6.0-rc.1(verified:git merge-base --is-ancestor 592668bd0 v7.6.0-rc.1returns 1).ConsoleHost - SettingsFile - PSModulePath - Verify PowerShell PSModulePath should contain paths from config file(Windows)test/powershell/Host/ConsoleHost.Tests.ps1#L402Itblock, run on Linux/macOS lanes)test/powershell/Host/ConsoleHost.Tests.ps1#L402Import-Module with WinCompat - WinCompat process does not inherit PowerShell-Core-specific pathstest/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1#L727Lanes affected (one or more of these tests fail per lane):
WindowsServer2016ZIP - Unelevatedubuntu22 TARmariner ARM64macOS TAR,macOSlinux ARM32debian12azurelinux30First failing build:
ReleaseAutomationTest-27557-ps-671171.These tests were previously tracked as Case 2 of issue #27343 and are split out here because the root cause is unrelated to PR #27305 (the original framing of #27343).
Background: what PR #26565 changed
Commit
592668bd0rewroteModuleIntrinsics.GetModulePathand replaced the helperAddToPath(withPathContainsSubstring) withUpdatePath, which usesHashSet<string>plusPath.TrimEndingDirectorySeparatorfor dedup and advancesinsertPositionafter each insert. It also added a staticstatic ModuleIntrinsics() { SetModulePath(); }initializer.The "EVT.Process exists" branch in preview.1's
GetModulePathis:When
hklmMachineModulePathis non-empty,systemModulePathToUse = hklmMachineModulePathandpsHomeModulePath(i.e.,$PSHOME/Modules) is never added to the processPSModulePath. The same logical branch exists on Linux/macOS via the equivalent OS-level system module path.PR #26565 also added the new test
Verify PowerShell PSModulePath should contain paths from config file(test 103778 / 103842) that asserts$PSHOME/Modulesis already present atIndexOf > 0in$env:PSModulePath. That assertion is incompatible with portable distributions where$PSHOMEis a user-local path not registered in the OS-levelPSModulePath.Why each test fails
Tests 103778 (Windows) and 103842 (non-Windows)
Failure mechanics on a portable distribution:
$env:PSModulePath=<personal><sep><shared><sep><OS-defaults>and does not contain the ZIP/TAR-extracted$PSHOME/Modules.PSModulePathis read ashkcuUserModulePath = "$PSHOME/Modules<sep>$TestDrive/NonExist".GetModulePath"Process exists" branch setspersonalModulePathToUse = hkcuUserModulePath.UpdatePath(current, "$PSHOME/Modules<sep>$TestDrive/NonExist", ref insertIndex=0):$PSHOME/Modulesis NOT ininitialPaths-> inserted at position 0.$TestDrive/NonExistis NOT ininitialPaths-> inserted at position 1.PSModulePathstarts with$PSHOME/Modules<sep>$TestDrive/NonExist<sep>....IndexOf("$PSHOME/Modules<sep>")=0->Should -BeGreaterThan 0fails.StartsWith("$TestDrive/NonExist<sep>")=false-> later assertion also fails.The
BeforeAllcomment in the test literally states: "$mPath1 already exists in the value of env PSModulePath, so it won''t be added again." That precondition does not hold on portable distributions. Since theItblock is shared across platforms, it manifests as test 103778 on Windows lanes and 103842 on non-Windows lanes.Test 108309
Same root assumption - the test requires
$PSHOME/Modulesto be in$env:PSModulePath. On portable distributions this is not guaranteed.This test is 7+ years old. It is reported as a "New Failure" by the comparator because it likely passed on the rc.1 baseline (rc.1 uses the older
AddToPathpath-construction code which had different ordering/dedup semantics) and now fails on preview.1 after PR #26565. Open verification item: confirm the rc.1ReleaseAutomationTestresult for 108309 on each affected lane.Passedon rc.1 -> PR Refactor the module path construction code to make it more robust and easier to maintain #26565 changed the effectivePSModulePathshape; this is also a real product-side behavior change and may warrant a product fix in addition to the test fix.Failed/Skipped/NotExecutedon rc.1 -> comparator artifact only; just apply the test fix.Suggested resolution
Test side (required regardless): make the assertions portable-distribution-aware.
For tests 103778 / 103842 (
test/powershell/Host/ConsoleHost.Tests.ps1):Option A - have
BeforeAllensure the precondition the test was written against:BeforeAll { $CustomSettingsFile = Join-Path -Path $TestDrive -ChildPath 'powershell.test.json' $mPath1 = Join-Path $PSHOME 'Modules' $mPath2 = Join-Path $TestDrive 'NonExist' $pathSep = [System.IO.Path]::PathSeparator # Test assumes $PSHOME/Modules is already in $env:PSModulePath. # On ZIP/TAR/portable distributions this may not hold; ensure it. $contains = $env:PSModulePath -split [regex]::Escape($pathSep) | Where-Object { [string]::Equals($_, $mPath1, 'OrdinalIgnoreCase') } if (-not $contains) { $script:savedPSModulePath = $env:PSModulePath $env:PSModulePath = "$mPath1$pathSep$env:PSModulePath" } $ModulePath = "${mPath1}${pathSep}${mPath2}".Replace(''\'', "\\") Set-Content -Path $CustomSettingsfile -Value "{`"Microsoft.PowerShell:ExecutionPolicy`":`"Unrestricted`", `"PSModulePath`": `"$ModulePath`" }" -ErrorAction Stop } AfterAll { if ($script:savedPSModulePath) { $env:PSModulePath = $script:savedPSModulePath } }Option B - skip when the precondition does not hold:
For test 108309 (
test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1):Product side (only if 108309 was
Passedon rc.1): investigate whether theAddToPath->UpdatePathrewrite in PR #26565 changed the effectivePSModulePathshape on portable distributions and, if so, restore the previous behavior or explicitly addpsHomeModulePathto the system path even when HKLM (or its OS-level equivalent) is non-empty.Branch strategy
Per
.github/instructions/code-review-branch-strategy.instructions.md: PR #26565 is onmasterand onrelease/v7.7.0-preview.1. Fix the test files onmasterfirst; backport to release branches as needed. Do not add ZIP/TAR-specific workarounds only on the release branch.Files affected
test/powershell/Host/ConsoleHost.Tests.ps1(lines 391-413) - tests 103778 / 103842test/powershell/Modules/Microsoft.PowerShell.Core/CompatiblePSEditions.Module.Tests.ps1(line 727) - test 108309src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs- product-side, only if 108309 regression on rc.1 is confirmedRelated
592668bd0); not inv7.6.0-rc.1ReleaseAutomationTest-27557-ps-671171