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?
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
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"
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)
À 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.
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:
$env:Path
pour que le changement prenne effet dans la session en coursAu 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.
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
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 .
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
.
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
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
}
}
En s'appuyant sur @Michael Kropat answer, j'ai ajouté un paramètre pour ajouter le nouveau chemin à la variable PATH
variable 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 ';'
}
}
}
}
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(“;”)
@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.
Ouvrez PowerShell et exécutez:
[Environment]::SetEnvironmentVariable("PATH", "$ENV:PATH;<path to exe>", "USER")
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