设置Windows PowerShell环境变量

953

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

注意:

我想使我的更改永久生效,这样我就不必每次运行PowerShell时都设置它。PowerShell是否有配置文件?就像Unix上的Bash配置文件一样?


1
我想要一个位于文件共享上的中央配置文件。同步很麻烦。通过使用. \computer\share\path\Profile.ps1创建存根配置文件似乎不是很好的解决办法(尝试Notepad $Profile)。如果有一种可以永久更改$Profile自动变量的方法就好了。 - Nathan Hartley
6
PATH环境变量确实会影响PowerShell命令提示符。不同的是,PowerShell不接受用引号括起来的路径。解决方法是:删除路径环境变量中所有的引号(")。 - Nilzor
4
如果您在使用PS > v1时遇到问题,请参考Nilzor上面的评论:使用以下命令可以删除PATH环境变量中所有路径中的引号,以便于您的会话:$($Env:PATH).Split(';') | %{ $str += "$($_.Trim('"'));" }; $Env:PATH=$str - d3r3kk
1
关于与 PowerShell 无关的持久更新,请参见:https://dev59.com/lcLra4cB1Zd3GeqPDCY1。请注意,应该避免使用基于 setx.exe[Environment]::SetEnvironmentVariable() 的解决方案,因为它们总是将 REG_EXPAND_SZ 定义替换为 REG_SZ 条目,这意味着动态引用其他环境变量的条目会被转换为静态条目。此外,setx.exe 具有 1024 个字符的硬长度限制。 - mklement0
如果遵循@mklement0的建议,可以使用PowerShell cmdlet Add-Path - dank8
1
这个回答解决了你的问题吗?使用PowerShell永久添加路径到Windows似乎不起作用 - dank8
24个回答

10

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

8
只有将值推入注册表的答案才会影响到永久更改(因此,本主题中的大多数答案(包括被接受的答案)都不会永久影响 Path )。以下函数对于 Path / PSModulePath User / 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"

7

在 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

更多信息请参阅关于环境变量的介绍


6

正如Jonathan Leaders这里所提到的那样,为了能够更改'machine'环境变量,必须以管理员身份运行命令/脚本,但是并不需要使用Community Extensions来以管理员身份运行某些命令,因此我想修改和扩展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

明确一下,Windows 90年代的方式是点击 开始,右键点击此电脑,选择属性,在弹出的对话框中选择高级系统设置,然后在列表中双击PATH,使用新建编辑上移下移来更改PATH环境变量。PowerShell和Windows中的其余部分都会使用您在此处设置的内容。

是的,您可以使用这些新方法,但旧方法仍然有效。在基本层面上,所有永久更改方法都是通过编辑您的注册表文件进行控制的。


5

大多数答案没有涉及到用户账户控制(UAC)。本文将讨论UAC问题。

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

3
我找到的最简单的解决方案,是将 C:\vcpkg 永久性地 添加到我的 PATH 环境变量中,而没有任何不良影响:
$current_PATH = [Environment]::GetEnvironmentVariable("PATH", "USER");[Environment]::SetEnvironmentVariable("PATH", "$current_PATH;C:\vcpkg;", "USER")

您可以将"USER"更改为"MACHINE"以更改系统环境变量(需要管理员终端,您可能需要将Environment更改为System.Environment),甚至可以将其更改为"PROCESS"以仅更改本地PATH环境变量(不会永久更改)。相应的"USER"=1 "MACHINE"=2"PROCESS"=0,这里是关于这些命令的文档:GetEnvironmentVariableSetEnvironmentVariable

我发现了另外两个答案,但有重大缺陷,不建议使用。两者均使用SETX作为PowerShell实现来永久更改环境变量。这些命令的缺点是您将复制系统PATH到您的本地路径并且需要PowerShell才能使用它们:

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

更长,但允许与其他环境变量一起使用:

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

3

打开 PowerShell 并运行:

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

2
这些脚本是幂等的(可运行多次)。它们更新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")

1
如果您需要动态设置变量名称并仅用于会话,则使用以下代码:
New-Item env:\$key -Value $value -Force | Out-Null

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接