我已经阅读了很多关于这个主题的帖子并尝试了很多东西,但似乎无法让它发挥作用。我想设置一个环境变量,然后将该变量嵌套在 Path 环境变量中。我从批处理文件切换到 Powershell,因为我无法进行后期扩展以防止扩展路径中已有的嵌套变量等。
这是演示问题的脚本。鉴于您已将 Maven 解压缩到 e:\Apps\maven\apache-maven-3.2.1
位置,测试脚本将运行,创建 MAVEN_HOME 变量,将该变量嵌套在路径中,然后执行 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
最佳答案
新的 cmd session 使用从父进程环境(通常是 Windows 资源管理器,或者生成它的 cmd 或 PowerShell session )继承的路径。更改注册表中环境变量的值不会自动更改资源管理器的环境,因此它不会更改新 cmd session 使用的值。
如果您通过系统属性 控制面板设置环境变量,该值会反射(reflect)在新的 cmd session 中,不是因为它存储在注册表中,而是因为这也改变了环境中的值主要的资源管理器进程。 (请注意,只需从系统属性 打开环境变量 对话框并单击确定 即可从注册表值更新资源管理器的所有环境变量)。
要从 PowerShell 获得相同的效果 — 同时更改注册表和资源管理器环境中传递给新 cmd session 的值 — 您可以这样做:
[Environment]::SetEnvironmentVariable("Path", $envpath, 'Machine')
请注意,这不会替换
[Environment]::SetEnvironmentVariable("Path", $envpath, 'Process')
因为如果目标是 Machine,则当前 PowerShell session 中的值不会更改。 (您可以使用字符串 'Process'
和 'Machine'
代替 [EnvironmentVariableTarget]::Process
和 [EnvironmentVariableTarget]: :机器
).
请注意,顺便说一句,新的 PowerShell session 始终使用注册表中的 Path 值,而不是从父级继承的值。此行为仅适用于路径;所有其他环境变量都是从父进程继承的。参见 this answer获取更多信息。
关于windows - 使用 PowerShell 设置嵌套的可扩展环境变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23813478/