2

I can create a user environment variable within a Powershell script (Windows 10) easily.

[System.Environment]::SetEnvironmentVariable('name', 'value', 'User')

When the variable should contain another user environment variable like %OTHERVAR%;static_part, I found that the type must be ExpandString. This can be done as follows

Set-ItemProperty HKCU:\Environment 'name' 'value' -Type ExpandString

So, I wrote the following code

[System.Environment]::SetEnvironmentVariable('M2_HOME', 'C:\dev\app\apache-maven-3.3.9', 'User')
# special treatment to get expandable type
Set-ItemProperty HKCU:\Environment 'PATH' '%M2_HOME%\bin;C:\Users\UID20852\AppData\Local\Microsoft\WindowsApps;' -Type ExpandString

Write-Host ([System.Environment]::GetEnvironmentVariable('M2_HOME', 'User'))
Write-Host ([System.Environment]::GetEnvironmentVariable('PATH', 'User'))
Write-Host 

Output:

C:\dev\app\apache-maven-3.3.9
C:\dev\app\apache-maven-3.3.9\bin;C:\Users\UID20852\AppData\Local\Microsoft\WindowsApps;

Everything is looking fine, both variables exist. When I open the Windows control to edit the user environment variables, I see both variables and the value of PATH is expanded. Even in regedit I see the type of the variables is correct.

However, when I open a new cmd and try to run a binary from %M2_HOME%\bin (should be on the PATH now), it fails.

To resolve the problem manually I just need to open the Windows control to edit the user environment variables, double-click the PATH variable, edit nothing, and close it again (I guess it re-writes it).

Then, in a new cmd, I can then run binaries from %M2_HOME%\bin.

Any ideas how I can make this PATH variable work just through the script?

5
  • 2
    Move [System.Environment]::SetEnvironmentVariable ... after Set-ItemProperty HKCU:\Environment ... Commented May 30, 2018 at 15:04
  • Why aren't you just editing the path environment variable in the way you're creating M2_HOME? Commented May 30, 2018 at 15:05
  • Hi @PetSerAl. Your answer works perfectly, thanks a lot. Have you got an explanation why that actually works in contrast to my version? Commented May 31, 2018 at 8:45
  • 1
    SetEnvironmentVariable not only update registry by also send notification about it, thus any interested application (for example explorer.exe) can know that them need to reread registry values. Also, AFAIK, there is no established order of user variables initialization, so dependency between per-user variables is not really supported. Commented May 31, 2018 at 20:27
  • @TheIncorrigible1: Because then it is not of type ExpandString and it does not work as expected because the %...% placeholder is taken literally and not as placeholder Commented Jun 6, 2018 at 14:51

2 Answers 2

1

Kudos to @PetSerAl. His answer to first prefix the PATH variable with the placeholder string and then create the environment variable that fulfils the placeholder afterwards works perfectly.

# special treatment to get expandable type
Set-ItemProperty HKCU:\Environment 'PATH' '%M2_HOME%\bin;C:\Users\UID20852\AppData\Local\Microsoft\WindowsApps;' -Type ExpandString
[System.Environment]::SetEnvironmentVariable('M2_HOME', 'C:\dev\app\apache-maven-3.3.9', 'User')

If I understand his explanation in the comments correct, because the creation of the "normal" variable fires an event that immediately updates the variable with the placeholder. So it works right after the script is done.

Sign up to request clarification or add additional context in comments.

Comments

0

Any program that use Environment.SetEnvironmentVariable() API, like PowerShell, broadcasts WM_SETTINGCHANGE that notifies system it needs to reload the environment. Then any new sessions can access the updated environment. This is not triggered when you use Set-ItemProperty only.

I strongly suggest the use of the free tool Rapid Environment Editor. Its command line covers any needs about Environment Variables management and its GUI will show every details at a glance.

Just be careful if you test its command line to NOT use -S parameter if you want to add a new value to an existent variable because it will override any previous values. Use -I or -A instead. And always use -C to avoid duplicate and invalid values. The -E parameter allow to use expandable variables.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.