【问题标题】:Set nested expandable environment variable with PowerShell使用 PowerShell 设置嵌套的可扩展环境变量
【发布时间】:2014-05-22 17:26:01
【问题描述】:

我已经阅读了很多关于这个主题的帖子并尝试了很多东西,但似乎无法让它发挥作用。我想设置一个环境变量,然后将该变量嵌套在 Path 环境变量中。我从批处理文件切换到 Powershell,因为我无法进行后期扩展以防止扩展路径中已经存在的嵌套变量等。

这是演示该问题的脚本。假设您已将 Maven 解压缩到 e:\Apps\maven\apache-maven-3.2.1 位置,测试脚本将运行,创建 MAVEN_HOME 变量,将该变量嵌套在 Path 中,并执行 mvn --help

这一切都很好,除了打开一个新的命令提示符并输入ECHO %PATH% 很明显没有应用更改。

我听说环境变量的字母顺序可能很重要,但在这种情况下,“MAVEN_HOME”在“PATH”之前,所以这无关紧要。

Path 变量正在注册表中创建为REG_EXPAND_SZ 类型。

我正在从批处理文件运行 Powershell 脚本以避免签名:

Call Powershell.exe -executionpolicy bypass -File .\test.ps1

这是 Powershell 脚本:

#Environment Variable
$HOME_VAR = "MAVEN_HOME"
$HOME_PATH = "e:\Apps\maven\apache-maven-3.2.1"
$APP_CMD = "mvn"
$APP_ARGS = "--help"

#String to be added to the Path
$BIN_PATH = "%$HOME_VAR%\bin"

#Registry location of Machine Environment variables
$SYSVAR_REG_PATH = "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"

#Get the correct hive
$HKLM = [Microsoft.Win32.Registry]::LocalMachine
#Get the registry key with true to indicate that it is for editing
$sysvar_regkey = $HKLM.OpenSubKey($SYSVAR_REG_PATH, $TRUE)

#Set the value in the registry
$sysvar_regkey.SetValue($HOME_VAR, $HOME_PATH)

#Read the value back out
$HOME_PATH = $sysvar_regkey.GetValue($HOME_VAR)

#Set the value within the current process
[Environment]::SetEnvironmentVariable($HOME_VAR, $HOME_PATH, [EnvironmentVariableTarget]::Process)

#Must use RegistryKey to get value because it allows the "DoNotExpandEnvironmentNames" option
#This ensures that nested environment variables are not expanded when read
$envpath = $sysvar_regkey.GetValue("Path", "C:\Windows", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
$segments = $envpath.split(";")

Write-Host "BEFORE"
Write-Host $env:path

#See if bin path is already in the Path
If (($segments -contains $BIN_PATH) -eq $FALSE) {
    #Add the bin path to the path
    $segments += $BIN_PATH
    $envpath = $segments -join ";"

    #RegistryValueKind.ExpandString ensures that variables in the path will expand when the Path is read
    $sysvar_regkey.SetValue("Path", $envpath, [Microsoft.Win32.RegistryValueKind]::ExpandString)
}   

#Read the path value as expanded
#All nested variables in the Path are expanded
$envpath = $sysvar_regkey.GetValue("Path")

#Update the Path for the current process
#Must do this every time to expand the Path
[Environment]::SetEnvironmentVariable("Path", $envpath, [EnvironmentVariableTarget]::Process)

Write-Host "AFTER"
Write-Host $env:path

#Run the command line
& $APP_CMD $APP_ARGS | Write-Host

【问题讨论】:

    标签: windows batch-file powershell registry


    【解决方案1】:

    新的 cmd 会话使用从父进程环境继承的路径(通常是 Windows 资源管理器,或者产生它的 cmd 或 PowerShell 会话)。更改注册表中环境变量的值不会自动更改 Explorer 的环境,因此不会更改新 cmd 会话使用的值。

    如果您通过系统属性控制面板设置环境变量,该值会反映在新的 cmd 会话中,不是因为它存储在注册表中,而是因为这也会改变环境中的值主要的资源管理器进程。 (请注意,只需从 System Properties 打开 Environment Variables 对话框并单击 OK 即可根据注册表值更新 Explorer 的所有环境变量。

    要从 PowerShell 中实现相同的效果 — 同时更改注册表和资源管理器环境中的值,并传递给新的 cmd 会话 — 您可以这样做:

    [Environment]::SetEnvironmentVariable("Path", $envpath, 'Machine')
    

    请注意,这不是替换

    [Environment]::SetEnvironmentVariable("Path", $envpath, 'Process')
    

    因为如果目标是 Machine,则当前 PowerShell 会话中的值不会更改。 (您可以使用字符串'Process''Machine' 代替[EnvironmentVariableTarget]::Process[EnvironmentVariableTarget]::Machine)。


    请注意,顺便说一句,新的 PowerShell 会话始终使用注册表中的 Path 值,而不是从父级继承的值。此行为仅适用于 Path;所有其他环境变量都继承自父进程。请参阅this answer 了解更多信息。

    【讨论】:

    • 我应该在问题中提到这一点。无论如何,问题在于 [Environment]::SetEnvironmentVariable 将注册表项类型更改为 REG_SZ,结果嵌套变量不会扩展,然后路径被破坏。
    • SetEnvironmentVariable(x,y,'Machine') 很可能以通常的方式工作,即在注册表中进行更改,然后广播一条消息,告诉感兴趣的应用程序重新读取注册表项。这意味着,如果您直接对注册表进行更改,然后使用SetEnvironmentVariable 进行不同 更改,那么这两个更改都应该生效。
    • 是的,我正在对进程执行此操作,因为我不在乎是否已将扩展路径设置为进程。但是,通过该 API 设置机器是对注册表的破坏性设置。我试过单独使用 SetEnvironmentVariable,它仍然将 RegistryKey 类型更改为 REG_SZ。
    • 我突然想到可以使用 SetEnvironmentVariable API 用扩展路径更新 Explorer,然后使用 RegistryKey 更正注册表。
    猜你喜欢
    • 2022-10-19
    • 2023-03-30
    • 2022-11-10
    • 2020-01-11
    • 2020-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2021-07-15
    相关资源
    最近更新 更多