在PowerShell中,我需要更改系统路径变量:
$oldPath = [System.Environment]::GetEnvironmentVariable('Path', 'Machine')
[System.Environment]::SetEnvironmentVariable('Path', (Transform-It $oldPath), 'Machine')
然后启动一个程序:
& $someExeName 'someargument'
我遇到的问题是可执行文件正在使用旧环境。它无法识别新路径。如果我还更改$env.path
,要仅更改此PowerShell会话的路径,它也不会传播到新进程。如果我关闭PowerShell并在新窗口中启动可执行文件,那很好。据推测,它正在继承PowerShell流程中的(未更新的)环境。
在PowerShell中更改环境变量并通过从该窗口启动的新进程识别它的最佳做法是什么?
答案 0 :(得分:7)
通常,子进程从父进程*继承环境。如果从现有PowerShell会话生成新的PowerShell会话,则新会话将从该会话继承环境变量(但不包含其他变量)。
但是, Path 变量是一个导致很多混淆的异常:即使它是一个环境变量,新的PowerShell会话也会从注册表项HKLM:\System\CurrentControlSet\Control\Session Manager\Environment
读取其值,从而覆盖从父会话继承的值。
此行为特定于路径变量。其他环境变量从父会话继承,无论它们是仅在父会话中定义还是存储在上述注册表项中。
此行为也特定于PowerShell。
»如果您在PowerShell会话中更改路径,但未在注册表中更改,并生成新的PowerShell会话(例如,使用start powershell
),则新会话将具有以下路径:注册表,但如果您生成cmd会话,新会话将具有产生它的PowerShell会话的路径。
»同样,如果您在cmd会话中更改路径(使用set Path=New Path
)并生成PowerShell会话,则新会话将具有来自注册表的路径,但是如果您生成在cmd会话中,它将具有来自父cmd会话的更改路径。
»默认行为是从父进程继承路径(以及其余环境)(如cmd所示)。 但是,很有可能其他一些程序的行为与PowerShell类似,用注册表值覆盖继承的值。这种行为并不常见,但不能排除可执行文件发生这种情况的可能性。
以下命令在当前会话中更改路径,而不是在注册表中:
$env:Path = 'New path'
[System.Environment]::SetEnvironmentVariable('Path', 'New Path', 'Process')
以下命令更改注册表中的路径,而不是当前会话中的路径
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' -Name 'Path' -Value 'New Path'
[System.Environment]::SetEnvironmentVariable('Path', 'New Path', 'Machine')
您所描述的内容对我没有意义,因为您说您已经尝试过一种方法来更改注册表中的路径,一种更改PowerShell会话中的路径,以及可执行文件无论如何,产卵都没有改变的路径。 AFAIK原始环境不会缓存在任何地方,并且子进程已从父进程的环境或注册表获取路径。
我建议您确保在启动可执行文件之前双向改变了路径:
如果由于某些无法解释的原因无效,请尝试以下方法:
不是直接从该PowerShell会话启动可执行文件,而是执行此命令
powershell "& $someExeName 'someargument'"
让新的但非交互式的PowerShell会话启动可执行文件,该会话将从注册表中读取 Path 环境变量。
*请注意,环境的继承是Windows中父进程和子进程之间的唯一关系。除此之外,它们完全独立(没有像Unix和Linux那样的层次结构)。