-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Start-Process -UseNewEnvironment provides an environment that is missing crucial standard environment variables while not supporting passing a new environment #4671
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
Comments
On Windows, you should use There is another issue on |
To provide some more insight into what, specifically, is wrong (in addition to the conceptual flaw that @GeeLaw mentions with respect to combining PowerShell/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs Lines 1867 to 1872 in 5fcab21
On Unix-like platforms, the In short, As for Windows:
PowerShell/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs Line 1869 in 5fcab21
and then only restoring those variables whose definitions are registry-based.
PowerShell/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs Line 2077 in 5fcab21
For the record, here are the built-in, system-defined environment variables that are not registry-based:
Command that generated the list above (with the exception of USERNAME) gci env: | % name | ? { -not [environment]::GetEnvironmentVariable($_, 'Machine') -and -not [environment]::GetEnvironmentVariable($_, 'User')} |
I'd deprecate UseNewEnvironment (make alias?) and introduce ClearEnvironment |
On GitHub, there's a small amount of usage of -UseNewEnvironment. I believe the intent of this switch is you would start a process from PowerShell as though you just started a new PowerShell process (not from the current PowerShell process). We just have to evaluate if we would break any existing usage (seems unlikely). As for specifying an environment, I think |
Agreed re intent, @SteveL-MSFT, so if we wanted to fix this feature (and also make it work on Unix), we could cache a copy of the environment-variable block on PowerShell startup (before reading profiles), and use that. @iSazonov: I agree that
|
I think really we need three operation:
UseNewEnvironment we could deprecate and hide. |
I don't think there is a need for this complexity: Re 1 and 2: You rarely want to start with no environment variables at all - you'll wipe out vital OS-defined variables too (which is the current problem on Unix-like platforms). It is far more common to build on an existing environment, either:
Re 3: Combining the hashtable As a user, I then:
The first 2 modifications are most common, but a single, hashtable-based environment variable also supports removing variables, given that assigning |
Historically environment variables is manipulated by one "Set" operation, even in C# API https://docs.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable?view=netframework-4.8#System_Environment_SetEnvironmentVariable_System_String_System_String_ CommandType Name
----------- ----
Cmdlet Clear-Variable
Cmdlet Get-Variable
Cmdlet New-Variable
Cmdlet Remove-Variable
Cmdlet Set-Variable Earlier we actively discussed Environment provider/drive. We found this very interesting. Obviously the API will has these operations explicitly. Should we keep consistency with the API in the issue too (also taking in account hosting scenario)? I do not like changing
|
The However, extending the I don't see a problem with having that coexist with the
Nothing meaningful can be broken, given the currently useless behavior.
I think the name is fine, but we could implement an alias, if there's consensus on a better name.
That is a valid concern - I can't speak to the real-world impact.
Personally, I won't miss the feature, but I can see how it is desirable in certain situations.
That's not the point, though. The point is that you yourself or third-party code may have modified the environment in multiple ways that you don't want external processes to see, lest it interfere with their proper operation. |
Interesting, has Windows or Unix an API to directly implement the scenario? (I mean this is too unbelievable scenario) |
Windows has Unix has the On closer examination, however, this appears to be more like a As a cross-platform shell, however, we'd be looking for standardized behavior, so IF we keep the switch, implementing the proposed behavior makes the most sense to me. Again, I personally wouldn't miss |
It seems |
@iSazonov: Well, like However, there's more going on, because Only with On both platforms, trying to launch |
This code is This code is somewhat confusing (in CoreFX too) 😕 This works in WSL (may be useful for tests): Start-Process -UseNewEnvironment -ArgumentList "set" bash |
We need to take in account #6489 Again slow down :-( This is not so important to start a process but it can be sensitive for startup scenario. |
As for the test command: You're missing Start-Process -UseNewEnvironment -ArgumentList '--norc', '-c', 'export' bash If you're experimenting with passing multiple commands to Start-Process -UseNewEnvironment -ArgumentList '--norc', '-c', '"export; set"' bash |
Also, I don't think we need to worry about #6489 for simply making a copy of the startup environment. As for the dictionary: are you referring to What |
Perhaps we can catch a problem if original set contains duplicate variables: we have to set them one-by-one and last will win. Although we use P/Invoke on Windows and this could allow to get around this.
It is not property in Process object. So we can use only [environment]::GetEnvironmentVariables().
It does not work for me on WSL. Folow works: I hope we can use this on all Unix-s and MacOs. |
Yes, |
I just discovered the
|
@mklement0 Thanks! I pulled PR - please review. |
Since we had PowerShell Committee conclusion in #10745 (comment) we can continue here to discuss a desired behavior. |
Thanks, @iSazonov; I think you meant to link to #10745 (comment) - given that specific points were made there, let me respond there. |
@iSazonov on Windows, the current code clears the env block, then fills it from the system profile (hence username is system) and then the user profile overwriting any that exist in the system. Hence Path is incomplete. It seems the fix here is to merge Path (append user PATH to end of machine PATH). USERNAME should be special cased to the user. The test is to start a new cmd.exe from Windows shell, run |
A slight;y different use case is for -UseNewEnvironment to use the default environment when somehting like the path has changed in another procerss. Specifically I'm using curl to download python and the script to initiate the install and want to start a shell with python on the path. My original script is windows cmd but as there was no way to do this I looked at PowerShell and got excited by -UseNewEnvironment, only to find it is broken as per this bug. I guess security might be a consideration though. PS I'm another Steve Lee :) |
@SteveL-MSFT Any updates on this issue? I see no changes related to |
I'll bring this up to the WG for discussion. I'm currently thinking maybe a completely new switch instead of reusing |
If we add |
@PowerShell/wg-powershell-cmdlets reviewed this and agreed with the asked behavior and a new switch to avoid any breaking change |
Not sure how far along this issue is, but a "common" (well the only one I ever came across) for this feature is to support a scenario where you run a program that changes the "global" environment (i.e. the registry entries) and then run another program that relies on these changes. The simplest example is a script that runs an installer and then wants to run the installed program right afterwards:
Which means that the "copy environment at the start of the process would not help, since this is not necessarily the same as the environment at the time the command is executed. On Windows at least I'd think that using |
On both Windows and Unix platforms,
Start-Process -UseNewEnvironment
results in an environment that is missing crucial standard environment variables, making the new environment virtually useless, while not providing a mechanism to define a new environment:On Windows,
-UseNewEnvironment
defines only the variables that are explicitly defined, as displayed in System Properties (sysdm.cpl
), with crucial, usually automatically defined variables such as$env:ProgramFiles
missing, and$env:USERNAME
unexpectedly containingSYSTEM
.powershell
instance from being started this way - see Start-Process fails to launch new powershell.exe instance with -UseNewEnvironment switch #3545 (comment) and below.On Unix, an empty environment is essentially passed (with no environment variables defined at all, except
$env:PSModulePath
).This even prevents invoking any executable by filename only, given that
$env:PATH
is undefined - see below.While this behavior is similar to POSIX
env -i
on Unix platforms, theenv
utility notably includes a mechanism to provide a new environment vianame=value
pairs, whichStart-Process
lacks.Possible solutions:
Repurpose
-UseNewEnvironment
to not start with a blank slate / crucial variables missing, but to provide the same environment that a shell would see when directly launched by the system (in other words: any environment-variable modifications made by the calling shell would be ignored).Additionally, provide a way to pass a custom environment, applied on top of the current or pristine (
-UseNewEnvironment
) environment:E.g., a new
-Environment <hashtable>
/-Environment <Collections.DictionaryEntry[]>
parameter could be used.If someone truly wanted an empty environment, they could start with
$emptyEnv = (Get-ChildItem env:); $emptyEnv | % { $_.Value = $null }
and pass-Environment $emptyEnv
.The
-Environment
feature would allow for an - incomplete - approximation of the convenient ad-hoc, command-scoped environment-variable definition feature that POSIX-like shells such asbash
offer, where you can prepend one or morename=value
pairs to a command:Update: #3316 suggests emulating this syntax in PowerShell, which would be the best solution.
The PS approximation would be:
That said, a crucial limitation is that use of
Start-Process
makes the external utility operate outside PowerShell's streams, so the only way to provide input / collect output is via the-Redirect*
parameters, which requires auxiliary files.Current behavior
-LoadUserProfile
makes no difference.$env:PSModulePath
as the only environment variable - with a seemingly temporary user account's module directory prepended - and thewhoami
invocation fails, because it cannot be located in the absence of a suitable$env:PATH
.Environment data
The text was updated successfully, but these errors were encountered: