在 Path 中重用环境变量

在 Path 中重用环境变量

是否可以从 PowerShell 中重用 Path 环境变量中的环境变量?

在高级系统设置中查看的%SystemRoot%路径变量中已经定义并使用这些环境变量。...;%SystemRoot%\system32;...

在 PowerShell 中,这些被定义为$Env:SystemRoot,并且$Env:Path该路径的一部分被解析为...;c:\windows\system32;...

如何在 Path 中创建和使用这样的自定义变量?例如$Env:MyPath = 'c:\mypath'将其添加到 Path...;%MyPath%\documents;...并在高级系统设置和 PowerShell 解析中获得相同的效果$Env:Path

答案1

天哪,这充满变数

三种类型的环境变量

  1. 机器

    环境变量存储或检索自 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\EnvironmentWindows 操作系统注册表中的键。当用户在设置操作中创建环境变量时,操作系统会将环境变量存储在系统注册表中,但不会存储在当前进程中。如果本地计算机上的任何用户启动新进程,操作系统就会将环境变量从注册表复制到该进程。当进程终止时,操作系统会销毁该进程中的环境变量。但是,注册表中的环境变量会一直存在,直到用户以编程方式或通过操作系统工具将其删除。

  2. 用户

    环境变量存储或检索自 HKEY_CURRENT_USER\环境Windows 操作系统注册表中的键。当用户在设置操作中创建环境变量时,操作系统会将环境变量存储在系统注册表中,但不存储在当前进程中。如果用户启动新进程,操作系统会将环境变量从注册表复制到该进程。当进程终止时,操作系统会销毁该进程中的环境变量。但是,注册表中的环境变量会一直存在,直到用户以编程方式或通过操作系统工具将其删除。

  3. 过程

    环境变量存储于当前进程关联的环境块中或从中检索。用户在设置操作中创建环境变量。当进程终止时,操作系统会销毁该进程中的环境变量。

在 PowerShell 中新创建的$env:环境变量的Process类型为。要显示的变量Advanced System Settings必须是MachineUser级别变量。要创建具有特定级别的变量,请使用环境.设置环境变量方法:

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'User')

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')

请注意,设置Machine级别环境变量需要提升。

你听懂我的话了吗,哈尔?

所以你想将一个环境变量嵌入另一个环境变量并使其扩展?毕竟,微软一直都是这么做的,例如每个用户TEMPTMP变量都包含USERPROFILEenv.var。不幸的是,这会带来一些问题:

  1. 此类变量的底层注册表项必须 REG_EXPAND_SZ type

  2. 容器环境变量必须是按字母顺序排列较少比容器环境变量:

    如果环境变量的定义变量1包含另一个环境变量变量2和名称变量1字母顺序小于变量2(IEstrcmp(变量1,变量2) < 0), 然后变量2不会展开。这似乎是因为当 Windows 首次设置环境变量时,它们是按字母顺序创建的,因此变量2 直到 var1 被创建之后才存在(因此无法进行扩展)。

  3. 对于PATH变量,应该有条目之间没有空格

    错误:c:\path1; c:\Maven\bin\; c:\path2\
    正确:c:\path1;c:\Maven\bin\;c:\path2\

此外,如果你尝试利用环境.设置环境变量像这样的方法:

$Path = [Environment]::GetEnvironmentVariable('Path', 'Machine')
    
[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')
[Environment]::SetEnvironmentVariable('Path', "%MyPath%;$Path", 'Machine')

它不会产生预期的结果,因为新创建的PATH变量不会具有类型REG_EXPAND_SZ,而是REG_SZ

打开吊舱门,HAL

由于SetEnvironmentVariable没有办法控制生成的注册表项类型,因此您必须采用替代方法:直接修改注册表创建该REG_EXPAND_SZ类型的条目。

$Path = [Environment]::GetEnvironmentVariable('Path','Machine')

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')

[Microsoft.Win32.Registry]::SetValue(
    'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
    'Path',
    "%MyPath%;$Path",
    [Microsoft.Win32.RegistryValueKind]::ExpandString
)

这种方法的缺点是它不能广播WM_SETTINGCHANGE消息到系统中的所有窗口,以便任何感兴趣的应用程序(例如 Windows 资源管理器、程序管理器、任务管理器、控制面板等)都可以执行更新。

为了缓解这种情况,你可以广播消息你自己:

if (-not ('Win32.NativeMethods' -as [type])) {
    # import SendMessageTimeout from Win32
    Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @'

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr hWnd,
            uint Msg,
            UIntPtr wParam,
            string lParam,
            uint fuFlags,
            uint uTimeout,
            out UIntPtr lpdwResult);
'@
}

$HWND_BROADCAST = [System.IntPtr]0xffff
$WM_SETTINGCHANGE = 0x1a
$result = [System.UIntPtr]::Zero

# Notify all windows of environment block change
[Win32.NativeMethods]::SendMessageTimeout(
    $HWND_BROADCAST, $WM_SETTINGCHANGE,
    [System.UIntPtr]::Zero,
    'Environment',
    2,
    5000,
    [ref]$result
)

相关内容