是否可以从 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
天哪,这充满变数
机器
环境变量存储或检索自 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\EnvironmentWindows 操作系统注册表中的键。当用户在设置操作中创建环境变量时,操作系统会将环境变量存储在系统注册表中,但不会存储在当前进程中。如果本地计算机上的任何用户启动新进程,操作系统就会将环境变量从注册表复制到该进程。当进程终止时,操作系统会销毁该进程中的环境变量。但是,注册表中的环境变量会一直存在,直到用户以编程方式或通过操作系统工具将其删除。
用户
环境变量存储或检索自 HKEY_CURRENT_USER\环境Windows 操作系统注册表中的键。当用户在设置操作中创建环境变量时,操作系统会将环境变量存储在系统注册表中,但不存储在当前进程中。如果用户启动新进程,操作系统会将环境变量从注册表复制到该进程。当进程终止时,操作系统会销毁该进程中的环境变量。但是,注册表中的环境变量会一直存在,直到用户以编程方式或通过操作系统工具将其删除。
过程
环境变量存储于当前进程关联的环境块中或从中检索。用户在设置操作中创建环境变量。当进程终止时,操作系统会销毁该进程中的环境变量。
在 PowerShell 中新创建的$env:
环境变量的Process
类型为。要显示的变量Advanced System Settings
必须是Machine
或User
级别变量。要创建具有特定级别的变量,请使用环境.设置环境变量方法:
[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'User')
[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')
请注意,设置Machine
级别环境变量需要提升。
你听懂我的话了吗,哈尔?
所以你想将一个环境变量嵌入另一个环境变量并使其扩展?毕竟,微软一直都是这么做的,例如每个用户TEMP
和TMP
变量都包含USERPROFILE
env.var。不幸的是,这会带来一些问题:
此类变量的底层注册表项必须
REG_EXPAND_SZ type
容器环境变量必须是按字母顺序排列较少比容器环境变量:
如果环境变量的定义变量1包含另一个环境变量变量2和名称变量1字母顺序小于变量2(IEstrcmp(变量1,变量2) < 0), 然后变量2不会展开。这似乎是因为当 Windows 首次设置环境变量时,它们是按字母顺序创建的,因此变量2 直到 var1 被创建之后才存在(因此无法进行扩展)。
对于
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
)