Skip to content

PATH update for tool installation using package managers like WinGet and Chocolatey #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

daxian-dbw
Copy link
Member

On Windows, when a user installs a tool using a package manager like WinGet or Chocolatey in PowerShell, the tool is often added to the system or user PATH environment variable. However, changes to PATH made during the installation process are not automatically propagated to running PowerShell sessions or other active console applications. As a result, users frequently need to
start a new PowerShell session to recognize and use the newly installed command-line tools.

This behavior can be confusing and disrupts the workflow—especially in automation scenarios or when users expect tools to be immediately available post-installation. Addressing this limitation would improve usability, align with user expectations, and reduce friction in both interactive and scripted environments.

- **_[WT comments]_** CMD only covers EXE, but `scoop` is a `.ps1` or `.bat` file, so CMD doesn't see it. PowerShell may want to broaden your support to account for any command.
- [dongbow && jason]'s thoughts on this comment
- [Scoop](https://scoop.sh/) creates shims inside the `~\scoop\shims` folder for terminal applications, which is accessible in the PATH. So `Scoop` doesn't need PATH refreshing.
- We should scope the work to native command only. Supporting non-native commands would need broader changes outside of the native command processor without a clear gain.

Choose a reason for hiding this comment

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

WinGet has a PS module, which is recommended by that team as the preferred mechanism for script use. This would introduce the caveat that if you wish to immediately use the installed item in your script, you should instead invoke winget.exe and need to handle its complex output (although directly using its DSCv3 resources could make things easier).

Naively it would seem that an attribute on cmdlets could solve this cleanly.

I assume that listening to the appropriate broadcast window messages and registry watchers were both considered for indirect monitoring schemes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point! We will think about how to handle package installation using Microsoft.WinGet.Client.

I assume that listening to the appropriate broadcast window messages and registry watchers were both considered for indirect monitoring schemes?

I believe Windows broadcasts the message WM_SETTINGCHANGE for environment variable changes only if the changes are done via the GUI (settings -> edit env variables), and console application cannot receive the broadcast because there is no message loop.

We indeed can monitor the registry changes (HKEY_CURRENT_USER\Environment and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) using RegNotifyChangeKeyValue. However, we don't want to update the process-scope Path blindly, but rather only update the process-scope Path after execution of the package manager.

Copy link
Contributor

Choose a reason for hiding this comment

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

we don't want to update the process-scope Path blindly,

There can be a race condition: while a package manager are working another process can change HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment.

Choose a reason for hiding this comment

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

I believe Windows broadcasts the message WM_SETTINGCHANGE for environment variable changes only if the changes are done via the GUI (settings -> edit env variables), and console application cannot receive the broadcast because there is no message loop.

I believe that anyone can send the message, but whether it is done so broadly by installers after updating the PATH variable(s) is a different question. There is also an opportunity for a package manager to pave the crack here, sending the message when the installer does not. Or to provide an incentive for installer technologies to "do the right thing" here.

Any process can create a window with a message handler; a console process would simply mark it as not shown and not need to handle many messages.

However, we don't want to update the process-scope Path blindly, but rather only update the process-scope Path after execution of the package manager.

I don't understand why though. I can understand not changing it while a command is processing, but any time the PS pipeline has control of execution seems reasonably safe.

As proposed, this change already introduces a potential update to the environment variable after an arbitrary set of native commands. Expanding that to "this environment variable is volatile (may change at any time)" doesn't seem like a big leap.

Copy link
Member Author

Choose a reason for hiding this comment

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

The PowerShell team discussed about the concerns brought up in this thread

  • The PowerShell module Microsoft.WinGet.Client, which provides cmdlets for installing packages
  • Monitor all changes to the env var PATH

The conclusion is:

  1. For a PowerShell module that installs packages through APIs instead of wrapping a package manager executable, the modules itself should handle refreshing the in-proc env var PATH.
  2. Changing the in-proc PATH value whenever user/system PATH gets changed is too risky. We will stick to the plan and only refresh the in-proc PATH value for package manager execution.

Choose a reason for hiding this comment

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

  1. For a PowerShell module that installs packages through APIs instead of wrapping a package manager executable, the modules itself should handle refreshing the in-proc env var PATH.

Please make the refresh mechanism available to be called by other modules (or the user for that matter). That way we get a consistent reload behavior and the only question is "when?".

Copy link
Member Author

@daxian-dbw daxian-dbw Aug 6, 2025

Choose a reason for hiding this comment

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

The PowerShell team in fact discussed about exposing an API for refreshing the in-proc PATH.
For package manager executables, we will

  • get the user/system PATH values before calling
  • get the values again after calling
  • compare the 2 paths and only update the in-proc PATH with entries newly prepended or appended.

So, the API would require the caller to pass in the original user/system PATH values, which feels weird but may be fine.
Be noted that, a new API will only be available in the latest version of PowerShell (e.g. v7.6+), so for a module that support Windows PowerShell v5.1 (or v7.4 and 7.5 which are still in support), it still needs to implement the logic in the module.

Exposing the API is currently considered out of scope for this RFC, but we will work closely with the owner team of Microsoft.WinGet.Client and see their feedback.

Choose a reason for hiding this comment

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

Exposing the API is currently considered out of scope for this RFC, but we will work closely with the owner team of Microsoft.WinGet.Client and see their feedback.

Good, because that is me :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants