Windows环境变量扩展:管理员与非管理员

时间:2017-02-21 20:48:14

标签: c# windows cmd registry

我有一个C#应用程序,在运行时设置一些环境变量。 这些环境变量需要在系统范围内设置。

我使用此代码实际执行该设置。

    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);
            }
        }
    }

此代码有效,但我注意到一些奇怪的行为。 运行我的应用程序和此代码后,我立即以常规用户身份运行cmd,并使用“set”命令查看环境。 它没有显示任何变化。

然后我以管理员身份运行cmd提示符并运行set。它显示了变化。不仅如此,它还显示了完全扩展的变量。其中ALLFOO = Foo,PATH = C:\ Windows \ System32;%ALLFOO%;, set命令显示PATH = C:\ Windows \ System32; Foo;。

然后我退出并重新开启。然后我作为普通用户运行cmd。 我输入set并显示新的环境变量,但未展开。 它显示PATH = C:\ Windows \ System32;%ALLFOO%; (由于某种原因,似乎可以毫不费力地扩展%SYSTEMROOT%。)

我知道注销并重新启动会导致启动的新Explorer.exe为常规用户的cmd.exe获取新的环境变量,但我不明白为什么它们不会被扩展。

为什么运行cmd并设置为管理员显示完全展开的环境变量并运行cmd并设置为普通用户不会?

在C#程序中设置env变量时,我使用RegistryValueKind.ExpandString枚举。

编辑: 我知道系统变量的扩展时间问题的声明时间顺序,并编辑了问题示例以反映这一点。

1 个答案:

答案 0 :(得分:0)

对环境变量的更改不是可见的。您需要notify正在运行的注册表更改过程。

并且,您应该记住,您在进程中看到的环境(您的cmd窗口)不是从注册表中获取的,而是从其父进程继承的。您可以发送通知,但有些进程会处理,有些则不会。

其余问题应该通过环境加载顺序来解释:

  • 在处理环境本身之前,会从注册表中检索一些值。 <{1}}在

    中定义
    %systemroot%
  • 加载系统环境

    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot 变量按字母顺序排在第一位
    • REG_SZ按字母顺序加入。由于REG_EXPAND_SZ值已被加入,因此可以扩展它们。如果REG_SZ变量引用了尚未展开的另一个REG_EXPAND_SZ变量(字母顺序),则无法解析此引用,也不会展开。
  • 当用户登录时,将处理用户环境。
    • 相同REG_EXPAND_SZ,然后处理REG_SZ变量。
    • 在用户级别定义的变量会覆盖系统环境的值,但某些变量(例如REG_EXPAND_SZ)除外,其中值是连接的。

所有这意味着

  • 不同的用户可以并且可能会看到不同的环境

  • 相同的用户可以看到不同的环境,具体取决于父进程的内容。使用 Win + R 并执行PATH与在文件夹中使用 Shift +右键单击并选择“在此处打开命令”不同。父流程是不同的。