Setting Windows PowerShell environment variables
我发现设置path环境变量只影响旧的命令提示。PowerShell似乎具有不同的环境设置。如何更改PowerShell(v1)的环境变量?
注:
我希望使更改永久化,因此不必每次运行PowerShell时都设置它。PowerShell是否有配置文件?像Unix上的bash配置文件?
如果在PowerShell会话期间,您需要临时附加到path环境变量,可以这样做:
1 | $env:Path +=";C:\Program Files\GnuWin32\bin" |
更改实际的环境变量可以通过使用
1 2 | $env:Path ="SomeRandomPath"; (replaces existing path) $env:Path +=";SomeRandomPath" (appends to existing path) |
有一些方法可以使环境设置永久化,但是如果您只在PowerShell中使用它们,可能是更好的方法是使用您的配置文件启动设置。启动时,PowerShell将运行任何.ps1在
1 | C:\Users\JaredPar\Documents\WindowsPowerShell\profile.ps1 |
您还可以使用以下命令永久地修改用户/系统环境变量(即在重新启动shell时保持不变):
1 2 3 4 5 6 7 8 9 10 11 12 13 | ### Modify a system environment variable ### [Environment]::SetEnvironmentVariable ("Path", $env:Path, [System.EnvironmentVariableTarget]::Machine) ### Modify a user environment variable ### [Environment]::SetEnvironmentVariable ("INCLUDE", $env:INCLUDE, [System.EnvironmentVariableTarget]::User) ### Usage from comments - add to the system environment variable ### [Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine) +";C:\bin", [EnvironmentVariableTarget]::Machine) |
从PowerShell提示:
1 | setx PATH"$env:path;\the\directory\to\add" -m |
然后您应该看到文本:
1 | SUCCESS: Specified value was saved. |
重新启动会话,变量将可用。
以这种方式处理路径之前,请确保在PowerShell提示中执行
就像Jeant的答案一样,我想要一个关于添加到路径上的抽象概念。与Jeant的答案不同,我需要它在没有用户交互的情况下运行。我在寻找的其他行为:
- 更新
$env:Path ,使更改在当前会话中生效。 - 为将来的会话保留环境变量更改
- 当同一路径已存在时不添加重复路径
如果有用的话,这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function Add-EnvPath { param( [Parameter(Mandatory=$true)] [string] $Path, [ValidateSet('Machine', 'User', 'Session')] [string] $Container = 'Session' ) if ($Container -ne 'Session') { $containerMapping = @{ Machine = [EnvironmentVariableTarget]::Machine User = [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 ';' } } |
查看我的要点,了解相应的
虽然当前接受的答案在从PowerShell上下文永久更新path变量的意义上有效,但它实际上并不更新存储在Windows注册表中的环境变量。
要实现这一点,您显然也可以使用PowerShell:
1 2 3 4 5 6 | $oldPath=(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path $newPath=$oldPath+’;C: ewFolderToAddToTheList\’ Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH –Value $newPath |
更多信息在博客文章中使用PowerShell修改您的环境路径
如果使用PowerShell社区扩展,则向环境变量path添加路径的正确命令是:
1 2 | Add-PathVariable"C: ewFolderToAddToTheList" -Target Machine |
所有建议永久更改的答案都有相同的问题:它们破坏了路径注册表值。
路径中的任何其他变量也将丢失。使用
下面是我用来解决这个问题的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | [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 } |
我在一篇博文中更详细地解释了这个问题。
这将设置当前会话的路径并提示用户永久添加它:
1 2 3 4 5 6 7 8 9 10 11 | function Set-Path { param([string]$x) $Env:Path+=";" + $x Write-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' } } |
您可以将此函数添加到默认配置文件(
正如Jonathan Leaders在这里提到的,运行提升的命令/脚本是很重要的,以便能够更改"machine"的环境变量,但是运行一些提升的命令并不需要通过社区扩展来完成,所以我想以某种方式修改和扩展Jeant的答案,更改机器变量也可以在en如果脚本本身未被提升运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 } } |
大多数答案都不是针对UAC的。这涉及UAC问题。
首先通过http://chocoley.org/安装PowerShell社区扩展:
然后启用pscx
1 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #allows scripts to run from the interwebs, such as pcsx |
然后使用
1 |
基于@michael kropat的答案,我添加了一个参数来预先设置现有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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]::Machine User = [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 ';' } } } } |
我的建议是这个我已经测试过将c:oraclex64in永久添加到路径中,这样可以正常工作。
1 | $ENV:PATH |
第一种方法很简单:
1 | $ENV:PATH="$ENV:PATH;c:\path\to\folder" |
但这种更改并不是永久性的,$env:path一旦关闭PowerShell终端并重新打开它,就会默认回到原来的状态。这是因为您已经在会话级别而不是源级别(即注册表级别)应用了更改。要查看$env:path的全局值,请执行以下操作:
1 | Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH |
或者更具体地说:
1 | (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path |
现在要更改这一点,首先我们捕获需要修改的原始路径:
1 | $oldpath = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path |
现在我们定义新路径的外观,在本例中,我们将附加一个新文件夹:
1 | $newpath ="$oldpath;c:\path\to\folder" |
注意:请确保$newpath看起来像您希望的样子,否则可能会损坏您的操作系统。
现在应用新值:
1 | Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH -Value $newPath |
现在做最后一个检查,看看你期望的样子:
1 | (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path |
现在,您可以重新启动PowerShell终端(甚至重新启动计算机),并确保它不会再次回滚到原来的值。请注意,路径的顺序可能会发生变化,因此它是按字母顺序排列的,因此请确保检查整行,以便更容易地将输出拆分为行,方法是使用分号作为分隔符:
1 | ($env:path).split(";") |
打开PowerShell并运行:
1 | [Environment]::SetEnvironmentVariable("PATH","$ENV:PATH;<path to exe>","USER") |
我试图优化SBF和Michael的代码,使其更紧凑。
我依赖于PowerShell的类型强制,它自动将字符串转换为枚举值,因此我没有定义查找字典。
我还拉出了一个块,它根据一个条件将新路径添加到列表中,这样工作就完成了一次,并存储在一个变量中以供重用。
然后根据
我们可以将代码块放在一个函数或PS1文件中,直接从命令提示符调用该函数或PS1文件。我和devenvaddpath.ps1一起去了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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; |
我为devenremovepath.ps1做了类似的事情。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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; |
到目前为止,它们似乎有效。