I use VSCode Anytime I install a python library, I get this notification:
WARNING: The scripts auto-py-to-exe.exe and autopytoexe.exe are installed in 'C:\Users\PC\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\Scripts' which is not on PATH
But I've added that to path. If I run:
echo $env:PATH
I get
C:\Users\PC\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\Scripts:C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Users\PC\AppData\Local\Microsoft\WindowsApps;C:\Users\PC\AppData\Local\Programs\Microsoft VS Code\bin;C:\texlive\2023\bin\windows
suggesting that I've added said path.
I'm confused because I can't run packages from the CLI directly, even though importing them works.
I added the path manually and I've tried removing it but that doesn't work. Any ideas on what to do?
Your own solution is effective in principle - ;
is the required separator on Windows - except that your statement isn't valid PowerShell code, and that \
chars. don't need escaping as \\
in PowerShell; also, you can express the new directory path more generically using the LOCALAPPDATA
environment variable; therefore:
$newDir = "$env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\Scripts"
$env:PATH = "$newDir;$env:PATH"
The above modifies $env:PATH
only for the current session (process).
To also persist this change on Windows - so that future sessions see it too:
Interactively, run sysmd.cpl
, select the Advanced
tab, and click on Environment Variables...
, then add the value of $newDir
to the desired scope; since your directory path is user-specific, add it to the User variables for <username>
list.
Programmatically, this is surprisingly difficult to do robustly:
If you don't mind converting the original REG_EXPAND_SZ
definition to a static REG_SZ
one, you can use [Environment]::SetEnvironmentVariable()
(to target the machine-level definition of the variable, change 'User'
to 'Machine'
, but not that doing so requires elevation (running as administrator):
[Environment]::SetEnvironmentVariable(
'PATH',
($newDir + ';' + [Environment]::GetEnvironmentVariable('PATH', 'User')),
'User'
)
While this typically has no ill effects, it can; see this answer for background information and a robust alternative; this answer wraps the robust alternative in a helper function, Add-Path
, and explains why setx.exe
should be avoided for PATH
updates.
A simpler programmatic alternative, which also works on Unix-like platforms, is to add the above statements to your $PROFILE
file, but note that only PowerShell sessions and programs launched from them will then see the updated PATH
, and that profile-loading can be suppressed by launching a PowerShell session via the -NoProfile
CLI parameter (the PowerShell CLI (powershell.exe -NoProfile
for Windows PowerShell, pwsh -NoProfile
for PowerShell (Core) 7+)
Note that .NET cannot offer APIs for persistent environment-variable definitions on Unix-like platforms, because there's no unified mechanism across all of them.
PATH
environment variable:The platform-specific separator used in the list of directory paths stored in the special PATH
environment variable is:
;
on Windows:
on Unix-like platformsIn cross-platform scripting, make changes to PATH
as follows in PowerShell:
Use $env:PATH
- all uppercase - because environment-variable access is case-sensitive on Unix-like platforms, and the special variable's name is indeed PATH
there.
Path
, but because environment-variable access is case-insensitive, any case variation and therefore also PATH
works.Use the - confusingly named - [System.IO.Path]::PathSeparator
property to get the platform-native separator.
In forming directory paths to add, use the platform-native file-system path separator, which .NET reflects in the - equally unfortunately named - [System.IO.Path]::DirectorySeparatorChar
property.
PowerShell's Join-Path
cmdlet and .NET's [System.IO.Path]::Combine()
method, when given components of a path, implicitly use the platform-native separator, which is \
on Windows, and /
on Unix-like platforms.
\
has no special meaning in PowerShell (and neither in cmd.exe
) so there is no need to represent literal \
characters as \\
(however, in the context of file-system paths, such accidentally duplicated separators are generally still accepted).On Windows, you could alternatively use /
as well, which is safe to use in the context of PATH
as well as PowerShell-native commands.
.NET reflects this fact via the [System.IO.Path]::AltDirectorySeparatorChar
property
However, programs / scripts examining $env:PATH
for existing entries are likely to assume \
, so it's best to use the platform-native separator.
Also, generally speaking, there are still Windows contexts where /
doesn't work, such as in cmd.exe
and COM APIs.
Generally, aim to express your directory paths in terms of environment / well-known directories, to be resolved to literals paths at the time of adding entries:
E.g., the C:\Users\PC\AppData\Local
part of your path could be replaced with environment variable $env:LOCALAPPDATA
However, for cross-platform use it's best to use platform-agnostic abstractions, as provided - within limits - by [System.Environment]::GetFolderPath()
E.g., the platform-agnostic equivalent of the above is:
[Environment]::GetFolderPath('LocalApplicationData')
Since use of [System.Environment]::GetFolderPath()
isn't very PowerShell-friendly, GitHub issue #6966 asks for surfacing known folders platform-agnostically via a separate namespace / provider, e.g. $sf:LocalApplicationData
(sf
standing for special folder).