Настройка переменных среды Windows PowerShell


608

Я обнаружил, что установка переменной среды PATH влияет только на старую командную строку. В PowerShell, похоже, разные настройки среды. Как изменить переменные среды для PowerShell (v1)?

Замечания:

Я хочу сделать свои изменения постоянными, поэтому мне не нужно их устанавливать каждый раз, когда я запускаю PowerShell. Есть ли в PowerShell файл профиля? Что-то вроде профиля Bash в Unix?


1
Я бы хотел, чтобы центральный профиль находился в общей папке. Синхронизация - это боль. Создание профиля заглушки с. \\ computer \ share \ path \ Profile.ps1 выглядит как кладж (попробуйте Notepad $ Profile). Было бы хорошо, если бы существовал способ навсегда изменить автоматическую переменную $ Profile.
Натан Хартли,

5
Никакая среда PATH также не влияет на командную строку powershell. Однако отличается то, что powershell не принимает пути, заключенные в кавычки. Решение: удалите все заключающие в кавычки ( ") в переменной окружения пути
Nilzor

3
ЕСЛИ ВЫ ЗЕМЛЯЕТЕ ЗДЕСЬ ДЛЯ PS> v1 ... В дополнение к комментарию Нильзора выше: используйте это, чтобы удалить все "из путей в переменной среды PATH для вашего сеанса:$($Env:PATH).Split(';') | %{ $str += "$($_.Trim('"'));" }; $Env:PATH=$str
d3r3kk

Ответы:


479

Изменение фактических переменных среды может быть сделано с помощью env: namespace / driveинформации. Например, этот код обновит переменную окружения path:

$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
Обратите внимание, что (split-path $ 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".
Льюистрик

7
@Lewistrick У вас нет профиля по умолчанию. Я следовал этим инструкциям, чтобы создать его: howtogeek.com/50236/customizing-your-powershell-profile
MikeB

16
Будьте осторожны при этом - это загубит ваш существующий путь. $env:Path = "SomeRandomPath"; Вместо этого - см. @Mloskot, ниже.
Джон Марк

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

11
Если вам нужно, чтобы ваш путь вызывался раньше стандартного, вставьте его в начале $env:Path = "C:\MyPath;$env:Path"
Michael Freidgeim

4
**** Не забывайте точку с запятой в начале добавляемой строки, как видно из комментария @Kevin. Это довольно очевидно, но это может быть упущено, если вы просто скопируете / вставите код в ответ и у вас не будет точки с запятой в конце существующего пути. Я постараюсь отправить изменения.
Мэтт Гудрич

1
@MattGoodrich У меня откат к предыдущей ревизии
Cœur

278

Вы также можете изменять переменные пользователя / среды системы постоянно (т.е. будет стойким через подставных перезагружается) со следующим:

Изменить системную переменную среды

[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

14
@AndresRiofrio, да, это постоянно. Использование: [Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\bin", [EnvironmentVariableTartget::Machine) Вы не увидите результат этого изменения, пока не начнете новый сеанс PowerShell. То есть, если вы проверите $ env: Path сразу после выполнения этой команды, вы увидите, что $ env: Path было до команды. Для обновления закройте и откройте оболочку или начните новый сеанс.
FLGMwt

7
@FLGM, если у вас есть опечатка, правильно это: [Environment] :: SetEnvironmentVariable ("Путь", $ env: Path + "; C: \ bin", [EnvironmentVariableTarget] :: Machine)
энтузиаст

10
Вы можете написать строку «Machine» или «User» вместо всего перечисления .NET. Из техн .
Bouvierr

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
Ой - только что получил ограничение в 1024 символа setx; К счастью, я последовал совету записать существующее значение $ end: Path. Просто кое-что, о чем нужно знать: superuser.com/questions/387619/…
Джонно,

3
Почему бы не установить $env:PATHсначала, а затем, setx /m PATH "$env:PATH"чтобы он применялся локально и глобально без перезапуска оболочки?
tresf

1
Ницца! Хотя setx не является родным командлетом, он все же является гораздо лучшей и легко забываемой альтернативой этим отвратительным долгим вызовам .NET Framework! Это сбивает с толку, что даже Powershell 7 все еще не поставляется с официальным командлетом для сохранения envvars. Какая. По ощущениям функция, которая должна иметь паритет с '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

Хотя текущий принятый ответ работает в том смысле, что переменная пути постоянно обновляется из контекста 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

Все ответы, предлагающие постоянное изменение, имеют одну и ту же проблему: они нарушают значение реестра пути.

SetEnvironmentVariableпревращает REG_EXPAND_SZзначение %SystemRoot%\system32 в REG_SZзначение C:\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

Как упоминал здесь Джонатан Лидерс , важно запустить команду / скрипт с повышенными правами, чтобы иметь возможность изменять переменные среды для «машины» , но выполнение некоторых команд с повышенными правами необязательно выполнять с помощью расширений сообщества, поэтому я бы хотел чтобы изменить и расширить ответ 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.

Сначала установите PowerShell Community Extensions: choco install pscxчерез http://chocolatey.org/ (возможно, вам придется перезапустить среду оболочки).

Затем включите 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\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(“;”)

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

Я попытался немного оптимизировать код 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.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/, так 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"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.