0

I have a folder that I want to add to the PATH variable under Environment Variables (for the machine). I am appending the folder to the path via the registry setting. SYSTEM\CurrentControlSet\Control\Session Manager\Environment.

Here is a snippet of the code where I read the registry setting. And I perform a registry update on the setting, so nothing revolutionary.

String keyName = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\";
string existingPathFolderVariable = (string)Registry.LocalMachine.OpenSubKey(keyName).GetValue("PATH", "", RegistryValueOptions.DoNotExpandEnvironmentNames);
string keyValue = @"c:\MyPath\";
if ( !existingPathFolderVariable.Contains(keyValue) )
{
    if (!existingPathFolderVariable.EndsWith(";", StringComparison.InvariantCulture))
    {
        existingPathFolderVariable += ';';
    }
    Followed by code to update registry value, standard registry functions.
}

I tried various options of updating the registry including using powershell.

$oldpath = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).path 
$newpath = "$oldpath;c:\install\sysinternals"
Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath

(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path

Though the path is updated and the values look correct, the path is no longer valid. The commands under the System32 folder are no longer valid. If I perform a ping, I get the unknown command message. Same for ipconfig and other commands.

I read that I could use the SetEnvironmentVariable function. But I do not want the values expanded. If I copy the line, delete the line, and add the line via the registry setting or UI, the problem is resolved.

Any suggestions on how to resolve the problem?

  • when your path seems invalid - what is its contents – BugFinder Dec 09 '19 at 12:02
  • [Environment.SetEnvironmentVariable(String, String, EnvironmentVariableTarget)](https://learn.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable?view=netframework-4.8#System_Environment_SetEnvironmentVariable_System_String_System_String_System_EnvironmentVariableTarget_). This overload - when the Target is `EnvironmentVariableTarget.Machine` - also broadcasts `WM_SETTINGCHANGE`, so all other applications are notified of the change in the (Windows only) registry. – Jimi Dec 09 '19 at 12:30
  • @BugFinder The path contains the standard content, %SYSTEMROOT%, %SYSTEMROOT%\System32, and other folders. The end of the path contains my folder. – Al Pennyworth Dec 09 '19 at 14:27
  • @Jimi I should have mentioned that I am performing the old school sendmessage to notify all apps of the change. `SendNotifyMessage((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, (UIntPtr)0, "Environment");` – Al Pennyworth Dec 09 '19 at 14:28
  • Let the standard implementation do the work for you. It will also take care of the correct formatting and the encoding, not just to broadcast a notification. The Shell needs to be *informed* as well. – Jimi Dec 09 '19 at 14:31
  • @Jimi Won't the standard implementation expand the variables instead of leaving them as-is? – Al Pennyworth Dec 09 '19 at 16:29
  • No, it doesn't. The `value` is stored as you pass it to the method. You could just test it. – Jimi Dec 09 '19 at 16:35
  • `existingPathFolderVariable = String.Concat(existingPathFolderVariable, @"c:\MyPath\;"); Environment.SetEnvironmentVariable("Path", existingPathFolderVariable, EnvironmentVariableTarget.Machine);` Upon execution of the code, I received the error "'ipconfig' is not recognized as an internal or external command..." Same problem I encountered with update of the registry setting. – Al Pennyworth Dec 09 '19 at 17:34
  • You mean: `string currentPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); currentPath += ";" + yourExecutablePath; Environment.SetEnvironmentVariable("Path", currentPath, EnvironmentVariableTarget.Machine);`, if you want to add your executable to the current path in the `Machine` scope. – Jimi Dec 09 '19 at 19:17
  • I used the code from your response and it expanded the variables. The Path contains C:\Windows instead of %SYSTEMROOT%. So the path looks like `C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;c:\MyPath` – Al Pennyworth Dec 09 '19 at 19:52
  • https://stackoverflow.com/questions/19705401/how-to-set-system-environment-variable-in-c was the article I read that commented to use the registry. – Al Pennyworth Dec 09 '19 at 20:00
  • If you don't want the Environment variables expanded, call `Registry.OpenKey("Key To Open").GetValue("Path", string.Empty, RegistryValueOptions.DoNotExpandEnvironmentNames).ToString()`, then modify it and save it with `SetEnvironmentVariable`. This is the only managed way to not expand `REG_EXPAND_SZ` keys. I haven't checked whether .Net Core 3.x has corrected this problem. Will do. – Jimi Dec 09 '19 at 20:44
  • If you find that the result, after saving the new value, is different from what you expect, then dump the `Environment` thing and write the value with `[RegistryKey].SetValue("Path", newValue, RegistryValueKind.ExpandString)` – Jimi Dec 09 '19 at 20:51

0 Answers0