设置Windows PowerShell环境变量


605

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

注意:

我想永久保留更改,因此不必每次运行PowerShell时都进行设置。PowerShell是否有配置文件?类似于Unix上的Bash配置文件?


1
我想要一个位于文件共享中的中央配置文件。同步是一种痛苦。使用创建一个存根配置文件。\\ computer \ share \ path \ Profile.ps1似乎有点麻烦(尝试使用记事本$ Profile)。如果有一种方法可以永久更改$ Profile自动变量,那就太好了。
内森·哈特利

5
PATH环境也不会影响powershell命令提示符。但是,不同之处在于Powershell不接受用引号引起来的路径。解决方案:删除"路径环境变量中所有封闭的引号()
Nilzor

3
如果您登陆PS> v1 ...除了上面的Nilzor评论:使用此命令从会话的PATH环境变量中的路径中删除所有“:$($Env:PATH).Split(';') | %{ $str += "$($_.Trim('"'));" }; $Env:PATH=$str
d3r3kk 2014年

Answers:


476

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

$env:Path = "SomeRandomPath";             (replaces existing path) 
$env:Path += ";SomeRandomPath"            (appends to existing path)

有一些方法可以使环境设置永久化,但是如果仅从PowerShell使用它们,则最好使用您的配置文件来启动设置。启动时,PowerShell将运行在“我的文档”文件夹下 的目录中找到的所有.ps1文件WindowsPowerShell。通常,您已经有一个profile.ps1 文件。我电脑上的路径是

C:\Users\JaredPar\Documents\WindowsPowerShell\profile.ps1

38
$ profile是一个自动变量,指向所有PowerShell主机的用户配置文件。
JasonMArcher

16
请注意,(分割路径$ profile)(要获取包含的文件夹)可以包含多个配置文件:profile.ps1应该由所有主机加载,<host-name> _profile.ps1应该仅由指定主机加载。对于PowerShell.exe(控制台主机),这是Microsoft.PowerShell_profile.ps1。
理查德

10
如果我的文档中没有WindowsPowerShell文件夹怎么办?我应该创建文件夹和文件吗?如果要添加C:\path\to\file.ext到环境变量,应该在文件中放入什么?编辑:已经找到它。答案是肯定的,创建它。该文件应由1行组成:$env:path += ;C:\path\to\file.ext"
Lewistrick 2015年

7
@Lewistrick默认情况下,您没有个人资料。我按照以下说明创建了一个说明:howtogeek.com/50236/customizing-your-powershell-profile
MikeB 2015年

16
请谨慎操作-这会破坏您现有的路径。 $env:Path = "SomeRandomPath"; 相反,请参见下面的@mloskot。
John Mark

626

如果在PowerShell会话期间的某个时间需要临时添加到PATH环境变量,则可以采用以下方式:

$env:Path += ";C:\Program Files\GnuWin32\bin"

4
+1 ::与mingw一样,这种单行代码对于基于会话的调用非常有效... IE $ env:PATH + =“; c:\ MinGW \ msys \ 1.0 \ bin” ^ {一些mingw bin ... }
Eddie B

2
以及如何删除路径?
becko 2014年

11
如果您需要您的路径之前标准之一叫,开始时将其插入 $env:Path = "C:\MyPath;$env:Path"
迈克尔Freidgeim

4
****不要忘了在附加字符串开头的分号,如@Kevin的注释所示。这是很明显的,但是如果您只复制/粘贴答案中的代码并且在现有路径的末尾没有分号,则可能会错过这一点。我将尝试提交修改。
马特·古德里奇

1
@MattGoodrich [我已回滚到以前的版本
心教堂

278

您还可以使用以下命令永久修改用户/系统环境变量(即在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")

6
这对于受限访问系统非常有用。
h0tw1r3 2012年

14
@AndresRiofrio,是的,这是永久的。用法:[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\bin", [EnvironmentVariableTartget::Machine) 在启动新的Powershell会话之前,您不会看到此更改的结果。也就是说,如果在运行此命令后立即检查$ env:Path,您将看到命令前的$ env:Path。要更新,请关闭并打开外壳或开始新的会话。
FLGMwt 2014年

7
@FLGMwt您有错字,正确的是:[Environment] :: SetEnvironmentVariable(“ Path”,$ env:Path +“; C:\ bin”,[EnvironmentVariableTarget] :: Machine)
enthus1ast 2014年

10
您可以编写字符串“ Machine”或“ User”,而不是整个.NET枚举。来自Technet
bouvierr 2014年

3
我认为该答案还应演示设置用户变量的用法,例如[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";C:\bin", "User")
Saito

63

在PowerShell提示符下:

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

然后,您应该看到以下文本:

SUCCESS: Specified value was saved.

重新启动会话,该变量将可用。setx也可以用来设置任意变量。键入setx /?在提示文档。

在以这种方式弄乱路径之前,请确保通过$env:path >> a.out在PowerShell提示符下执行操作来保存现有路径的副本。


5
似乎仅在“以管理员身份运行”时才起作用,此后仅对“以管理员身份运行” PowerShell控制台生效,而不是定期运行的控制台。
matanster


12
哎呀-刚被setx的1024个字符限制击中;值得庆幸的是,我按照建议记录了$ end:Path的现有值。只是需要注意的事项:superuser.com/questions/387619/…–
乔诺

3
为什么不$env:PATH先进行设置,然后再进行设置,setx /m PATH "$env:PATH"以使其在本地和全局应用而无需重新启动Shell?
tresf

1
真好!尽管setx不是本机cmdlet,但是对于那些讨厌的,冗长的.NET Framework调用,它仍然是一个更好,更容易被忘记的替代方案!令人困惑的是,即使Powershell 7仍然没有附带用于持久化envvar的官方cmdlet。什么。感觉像应该与“ ls”具有同等功能的功能。
乔纳斯

27

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]::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 ';'
    }
}

查看我的要旨以获取相应的Remove-EnvPath功能。


16

尽管当前接受的答案在某种意义上是可行的,即path变量是从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

12

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

SetEnvironmentVariableREG_EXPAND_SZ%SystemRoot%\system32 转换REG_SZC:\Windows\system32

路径中的任何其他变量也会丢失。使用添加新的%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
 }

我在博客文章中更详细地解释了这个问题。


应为:$ newPath = $ newPath -replace“ ;;”,“;” ?
乔·约翰斯顿,

8

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

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'
    }
}

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


6

@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]::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 ';'
            }
        }
    }
}

5

正如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
    }

}

5

大多数答案不是针对UAC的。这涵盖了UAC问题。

首先choco install pscx通过http://chocolatey.org/安装PowerShell社区扩展(您可能必须重新启动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

4

我的建议是:

我已经测试过将C:\oracle\x64\binPath永久添加到环境变量中,并且可以正常工作。

$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(“;”)

3

打开PowerShell并运行:

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

1

在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

有关更多信息,请参见关于环境变量


0

我尝试优化SBFMichael的代码以使其更紧凑。

我依靠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.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;

到目前为止,它们似乎起作用了。


0

仅将值推入注册表的答案会永久更改(因此,该线程上的大多数答案(包括已接受的答案)都不会永久影响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 $PathNew
        Get-ItemProperty -Path $RegPropertyLocation -Name $PathType | select -ExpandProperty $PathType
        if ($PathType -eq "Path") { $env:Path += ";$PathToAdd" }                  # Add to Path also for this current session
        if ($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 path
AddTo-Path "" "User" "Path"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.