Skip to content

Stop altering the PATH env variable by honoring the PSHome path in CommandDiscovery - #27757

Open
Dongbo Wang (daxian-dbw) wants to merge 8 commits into
PowerShell:masterfrom
daxian-dbw:env-path
Open

Stop altering the PATH env variable by honoring the PSHome path in CommandDiscovery#27757
Dongbo Wang (daxian-dbw) wants to merge 8 commits into
PowerShell:masterfrom
daxian-dbw:env-path

Conversation

@daxian-dbw

@daxian-dbw Dongbo Wang (daxian-dbw) commented Aug 3, 2026

Copy link
Copy Markdown
Member

Context

Altering the PATH env variable causes a problem to cmake-based build system when running in the MSIX PowerShell installation because they cache the location of PowerShell sometimes.

At startup, PowerShell adds $PSHOME to the beginning of PATH, and for MSIX installation, $PSHOME contains version numbers that change when PowerShell is updated.

When cmake is started from MSIX PowerShell, the path it caches will be that $PSHOME, which will become invalid after an update of the MSIX PowerShell.

PR Summary

The main change of this PR is to move the logic for ensuring the current PowerShell's executable directory ($PSHOME) is prioritized in command lookup from prepend it to PATH at startup to the CommandDiscovery process itself. This results in a more accurate and less intrusive handling of PATH. The PR also improves test coverage for these scenarios.

Refactoring of PATH handling:

  • The logic for prepending PSHOME to the PATH environment variable is removed from ConsoleHost.cs, so PowerShell no longer alters PATH during startup.
  • The logic to ensure PSHOME is always the first lookup directory is now implemented in CommandDiscovery.cs within the GetLookupDirectoryPaths method, regardless of the state of the PATH variable. This includes handling cases where PATH is unset and expanding ~ to the user home directory.
  • Skip the duplicate path of _psHome when constructing _cachedLookupPaths.

Code cleanup and caching improvements:

  • Removed the _cachedPath field and streamlined the caching logic for lookup paths in CommandDiscovery.cs.

Test updates:

  • Updated and added tests in ConsoleHost.Tests.ps1 to verify that running pwsh always starts the current version and that PATH remains unaltered during startup, including when PATH is unset.

PR Checklist

@daxian-dbw
Dongbo Wang (daxian-dbw) requested a review from a team as a code owner August 3, 2026 21:56
Copilot AI review requested due to automatic review settings August 3, 2026 21:56
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR stops PowerShell from modifying the PATH environment variable at startup and instead ensures the current PowerShell installation directory ($PSHOME) is prioritized during command lookup inside CommandDiscovery, addressing issues with tools (e.g., CMake) caching an MSIX-versioned pwsh path. It also updates/extends tests to validate pwsh resolution and behavior when PATH is unset.

Changes:

  • Removed startup-time PATH mutation from ConsoleHost.
  • Updated CommandDiscovery.GetLookupDirectoryPaths() to always prioritize the current pwsh location (including global tool path correction) without editing PATH.
  • Updated Pester tests to validate pwsh version resolution and that startup does not populate PATH when it is unset.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs Removes logic that prepended $PSHOME to PATH during startup.
src/System.Management.Automation/engine/CommandDiscovery.cs Prioritizes $PSHOME in lookup paths and streamlines path caching/tilde expansion.
test/powershell/Host/ConsoleHost.Tests.ps1 Adjusts/adds tests for pwsh resolution and verifies PATH remains unaltered when unset.

Comment thread test/powershell/Host/ConsoleHost.Tests.ps1 Outdated
Comment thread test/powershell/Host/ConsoleHost.Tests.ps1
Comment thread test/powershell/Host/ConsoleHost.Tests.ps1 Outdated
Comment thread src/System.Management.Automation/engine/CommandDiscovery.cs Outdated
@daxian-dbw Dongbo Wang (daxian-dbw) added the CL-Engine Indicates that a PR should be marked as an engine change in the Change Log label Aug 3, 2026
if (!isPathCacheValid)
{
// Reset the cached lookup paths
_pathCacheKey = null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Is isPathCacheValid evaluated correctly now?
  2. If we evaluate _psHome only for saving in _cachedLookupPaths why do we save it permanently in field?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For 1, I think it's correct now.
For 2, _cachedLookupPaths will be invalidated and reconstructed when the PATH env var is changed, but we don't want to recalculate _psHome in that case.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For 2, the question is rather what if we search for pshome throughout the source code, there is more than one place where it is used according to the old pattern. I.e., I would expect that pshome should be cached in Utils.DefaultPowerShellAppBase, taking into account regular, dotnet tool and hosted scenarios.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed the _psHome variable to _psExeHome to differentiate it from the $PSHOME concept.

_psExeHome is the directory that contains the pwsh executable, which is not necessarily under $PSHOME. For example, the built-in pwsh in the .NET SDK docker container image is located at C:\Program Files\powershell for Windows Server Core, and $PSHOME\pwsh.exe doesn't exist.

The only place I plan to update next is the PwshExePath in PowerShellProcessInstance. The current code is incorrect. I plan to reuse what I have here in the CommandDiscovery, in a separate PR.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Perhaps the best thing that could be done is to have a common code for each scenario somewhere in Utils. (Actually, it was originally like that once.)

@jshigetomi

Justin Chung (jshigetomi) commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Would this effect embedded pwsh runspaces and their command discovery look up order? For embedded pwsh, I believe the location of SMA.dll would be the pshome that gets prepended to the path by command discovery.

Any name collision in that SMA.dll location would be unintended. I can't imagine this happening often.

@daxian-dbw

Dongbo Wang (daxian-dbw) commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

That's a good point Justin Chung (@jshigetomi). Let me think about the impact to the applications that host PowerShell using the NuGet packages.

@daxian-dbw

Copy link
Copy Markdown
Member Author

Justin Chung (@jshigetomi) I've updated the changes to take into account the "PowerShell hosted by application via NuGet packages" scenario. In that case, we will use the PATH as is. Can you please review again?

@jshigetomi Justin Chung (jshigetomi) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment thread src/System.Management.Automation/engine/CommandDiscovery.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-Engine Indicates that a PR should be marked as an engine change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants