8

I am tweaking the PATH on several W2k3 servers in PowerShell to convert certain paths with blank spaces to their 8.3 equivalents. After several regex transformations, I run the following two commands:

# Set the path for this process
$env:PATH = $path
# Set the path for the Machine
[System.Environment]::SetEnvironmentVariable('PATH', $path,[System.EnvironmentVariableTarget]::Machine) 

After running them, the path is changed in ways I didn't intend. %SystemRoot% is uniformly expanded to C:\Windows. I can't see where this signals the apocalypse, but I'd rather keep the %SystemRoot%, so I fiddled until I got %SystemRoot% to appear in the path again, but when I do the path no longer expands and no longer works. Echoing the path at the CLI returns an unexpanded string (this is wrong) and commands in the SystemRoot can no longer be found.

If I then add a null entry to the Path ";;", without altering any other text in the PATH, it begins to work correctly.

So my question is how to alter the path programmatically using PowerShell so as not to muck up variable expansion within the path?

4
  • 2 notes: 1) I do open a new CLI for each test, and 2) the path I read from $env:PATH is expanded, so I'm reading c:\windows and manually changing the value to %SystemRoot% then pushing that value back to the environment. Commented Jan 23, 2012 at 16:55
  • What is there in $path when you are setting it to PATH? Commented Jan 23, 2012 at 17:01
  • It's different on every server, but ...;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SystemRoot%\system32\WindowsPowerShell\v1.0;... is a component on all of them. When I read $path, it's expanded to c:\Windows during the read proces. I have to -ireplace the expanded value with its variable equivalent before setting it. That $path value with variables will not then expand again unless I manually touch it through the properties dialog. Commented Jan 23, 2012 at 18:05
  • This can have painful effects if you're using %USERPROFILE%. Commented May 22, 2023 at 21:28

1 Answer 1

10

As far as I can tell, you can't do this with the [Environment]::SetEnvironmentVariable() method and you can't do this with the Registry provider. However you can access the system Path env var in the registry using the Microsoft.Win32.RegistryKey class like so:

C:\PS> $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', $true)
C:\PS> $path = $key.GetValue('Path',$null,'DoNotExpandEnvironmentNames')
C:\PS> $path
...;%systemroot%\System32\WindowsPowerShell\v1.0\
C:\PS> $key.SetValue('Path', $path + ';%Windir%\Symbols', 'ExpandString')
C:\PS> $key.Dispose()

This will allow you to save the updated PATH and preserve the variables that appear in the Path value.

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

7 Comments

Fabulous, Keith. Thank you again.
FYI, the script should probably be put in a try/finally and inside the finally do a Dispose on the registry key.
You know, I almost asked about this, but since my script is short and every variable goes away immediately, I didn't sweat it. But since you brought it up. :-) .NET 4.0 includes the manual Dispose() method you call, but 2.0 does not. How should I dispose of the key without a Dispose() method?
In .NET 2.0, use the Close() method.
Can you expand on this for User Path and System Path? I assume the one that you have shown here is the System Path and not the User Path.
|

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.