我发现设置PATH环境变量只影响旧的命令提示符。PowerShell似乎有不同的环境设置。如何更改PowerShell (v1)的环境变量?
注意:
我希望我的更改是永久性的,这样我就不必每次运行PowerShell时都设置它。PowerShell有配置文件吗?比如Unix上的Bash配置文件?
我发现设置PATH环境变量只影响旧的命令提示符。PowerShell似乎有不同的环境设置。如何更改PowerShell (v1)的环境变量?
注意:
我希望我的更改是永久性的,这样我就不必每次运行PowerShell时都设置它。PowerShell有配置文件吗?比如Unix上的Bash配置文件?
当前回答
我试着优化了SBF和Michael的代码,使其更紧凑。
我依赖于PowerShell的类型强制,它会自动将字符串转换为enum值,所以我没有定义查找字典。
我还取出了根据条件将新路径添加到列表中的块,这样工作只完成一次,并存储在变量中以供重用。
然后,根据$PathContainer参数,它会被永久地应用到Session中。
我们可以将代码块放在函数或ps1文件中,直接从命令提示符调用。我选择了DevEnvAddPath.ps1。
param(
[Parameter(Position=0,Mandatory=$true)][String]$PathChange,
[ValidateSet('Machine', 'User', 'Session')]
[Parameter(Position=1,Mandatory=$false)][String]$PathContainer='Session',
[Parameter(Position=2,Mandatory=$false)][Boolean]$PathPrepend=$false
)
[String]$ConstructedEnvPath = switch ($PathContainer) { "Session"{${env:Path};} default{[Environment]::GetEnvironmentVariable('Path', $containerType);} };
$PathPersisted = $ConstructedEnvPath -split ';';
if ($PathPersisted -notcontains $PathChange) {
$PathPersisted = $(switch ($PathPrepend) { $true{,$PathChange + $PathPersisted;} default{$PathPersisted + $PathChange;} }) | Where-Object { $_ };
$ConstructedEnvPath = $PathPersisted -join ";";
}
if ($PathContainer -ne 'Session')
{
# Save permanently to Machine, User
[Environment]::SetEnvironmentVariable("Path", $ConstructedEnvPath, $PathContainer);
}
# Update the current session
${env:Path} = $ConstructedEnvPath;
我对DevEnvRemovePath.ps1做了类似的事情。
param(
[Parameter(Position=0,Mandatory=$true)][String]$PathChange,
[ValidateSet('Machine', 'User', 'Session')]
[Parameter(Position=1,Mandatory=$false)][String]$PathContainer='Session'
)
[String]$ConstructedEnvPath = switch ($PathContainer) { "Session"{${env:Path};} default{[Environment]::GetEnvironmentVariable('Path', $containerType);} };
$PathPersisted = $ConstructedEnvPath -split ';';
if ($PathPersisted -contains $PathChange) {
$PathPersisted = $PathPersisted | Where-Object { $_ -ne $PathChange };
$ConstructedEnvPath = $PathPersisted -join ";";
}
if ($PathContainer -ne 'Session')
{
# Save permanently to Machine, User
[Environment]::SetEnvironmentVariable("Path", $ConstructedEnvPath, $PathContainer);
}
# Update the current session
${env:Path} = $ConstructedEnvPath;
到目前为止,它们似乎是有效的。
其他回答
虽然目前接受的答案在某种意义上是路径变量从PowerShell的上下文中被永久更新,但它实际上并不更新存储在Windows注册表中的环境变量。
要实现这一点,你显然也可以使用PowerShell:
$oldPath=(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path
$newPath=$oldPath+’;C:\NewFolderToAddToTheList\’
Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH –Value $newPath
更多信息请参见博文《使用PowerShell修改环境路径》
如果您使用PowerShell社区扩展,为环境变量path添加路径的正确命令是:
Add-PathVariable "C:\NewFolderToAddToTheList" -Target Machine
更改实际的环境变量可以通过 使用env:命名空间/驱动器信息。例如,这个 代码将更新path环境变量:
$env:Path = "SomeRandomPath"; (replaces existing path)
$env:Path += ";SomeRandomPath" (appends to existing path)
让改变永久化
有办法让环境设置永久存在,但是 如果你只从PowerShell中使用它们,它可能 使用Powershell配置文件脚本更好。
每次Powershell的一个新实例启动时,它都会查找特定的脚本文件(称为配置文件),如果它们存在,就执行它们。您可以编辑这些概要文件中的一个来定制您的环境。
要了解这些配置文件脚本在您的计算机中的位置,请键入:
$profile
$profile.AllUsersAllHosts
$profile.AllUsersCurrentHost
$profile.CurrentUserAllHosts
$profile.CurrentUserCurrentHost
你可以编辑其中一个,例如,输入:
notepad $profile
所有建议永久更改的答案都有相同的问题:它们破坏了路径注册表值。
SetEnvironmentVariable将REG_EXPAND_SZ值%SystemRoot%\system32转换为c:\ windows \system32的REG_SZ值。
路径中的任何其他变量也会丢失。使用%myNewPath%添加新的将不再工作。
这里有一个脚本Set-PathVariable。我用来解决这个问题的ps1:
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$NewLocation)
Begin
{
#requires –runasadministrator
$regPath = "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
$hklm = [Microsoft.Win32.Registry]::LocalMachine
Function GetOldPath()
{
$regKey = $hklm.OpenSubKey($regPath, $FALSE)
$envpath = $regKey.GetValue("Path", "", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
return $envPath
}
}
Process
{
# Win32API error codes
$ERROR_SUCCESS = 0
$ERROR_DUP_NAME = 34
$ERROR_INVALID_DATA = 13
$NewLocation = $NewLocation.Trim();
If ($NewLocation -eq "" -or $NewLocation -eq $null)
{
Exit $ERROR_INVALID_DATA
}
[string]$oldPath = GetOldPath
Write-Verbose "Old Path: $oldPath"
# Check whether the new location is already in the path
$parts = $oldPath.split(";")
If ($parts -contains $NewLocation)
{
Write-Warning "The new location is already in the path"
Exit $ERROR_DUP_NAME
}
# Build the new path, make sure we don't have double semicolons
$newPath = $oldPath + ";" + $NewLocation
$newPath = $newPath -replace ";;",""
if ($pscmdlet.ShouldProcess("%Path%", "Add $NewLocation")){
# Add to the current session
$env:path += ";$NewLocation"
# Save into registry
$regKey = $hklm.OpenSubKey($regPath, $True)
$regKey.SetValue("Path", $newPath, [Microsoft.Win32.RegistryValueKind]::ExpandString)
Write-Output "The operation completed successfully."
}
Exit $ERROR_SUCCESS
}
我在一篇博文中更详细地解释了这个问题。
我的建议是:
我已经测试了将C:\oracle\x64\bin永久地添加到环境变量Path中,这工作正常。
$ENV:PATH
第一种方法很简单:
$ENV:PATH=”$ENV:PATH;c:\path\to\folder”
但这种改变不是永久的。$env:path将在关闭PowerShell终端并重新打开时默认恢复到之前的状态。这是因为您在会话级别而不是源级别(即注册表级别)应用了更改。要查看$env:path的全局值,请执行以下操作:
Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH
或者更具体地说:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path
现在要改变这一点,首先我们捕获需要修改的原始路径:
$oldpath = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path
现在我们定义新的路径应该是什么样的。在本例中,我们添加了一个新文件夹:
$newpath = “$oldpath;c:\path\to\folder”
注意:请确保$newpath看起来是您想要的样子。如果不是,那么你可能会损坏你的操作系统。
现在应用新值:
Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH -Value $newPath
现在做最后一次检查,它看起来像你期望的那样:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).Path
现在可以重新启动PowerShell终端(甚至重新启动计算机),并看到它不会再次回滚到旧值。
注意路径的顺序可能会改变,所以它是按字母顺序排列的,所以一定要检查整行。为了更简单,你可以使用分号作为分隔符将输出分成行:
($env:path).split(“;”)
有很多附加或覆盖的例子。下面是一个在powershell (Linux, Ubuntu 18.04和pwsh 7.1.3)上预先设置路径的示例
$ENV:PATH = "/home/linuxbrew/.linuxbrew/bin:$ENV:PATH"
我特别添加了linuxbrew (homebrew for linux) bin目录,使其优先于已安装的系统。它帮助我解决了一个问题,虽然这是最有帮助的地方,但它也让我“尝试”。
注意:是Linux的路径分隔符,而在Windows(或者至少是我的Windows)上,你会使用;通常是powershell。