设置Windows PowerShell环境变量

我发现设置PATH环境变量只影响旧的命令提示符。PowerShell似乎有不同的环境设置。如何更改PowerShell(v1)的环境变量?

备注:

我想使我的更改永久化,所以我不必每次运行PowerShell时都设置它。PowerShell有配置文件吗?类似Unix上的Bash配置文件?

990888 次浏览

更改实际的环境变量可以通过使用env: namespace / drive信息。例如,这个代码将更新路径环境变量:

$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

如果在PowerShell会话期间的某个时间,您需要查看或暂时修改PATH环境变量,您可以键入以下命令之一:

$env:Path                             # shows the actual content$env:Path = 'C:\foo;' + $env:Path     # attach to the beginning$env:Path += ';C:\foo'                # attach to the end

您还可以使用以下内容修改用户/系统环境变量永久(即在shell重新启动期间保持不变):

修改系统环境变量

[Environment]::SetEnvironmentVariable("Path", $env:Path, [System.EnvironmentVariableTarget]::Machine)

修改用户环境变量

[Environment]::SetEnvironmentVariable("INCLUDE", $env:INCLUDE, [System.EnvironmentVariableTarget]::User)

注释中的用法-添加到系统环境变量

[Environment]::SetEnvironmentVariable("Path",[Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine) + ";C:\bin",[EnvironmentVariableTarget]::Machine)

如果您不想编写类型,也可以使用基于字符串的解决方案

[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\bin", "Machine")

警告:在PowerShell提示符中执行$env:path >> a.out以保存现有路径的副本,以防出现问题。

从PowerShell提示符:

setx PATH "$env:path;\the\directory\to\add" -m

你应该看到文本:

SUCCESS: Specified value was saved.

重新启动会话,变量将可用。setx也可用于设置任意变量。在留档提示符下键入setx /?

虽然当前接受的答案在某种意义上是路径变量从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社区扩展,向环境变量路径添加路径的正确命令是:

Add-PathVariable "C:\NewFolderToAddToTheList" -Target Machine

大多数答案都没有解决UAC。这包括UAC问题。

首先安装PowerShell社区扩展:choco install pscxhttp://chocolatey.org/(您可能需要重新启动shell环境)。

然后启用pscx

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #allows scripts to run from the interwebs, such as pcsx

然后使用Invoke-Elevated

Invoke-Elevated {Add-PathVariable $args[0] -Target Machine} -ArgumentList $MY_NEW_DIR

这将设置当前会话的路径并提示用户永久添加它:

function Set-Path {param([string]$x)$Env:Path+= ";" +  $xWrite-Output $Env:Path$write = Read-Host 'Set PATH permanently ? (yes|no)'if ($write -eq "yes"){[Environment]::SetEnvironmentVariable("Path",$env:Path, [System.EnvironmentVariableTarget]::User)Write-Output 'PATH updated'}}

您可以将此函数添加到默认配置文件(Microsoft.PowerShell_profile.ps1)中,通常位于%USERPROFILE%\Documents\WindowsPowerShell

JeanT的回答一样,我想要一个围绕添加路径的抽象。与JeanT的回答不同,我需要它在没有用户交互的情况下运行。我正在寻找的其他行为:

  • 更新$env:Path,以便更改在当前会话中生效
  • 为将来的会话保留环境变量更改
  • 当相同的路径已经存在时,不添加重复的路径

如果有用,这里是:

function Add-EnvPath {param([Parameter(Mandatory=$true)][string] $Path,
[ValidateSet('Machine', 'User', 'Session')][string] $Container = 'Session')
if ($Container -ne 'Session') {$containerMapping = @{Machine = [EnvironmentVariableTarget]::MachineUser = [EnvironmentVariableTarget]::User}$containerType = $containerMapping[$Container]
$persistedPaths = [Environment]::GetEnvironmentVariable('Path', $containerType) -split ';'if ($persistedPaths -notcontains $Path) {$persistedPaths = $persistedPaths + $Path | where { $_ }[Environment]::SetEnvironmentVariable('Path', $persistedPaths -join ';', $containerType)}}
$envPaths = $env:Path -split ';'if ($envPaths -notcontains $Path) {$envPaths = $envPaths + $Path | where { $_ }$env:Path = $envPaths -join ';'}}

我的要点中查看相应的Remove-EnvPath函数。

正如Jonathan Leaders提到的这里,运行命令/脚本提升以能够更改机器的环境变量是很重要的,但是运行一些命令提升并不需要使用社区扩展来完成,所以我想修改和扩展JeanT的回答,即使脚本本身没有运行提升,也可以执行更改机器变量:

function Set-Path ([string]$newPath, [bool]$permanent=$false, [bool]$forMachine=$false ){$Env:Path += ";$newPath"
$scope = if ($forMachine) { 'Machine' } else { 'User' }
if ($permanent){$command = "[Environment]::SetEnvironmentVariable('PATH', $env:Path, $scope)"Start-Process -FilePath powershell.exe -ArgumentList "-noprofile -command $Command" -Verb runas}
}

所有建议永久更改的答案都有相同的问题:它们破坏了路径注册表值。

SetEnvironmentVariableREG_EXPAND_SZ%SystemRoot%\system32转换为C:\Windows\system32REG_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 = GetOldPathWrite-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”

但这种更改不是永久性的。一旦您关闭PowerShell终端并再次重新打开它,$env:path将默认恢复到以前的状态。这是因为您已在会话级别而不是源级别(即注册表级别)应用了更改。要查看$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(“;”)

@Michael Kropat答案的基础上,我添加了一个参数来为现有的PATH变量添加新路径,并检查以避免添加不存在的路径:

function Add-EnvPath {param([Parameter(Mandatory=$true)][string] $Path,
[ValidateSet('Machine', 'User', 'Session')][string] $Container = 'Session',
[Parameter(Mandatory=$False)][Switch] $Prepend)
if (Test-Path -path "$Path") {if ($Container -ne 'Session') {$containerMapping = @{Machine = [EnvironmentVariableTarget]::MachineUser = [EnvironmentVariableTarget]::User}$containerType = $containerMapping[$Container]
$persistedPaths = [Environment]::GetEnvironmentVariable('Path', $containerType) -split ';'if ($persistedPaths -notcontains $Path) {if ($Prepend) {$persistedPaths = ,$Path + $persistedPaths | where { $_ }[Environment]::SetEnvironmentVariable('Path', $persistedPaths -join ';', $containerType)}else {$persistedPaths = $persistedPaths + $Path | where { $_ }[Environment]::SetEnvironmentVariable('Path', $persistedPaths -join ';', $containerType)}}}
$envPaths = $env:Path -split ';'if ($envPaths -notcontains $Path) {if ($Prepend) {$envPaths = ,$Path + $envPaths | where { $_ }$env:Path = $envPaths -join ';'}else {$envPaths = $envPaths + $Path | where { $_ }$env:Path = $envPaths -join ';'}}}}

我尝试优化SBF的迈克尔的代码以使其更紧凑。

我依赖PowerShell的类型强制转换,它会自动将字符串转换为枚举值,因此我没有定义查找字典。

我还提取了根据条件将新路径添加到列表的块,以便完成一次工作并存储在变量中以供重用。

然后根据$PathContainer参数将其永久应用或仅应用于会话。

我们可以将代码块放在函数或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.ps做了类似的事情。

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并运行:

[Environment]::SetEnvironmentVariable("PATH", "$ENV:PATH;<path to exe>", "USER")

在PowerShell中,可以通过键入以下内容导航到环境变量目录:

Set-Location Env:

这将带您到Env:>目录。在此目录中:

要查看所有环境变量,请键入:

Env:\> Get-ChildItem

要查看特定的环境变量,请键入:

Env:\> $Env:<variable name>, e.g. $Env:Path

要设置环境变量,请键入:

Env:\> $Env:<variable name> = "<new-value>", e.g. $Env:Path="C:\Users\"

要删除环境变量,请键入:

Env:\> remove-item Env:<variable name>, e.g. remove-item Env:SECRET_KEY

更多信息在关于环境变量

只有将值推送到注册表的答案才会影响常设的更改(因此此线程上的大多数答案,包括已接受的答案,没有会永久影响Path)。

以下函数适用于Path/PSModulePathUser/System类型。默认情况下,它还会将新路径添加到当前会话。

function AddTo-Path {param ([string]$PathToAdd,[Parameter(Mandatory=$true)][ValidateSet('System','User')][string]$UserType,[Parameter(Mandatory=$true)][ValidateSet('Path','PSModulePath')][string]$PathType)
# AddTo-Path "C:\XXX" "PSModulePath" 'System'if ($UserType -eq "System" ) { $RegPropertyLocation = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' }if ($UserType -eq "User"   ) { $RegPropertyLocation = 'HKCU:\Environment' } # also note: Registry::HKEY_LOCAL_MACHINE\ format$PathOld = (Get-ItemProperty -Path $RegPropertyLocation -Name $PathType).$PathType"`n$UserType $PathType Before:`n$PathOld`n"$PathArray = $PathOld -Split ";" -replace "\\+$", ""if ($PathArray -notcontains $PathToAdd) {"$UserType $PathType Now:"   # ; sleep -Milliseconds 100   # Might need pause to prevent text being after Path output(!)$PathNew = "$PathOld;$PathToAdd"Set-ItemProperty -Path $RegPropertyLocation -Name $PathType -Value $PathNewGet-ItemProperty -Path $RegPropertyLocation -Name $PathType | select -ExpandProperty $PathTypeif ($PathType -eq "Path") { $env:Path += ";$PathToAdd" }                  # Add to Path also for this current sessionif ($PathType -eq "PSModulePath") { $env:PSModulePath += ";$PathToAdd" }  # Add to PSModulePath also for this current session"`n$PathToAdd has been added to the $UserType $PathType"}else {"'$PathToAdd' is already in the $UserType $PathType. Nothing to do."}}
# Add "C:\XXX" to User Path (but only if not already present)AddTo-Path "C:\XXX" "User" "Path"
# Just show the current status by putting an empty pathAddTo-Path "" "User" "Path"

无痛苦的单线示例解决方案

尝试这三个命令来练习在PowerShell中设置和删除环境变量。

用法说明

  1. 在提升的PowerShell上运行这些命令(例如,具有管理员权限)。
  2. 在每一步之后,要使您的命令工作,请关闭会话并再次打开它。

添加/创建一个<强>永久环境变量:

[Environment]::SetEnvironmentVariable("MyEnvVar", "NewEnvValue", "Machine")

Machine是一个EnvironmentVariableTarget将适用于当前和未来的用户,而不是User的目标。


修改/更改环境变量:

[Environment]::SetEnvironmentVariable("MyEnvVar", "NewerEnvValue", "Machine")

删除/删除变量:

[Environment]::SetEnvironmentVariable("MyEnvVar", "", "Machine")

需要明确的是,1990年代的Windows方式单击开始,右键单击此pc,然后选择属性,然后选择高级系统设置,然后在弹出的对话框中选择环境变量,在列表中双击PATH,然后使用编辑向上移动下移仍然可以更改PATH。Power shell,其余的Windows获取您在此处设置的任何内容。

是的,您可以使用这些新方法,但旧方法仍然有效。在基本级别,所有永久更改方法都是编辑注册表文件的受控方式。

有很多附加或覆盖的例子。这是一个在Powershell上为Linux、Ubuntu 18.04和pwsh 7.1.3预先添加路径的例子

$ENV:PATH = "/home/linuxbrew/.linuxbrew/bin:$ENV:PATH"

我特别添加了linuxbrew(linux的自制)bin目录以优先于安装的系统。它帮助解决了我遇到的一个问题,尽管这是最有用的地方,它也让我“尝试”。

请注意,:是Linux路径分隔符,而在Windows(或至少我的Windows)上,您通常会将;用于PowerShell。

@ali Darabi的回答中编辑注册表项最适合我,但是当我没有正确的权限从Powershell执行此操作时。所以我直接在注册表中编辑它。

我想在这个答案中进一步扩展这个问题。

重新启动Powershell也不足以传播更改。我必须打开任务管理器并重新启动explorer.exe以触发注册表的重新加载。

导航注册表可能非常繁琐,因此为了保持用户友好的体验,您可以从Powershell执行此操作:

REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit" /v "LastKey" /d "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment" /f; regedit

它将上次打开的窗口设置为某个注册表路径,以便下次打开注册表时,它会以正确的键打开。

如果您需要动态设置变量名并且仅用于会话,请使用:

New-Item env:\$key -Value $value -Force | Out-Null

这些脚本是幂等的(可以多次运行)。
它们更新Windows路径和当前/未来的Powershell会话:

永久添加路径

    $targetDir="c:\bin"$oldPath = [System.Environment]::GetEnvironmentVariable("Path","Machine")$oldPathArray=($oldPath) -split ';'if(-Not($oldPathArray -Contains "$targetDir")) {write-host "Adding $targetDir to Machine Path"$newPath = "$oldPath;$targetDir" -replace ';+', ';'[System.Environment]::SetEnvironmentVariable("Path",$newPath,"Machine")$env:Path = [System.Environment]::GetEnvironmentVariable("Path","User"),[System.Environment]::GetEnvironmentVariable("Path","Machine") -join ";"}write-host "Windows paths:"($env:Path).Replace(';',"`n")

永久移除路径

    $targetDir="c:\bin"$oldPath = [System.Environment]::GetEnvironmentVariable("Path","Machine")$oldPathArray=($oldPath) -split ';'if($oldPathArray -Contains "$targetDir") {write-host "Removing $targetDir from Machine path"$newPathArray = $oldPathArray | Where-Object { $_ –ne "$targetDir" }$newPath = $newPathArray -join ";"[System.Environment]::SetEnvironmentVariable("Path",$newPath,"Machine")$env:Path = [System.Environment]::GetEnvironmentVariable("Path","User"),[System.Environment]::GetEnvironmentVariable("Path","Machine") -join ";"}write-host "Windows paths:"($env:Path).Replace(';',"`n")

我发现将C:\vcpkg永久添加到我的PATH env变量而没有缺点的最简单解决方案是:

$current_PATH = [Environment]::GetEnvironmentVariable("PATH", "USER");[Environment]::SetEnvironmentVariable("PATH", "$current_PATH;C:\vcpkg;", "USER")

您可以将"USER"更改为"MACHINE"以更改系统env var(需要一个管理终端,您可能需要将Environment更改为System.Environment),甚至更改为"PROCESS"以仅更改本地PATH env var(不永久更改)。分别为"USER"=1"MACHINE"=2"PROCESS"=0,这里是有关这些命令的留档:获取环境变量"MACHINE"0

我找到了另外两个答案,但有主要缺点和我不建议使用它们。两者都使用SETX,因为它是由PowerShell实现的,以永久更改env变量。这些命令的缺点是,您将复制您的系统路径进入您的语言环境PATH,并且您需要PowerShell才能使用它们:

setx PATH "$($Env:PATH);C:\vcpkg;"

较长但允许与其他env变量一起使用:

$($Env:PATH).Split(';') | %{ $str += "$($_.Trim('"'));" }; %{ $str += "C:\vcpkg;" } ; setx PATH $str; %{ $str = "" }