it-roy-ru.com

Настройка переменной пути Windows PowerShell

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

Замечания:

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

483
Vasil

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

$env:Path = "SomeRandomPath";

Существуют способы сделать параметры среды постоянными, но Если вы используете их только из PowerShell, вероятно, Гораздо лучше использовать свой профиль для запуска параметров При запуске PowerShell запускает любые файлы .ps1 , Которые он находит в каталоге WindowsPowerShell в папке My Documents. Обычно у вас уже есть файл profile.ps1 Путь на моем компьютере

c:\Users\JaredPar\Documents\WindowsPowerShell\profile.ps1
331
JaredPar

Если какое-то время во время сеанса PowerShell вам необходимо Временно добавить переменную среды PATH, вы можете сделать это следующим образом:

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

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

### 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)
206
hoge

Из подсказки PowerShell:

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

Вы должны увидеть текст:

SUCCESS: Specified value was saved.

Перезапустите сеанс, и переменная будет доступна. setx также может использоваться для установки произвольных переменных. Введите setx /? в строке «Запросить документацию».

Прежде чем связываться с вашим путем таким образом, убедитесь, что вы сохранили копию существующего пути, выполнив $env:path >> a.out в приглашении PowerShell.

48
tjb

Как ответ 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 ';'
    }
}

Проверьте мой Gist для соответствующей функции Remove-EnvPath.

19
Michael Kropat

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

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

SetEnvironmentVariable превращает значение REG_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
 }

Я объясню проблему более подробно в сообщение в блоге .

9
Peter Hahndorf

Это устанавливает путь для текущего сеанса и предлагает пользователю добавить его навсегда:

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.

8
JeanT

Большинство ответов не адресованы UAC . Это охватывает вопросы UAC.

Сначала установите расширения сообщества PowerShell: choco install pscx via http://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
5
Jonathan

Поскольку Джонатан Лидеры упомянутый здесь , важно запустить команду/скрипт с повышенными правами, чтобы иметь возможность изменять переменные среды для 'machine', но выполнение некоторых команд с повышенными правами не должно быть сделано с помощью расширений сообщества, поэтому я бы хотел изменить/расширить JeanT'sanswer таким образом, что изменение машинных переменных также может быть выполнено, даже если сам скрипт не запущен с повышенными правами:

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
Mehrdad Mirreza

Опираясь на @Michael Kropat's answer Я добавил параметр для добавления нового пути к существующей PATHvariable и проверку, чтобы избежать добавления несуществующего пути:

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 ';'
            }
        }
    }
}
4
SBF

МОЕ ПРЕДЛОЖЕНИЕ IS ЭТОТ ОДИН Я ПРОВЕРИЛ ЭТО ДОБАВЛЕНИЕ 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(“;”)
1
ali Darabi

@SBF и @Michael, пожалуйста, разрешите мне присоединиться к вечеринке.

Я попытался немного оптимизировать ваш код, чтобы сделать его более компактным. 

Я полагаюсь на приведение типов в Powershell, когда он автоматически преобразует строки в значения enum, поэтому я не определил словарь поиска.

Я также вытащил блок, который добавляет новый путь в список на основе условия, чтобы работа выполнялась один раз и сохранялась в переменной для повторного использования.

Затем он применяется постоянно или только к сеансу в зависимости от параметра $ 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
Eniola

Откройте PowerShell и запустите:

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