web-dev-qa-db-fra.com

Définition de la variable de chemin d'accès Windows PowerShell

J'ai découvert que la définition de la variable d'environnement PATH n'affecte que l'ancienne commande Invite. PowerShell semble avoir différents paramètres d'environnement. Comment modifier les variables d'environnement pour PowerShell (v1)?

Remarque:

Je souhaite que mes modifications soient permanentes. Je n'ai donc pas à les définir chaque fois que j'exécute PowerShell. PowerShell a-t-il un fichier de profil? Quelque chose comme profil Bash sur Unix?

483
Vasil

Vous pouvez modifier les variables d’environnement réelles avec En utilisant les informations env: namespace / drive. Par exemple, ce code Mettra à jour la variable d’environnement du chemin:

$env:Path = "SomeRandomPath";

Il existe différentes manières de rendre les paramètres d'environnement permanents, mais Si vous ne les utilisez que depuis PowerShell, il est probablement préférable de D'utiliser votre profil pour définir les paramètres Au démarrage, PowerShell exécute tous les fichiers .ps1 Qu'il trouve dans le répertoire WindowsPowerShell sous le dossier My Documents. Généralement, vous avez déjà un fichier profile.ps1 Le chemin sur mon ordinateur est

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

Si, au cours d'une session PowerShell, vous devez Ajouter temporairement à la variable d'environnement PATH, vous pouvezdo le faire de cette façon:

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

Vous pouvez également modifier les variables d’environnement utilisateur/système de manière permanente (c’est-à-dire qu'elles seront persistantes lors des redémarrages de Shell) avec les éléments suivants:

### 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

À partir de l'invite PowerShell:

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

Vous devriez alors voir le texte:

SUCCESS: Specified value was saved.

Redémarrez votre session et la variable sera disponible. setx peut également être utilisé pour définir des variables arbitraires. Tapez setx /? à l'invite de documentation.

Avant de modifier votre chemin de cette façon, assurez-vous de sauvegarder une copie de votre chemin existant en effectuant $env:path >> a.out dans une invite PowerShell.

48
tjb

Comme la réponse de JeanT , je voulais une abstraction pour ajouter du chemin. Contrairement à la réponse de JeanT, je devais l'exécuter sans interaction de l'utilisateur. Autre comportement que je cherchais:

  • Met à jour $env:Path pour que le changement prenne effet dans la session en cours
  • Maintient le changement de variable d'environnement pour les sessions futures
  • N'ajoute pas un chemin dupliqué lorsque le même chemin existe déjà

Au cas où cela serait utile, le voici:

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

Découvrez my Gist pour la fonction Remove-EnvPath correspondante.

19
Michael Kropat

Bien que la réponse acceptée actuellement fonctionne en ce sens que la variable de chemin d'accès est mise à jour de manière permanente à partir du contexte de PowerShell, elle ne met pas à jour la variable d'environnement stockée dans le registre Windows.

Pour ce faire, vous pouvez évidemment utiliser PowerShell également:

$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

Vous trouverez plus d'informations dans l'article de blog - Utilisez PowerShell pour modifier votre trajectoire environnementale

Si vous utilisez des extensions de communauté PowerShell, la commande appropriée pour ajouter un chemin au chemin de la variable d'environnement est la suivante:

Add-PathVariable "C:\NewFolderToAddToTheList" -Target Machine
15
gijswijs

Toutes les réponses suggérant un changement permanent ont le même problème: elles cassent la valeur du registre de chemin.

SetEnvironmentVariable transforme la REG_EXPAND_SZ valeur %SystemRoot%\system32 en une REG_SZ valeur de C:\Windows\system32.

Toutes les autres variables du chemin sont également perdues. L'ajout de nouveaux avec %myNewPath% ne fonctionnera plus.

Voici un script Set-PathVariable.ps1 que j'utilise pour résoudre ce problème:

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

J'explique le problème plus en détail dans un article de blog .

9
Peter Hahndorf

Cela définit le chemin de la session en cours et invite l'utilisateur à l'ajouter définitivement:

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

Vous pouvez ajouter cette fonction à votre profil par défaut (Microsoft.PowerShell_profile.ps1), généralement situé à %USERPROFILE%\Documents\WindowsPowerShell.

8
JeanT

La plupart des réponses ne concernent pas UAC . Ceci couvre les problèmes de l'UAC.

Installez d’abord les extensions de communauté PowerShell: choco install pscx via http://chocolatey.org/ (vous devrez peut-être redémarrer votre environnement Shell).

Puis activez pscx

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #allows scripts to run from the interwebs, such as pcsx

Puis utilisez Invoke-Elevated 

Invoke-Elevated {Add-PathVariable $args[0] -Target Machine} -ArgumentList $MY_NEW_DIR
5
Jonathan

Comme Jonathan Leaders mentionne ici , il est important d'exécuter la commande/script elevated pour pouvoir modifier les variables d'environnement pour 'machine', mais l'exécution de certaines commandes elevées ne doit pas obligatoirement faire avec les extensions de la communauté, je voudrais donc modifier et étendre JeanT'sanswer en quelque sorte, qu'il est également possible de modifier les variables de la machine même si le script lui-même n'est pas exécuté surélevé:

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

En s'appuyant sur @Michael Kropat answer, j'ai ajouté un paramètre pour ajouter le nouveau chemin à la variable PATHvariable existante, ainsi qu'une vérification pour éviter l'ajout d'un chemin inexistant:

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

MON SUGGESTION IS CELUI-CI J’AI TESTÉ CELUI-CI POUR AJOUTER C:\Oracle\x64\bin à Path de façon permanente et cela fonctionne bien.

$ENV:PATH

La première façon consiste simplement à faire:

$ENV:PATH=”$ENV:PATH;c:\path\to\folder”

Mais ce changement n’est pas permanent, $ env: path retournera à ce qu’il était avant dès que vous fermez votre terminal powershell et le rouvrez à nouveau. C’est parce que vous avez appliqué la modification au niveau de la session et non au niveau de la source (qui est le niveau du registre). Pour afficher la valeur globale de $ env: path, faites:

Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH

ou plus spécifiquement:

(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path

Maintenant, pour changer cela, commençons par capturer le chemin original qui doit être modifié:

$oldpath = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path

Maintenant, nous définissons à quoi le nouveau chemin devrait ressembler, dans ce cas, nous ajoutons un nouveau dossier:

$newpath = “$oldpath;c:\path\to\folder”

Remarque: assurez-vous que $ newpath ressemble à ce que vous voulez, sinon vous pourriez endommager votre système d'exploitation.

Appliquez maintenant la nouvelle valeur:

Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH -Value $newPath

Maintenant, faites une dernière vérification pour vous assurer que tout se passe comme prévu:

(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).Path

Vous pouvez maintenant redémarrer votre terminal powershell (ou même redémarrer votre ordinateur) et vérifier qu’il ne reviendra pas à son ancienne valeur. Notez que l’ordre des chemins peut changer pour s’inscrire dans l’ordre alphabétique. Veillez donc à vérifier toute la ligne. Pour faciliter les choses, vous pouvez fractionner la sortie en lignes en utilisant le point-virgule comme séparateur:

($env:path).split(“;”)
1
ali Darabi

@SBF et @Michael, permettez-moi de rejoindre la fête.

J'ai essayé d'optimiser un peu votre code pour le rendre plus compact. 

Je me fie à la coercition de caractères de Powershell, qui convertit automatiquement les chaînes en valeurs enum. Je n'ai donc pas défini le dictionnaire de recherche.

J'ai également extrait le bloc qui ajoute le nouveau chemin d'accès à la liste en fonction d'une condition, de sorte que le travail est effectué une fois et stocké dans une variable pour être réutilisé.

Il est ensuite appliqué de manière permanente ou uniquement à la session en fonction du paramètre $ PathContainer.

Nous pouvons placer le bloc de code dans une fonction ou dans un fichier ps1 que nous appelons directement à partir de la commande Invite. Je suis allé avec 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;

Je fais quelque chose de similaire pour un 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;

Jusqu'à présent, ils semblent fonctionner. Je vais apprécier vos commentaires.

La question et les différentes réponses m'ont vraiment fait réfléchir.

0
Eniola

Ouvrez PowerShell et exécutez:

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

Dans Powershell, il est possible de naviguer dans le répertoire des variables d’environnement en tapant:

Set-Location Env:

Cela vous mènera au répertoire Env:>. Dans ce répertoire:

Pour voir toutes les variables d'environnement, tapez:

Env:\> Get-ChildItem

Pour voir une variable d'environnement spécifique, tapez:

Env:\> $Env:<variable name>, e.g. $Env:Path

Pour définir une variable d'environnement, tapez:

Env:\> $Env:<variable name> = "<new-value>", e.g. $Env:Path="C:\Users\"

Pour supprimer une variable d'environnement, tapez:

Env:\> remove-item Env:<variable name>, e.g. remove-item Env:SECRET_KEY

Plus d'informations ici: https://docs.Microsoft.com/en-us/powershell/module/Microsoft.powershell.core/about/about_environment_variables?view=powershell-6

0
Paul Maurer