Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change a environment variable in PowerShell and launch an application

In PowerShell, I need to change the system path variable:

$oldPath = [System.Environment]::GetEnvironmentVariable('Path', 'Machine')
[System.Environment]::SetEnvironmentVariable('Path', (Transform-It $oldPath), 'Machine')

And then launch a program:

& $someExeName 'someargument'

The problem I am getting is that the executable is using the old environment. It doesn't recognize the new path. If I also change $env.path, to change the path only for this PowerShell session, it also does not propagate to the new process. If I close PowerShell and launch the executable in a new window, it's fine. Presumably it's inheriting the (non-updated) environment from the PowerShell process.

What is the best practice for changing an environment variable in PowerShell, and having it recognized by new processes launched from that window?

like image 781
Craig Celeste Avatar asked Dec 26 '22 10:12

Craig Celeste


1 Answers

In general, child processes inherit the environment from the parent process*. If you spawn a new PowerShell session from an existing PowerShell session, the new session will inherit the environment variables from that session (but no other variables).

However, the Path variable is an exception that causes a lot of confusion: Even though it's an environment variable, new PowerShell sessions read its value from the registry key HKLM:\System\CurrentControlSet\Control\Session Manager\Environment, overriding the value inherited from a parent session.

  • This behavior is specific to the Path variable. Other environment variables are inherited from the parent session regardless of whether they were defined only in the parent session or are stored in the aforementioned registry key.

  • This behavior is also specific to PowerShell.

    » If you change Path in a PowerShell session, but not in the registry, and spawn a new PowerShell session (e.g. with start powershell), the new session will have the path from the registry, but if you spawn a cmd session, the new session will have the path from the PowerShell session that spawned it.

    » Likewise, if you change Path in a cmd session (with set Path=New Path) and spawn a PowerShell session, the new session will have the path from the registry, but if you spawn a cmd session, it will have the changed path from the parent cmd session.

    » The default behavior is to inherit the path (along with the rest of the environment) from the parent process (as cmd does). However, it's quite possible that some other programs behave in a similar fashion to PowerShell, overriding the inherited value with the registry value. This behavior is not common, but the possibility can't be ruled out that this happens with your executable.

The following commands change Path in the current session, and not in the registry:

$env:Path = 'New path'

[System.Environment]::SetEnvironmentVariable('Path', 'New Path', 'Process')


The following commands change Path in the registry, and not in the current session:

Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' -Name 'Path' -Value 'New Path'

[System.Environment]::SetEnvironmentVariable('Path', 'New Path', 'Machine')

What you're describing doesn't make sense to me, because you say that you've tried one method that changes the path in the registry, and one that changes the path in the PowerShell session, and that the executable you're spawning doesn't have the changed path either way. AFAIK the original environment isn't cached anywhere, and the child process has to be getting the path from either the parent process's environment or the registry.

What I suggest it to make absolutely sure you've changed the path both ways before launching the executable:

  1. Open a PowerShell session
  2. Change the path using one of the methods that changes it in the session
  3. Change the path using one of the methods that changes it in the registry
  4. Launch the executable

If for some inexplicable reason that doesn't work, try this:

  1. Open a PowerShell session
  2. Change the path using one of the methods that changes it in the registry
  3. Rather than launching the executable directly from that PowerShell session, execute this command

    powershell "& $someExeName 'someargument'"
    

    to have the executable launched by a new but non-interactive PowerShell session that will read the Path environment variable from the registry.


* Note that the inheritance of the environment is the only relationship between parent and child processes in Windows. Other than that they're completely independent (there's no hierarchy as there is in Unix and Linux).

like image 128
Adi Inbar Avatar answered Jan 05 '23 18:01

Adi Inbar