Reputation: 606
I have a C# application that when run sets some environment variables. These environment variables need to be set system wide.
I use this code to actually do the set.
public static void SetEnvironmentVariable(string _keyName, string _value, RegistryValueKind _type)
{
using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true))
{
if (reg != null)
{
reg.SetValue(_keyName, _value, _type);
}
else
{
string x =
string.Format(
"Could find registry key that hosts Environment Variables: SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment");
App.AppLogger.Error(x);
throw new Exception(x);
}
}
}
This code works, but I notice some strange behavior. Immediately after running my app and this code, I run cmd as a regular user and take a look a the environment using the "set" command. It shows no changes.
I then run a cmd prompt as admin and run set. It shows the changes. Not only that, it shows fully expanded variables. Where ALLFOO=Foo, and PATH=C:\Windows\System32;%ALLFOO%;, the set command shows PATH=C:\Windows\System32;Foo;.
I then log off and back on. I then run cmd as a normal user. I type set and it shows the new environment variables, but not expanded. It shows PATH=C:\Windows\System32;%ALLFOO%; ( It seems to have no trouble expanding %SYSTEMROOT% for some reason.)
I get that the log-off and back on causes the new Explorer.exe that's launched to get the new env vars for the regular user's cmd.exe, but I don't understand why they are not expanded.
Why would running cmd and set as administrator show fully expanded environment variables and running cmd and set as a normal user would not?
When setting the env vars in the C# program i use the RegistryValueKind.ExpandString enumeration.
Edit: I am aware of the order of declaration time to expansion time issue with system variables and have edited the question example to reflect this.
Upvotes: 0
Views: 1338
Reputation: 70943
Changes to the environment variables are not inmediatly visible. You need to notify the running processes of changes to the registry.
And, you should remember that the environment you see in a process (your cmd
windows) is not readed from the registry, it is inherited from its parent process. You can send the notification, but some processes will handle it and some not.
The rest of the problems should be explained by the environment load order:
Some values are retrieved from the registry before processing the environment itself. %systemroot%
is defined in
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot
System environment is loaded
REG_SZ
variables, in alphabetic order, are readed firstREG_EXPAND_SZ
, in alphabetic order, are readed. As the REG_SZ
values have been readed, they can be expanded. If a REG_EXPAND_SZ
variable makes reference to another REG_EXPAND_SZ
variable that still has not been expanded (alphabetic order), this reference can not be resolved and is not expanded.REG_SZ
, then REG_EXPAND_SZ
variable are processed.PATH
) where the values are concatenated.All that means that
Different users can and probably will see different environments
Same user can see different environments depending on what the parent process is. It is not the same to use Win+R and execute cmd
than to use Shift+right click in a folder and select "Open command here". Parent processes are different.
Upvotes: 1