PowerShell Core doesn't inherit PSModulePath environment variable from the environment

Created on 10 May 2018  路  15Comments  路  Source: PowerShell/PowerShell

Windows PowerShell correctly inherits environment variables from the environment -- although it may add paths to these variables, it doesn't ignore the existing environment.

PowerShell Core sets the PSModulePath -- completely ignoring and overwriting the existing environment, including the default values set in the Windows System Properties control panel...

This makes PowerShell Core's PSModulepath basically impossible to manage, since it can only be set reliably in a machine profile script --which depend on the _install location_ of the shell, which changes with each release!!

Steps to reproduce

From Windows PowerShell run:

$Env:PSModulePath
pwsh -noprofile -command { $Env:PSModulePath }
pwsh -noprofile -command { powershell -noprofile -command { $Env:PSModulePath } }

From pwsh run:

$Env:PSModulePath
PowerShell -noprofile -command { $Env:PSModulePath }

Expected behavior

pwsh should respect it's environment.

Actual behavior

pwsh overwrites it's environment

Environment data

> $PSVersionTable
Name                           Value
----                           -----
PSVersion                      6.0.2
PSEdition                      Core
GitCommitId                    v6.0.2
OS                             Microsoft Windows 10.0.17134
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Breaking-Change Committee-Reviewed Resolution-Fixed WG-Engine

Most helpful comment

All 15 comments

There's explicit code clearing the variable

yes, but that code is based on the incorrect (or rather, outdated) assumptions that "The machine-wide and user-wide environment variables are only meaningful for full ps"

First of all, since PowerShell itself does not set those environment variables, there is no basis for this assumption. These are environment variables under the control of the user. You have no right to ignore them.

Second, as noted on #2636, many of the core modules _do_ work. You've even released a module predicated on the fact that this is, in fact, not true 馃槈

We can't on the one hand claim that many (or most) modules will just work, and on the other hand say that the environment variable is _so toxic_ that we can't trust users (and enterprises) to deal with it properly. Especially since this breaks all _reasonable_ expectations regarding environment variables.

Maybe we should have another environment variable $ENV:PSModulePathCore. On startup, if PowerShell Core sees this variable, it uses it otherwise it falls back to $ENV:PSModulePath. With two variables, then powershell can call pwsh and pwsh can call powershell and everything works. And eventually we can create a PowerShellCommon module directory for modules that work with both and that both variables include.

A separate $Env:PSCoreModulePath environment variable kind-of makes sense.

However, there are probably a lot of scripts and modules using $Env:PSModulePath ... I mean, at a minimum, people's profiles, and modules like PSDepend. Would you just read it and overwrite $Env:PSModulePath? Would that help?

Could we rely on the modules themselves setting CompatiblePSEditions, and let each version of PowerShell ignore modules that aren't compatible? (Actually, sure this wouldn't work, nevermind. Most of the modules that I'm concerned with are legacy modules which aren't going to be updated with CompatiblePSEdition any time soon, but which still work ... )

Bear in mind that in the _near future_, the more frustrating problem is _Windows PowerShell_. As new modules come out which take advantage of PowerShell Core functionality, Windows PowerShell won't be able to use them, and it _does_ inherit the environment variable, already.

I mean, at a minimum, people's profiles

There are different profiles for desktop and core. You have to expend effort to get them to share common code and work properly. (e.g. no loading winform assemblies in your Core profile). So you put edition-specific tweaks in the appropriate profile.

However, there are probably a lot of scripts and modules using $Env:PSModulePath

Most scripts and modules depend on the module path being set correctly for the PS edition they are using. With separate variables, by default they will only load modules from the module directories associated with their shell edition. For things that work directly with PSModulePath, they'll have to be updated to understand PowerShell Core.

Could we rely on the modules themselves setting CompatiblePSEditions, and let each version of PowerShell ignore modules that aren't compatible?

Without separate 'edition' directories, how do I have both "core" and "desktop" install paths for a given module/version? (Nuget does this with <package>/<version>/lib/<editionEquivalent> but that would require changing both Core and Windows Powershell so it is unlikely to happen.)

Bear in mind that in the near future, the more frustrating problem is Windows PowerShell. As new modules come out which take advantage of PowerShell Core functionality, Windows PowerShell won't be able to use them, and it does inherit the environment variable, already.

All the more reason to have separate module paths. I should be able to do

powershell {
    Get-ADComputer ...
}

from pwsh.exe and it should just work.

Was this page helpful?
0 / 5 - 0 ratings