Ich habe herausgefunden, dass das Setzen der Umgebungsvariable PATH nur die alte Eingabeaufforderung betrifft. Die PowerShell scheint unterschiedliche Umgebungseinstellungen zu haben. Wie ändere ich die Umgebungsvariablen für PowerShell (v1)?
Hinweis:
Ich möchte meine Änderungen dauerhaft machen, sodass ich sie nicht bei jedem Start von PowerShell festlegen muss. Hat PowerShell eine Profildatei? So etwas wie das Bash-Profil unter Unix?
Das Ändern der tatsächlichen Umgebungsvariablen kann mit Unter Verwendung der env: namespace / drive
-Informationen vorgenommen werden. Mit diesem -Code wird beispielsweise die Pfadumgebungsvariable aktualisiert:
$env:Path = "SomeRandomPath";
Es gibt Möglichkeiten, die Umgebungseinstellungen dauerhaft festzulegen, aber Wenn Sie sie nur von PowerShell aus verwenden, ist es wahrscheinlich Viel besser, Ihr Profil zu verwenden, um die Beim Start führt PowerShell alle .ps1 -Dateien aus, die im WindowsPowerShell-Verzeichnis unterMein Ordner Dokumente gefunden werden. Normalerweise haben Sie bereits eine Datei profile.ps1 Der Pfad auf meinem Computer lautet
c:\Users\JaredPar\Documents\WindowsPowerShell\profile.ps1
Wenn Sie während einer PowerShell-Sitzung vorübergehend an die Umgebungsvariable PATH anhängen müssen, können Sie.
$env:Path += ";C:\Program Files\GnuWin32\bin"
Sie können Benutzer-/Systemumgebungsvariablen auch dauerhaft ändern (d. H. Bleiben bei Shell-Neustarts bestehen).
### 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)
Aus der PowerShell-Eingabeaufforderung:
setx PATH "$env:path;\the\directory\to\add" -m
Sie sollten dann den Text sehen:
SUCCESS: Specified value was saved.
Starten Sie Ihre Sitzung neu und die Variable ist verfügbar. setx
kann auch verwendet werden, um beliebige Variablen festzulegen. Geben Sie an der Eingabeaufforderung für die Dokumentation setx /?
ein.
Stellen Sie sicher, dass Sie eine Kopie des vorhandenen Pfads speichern, indem Sie $env:path >> a.out
in einer PowerShell-Eingabeaufforderung ausführen, bevor Sie den Pfad auf diese Weise mit dem Pfad vermischen.
Wie die Antwort von JeanT wollte ich eine Abstraktion um den Pfad. Im Gegensatz zu Jeants Antwort musste ich es ohne Benutzerinteraktion laufen lassen. Anderes Verhalten, das ich gesucht habe:
$env:Path
, damit die Änderung in der aktuellen Sitzung wirksam wirdFalls es nützlich ist, hier ist es:
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 ';'
}
}
Check out my Gist für die entsprechende Remove-EnvPath
-Funktion.
Obwohl die aktuell akzeptierte Antwort dahingehend funktioniert, dass die Pfadvariable permanent aus dem Kontext von PowerShell aktualisiert wird, wird die in der Windows-Registrierung gespeicherte Umgebungsvariable nicht aktualisiert.
Um dies zu erreichen, können Sie natürlich auch PowerShell verwenden:
$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
Weitere Informationen finden Sie im Blogbeitrag Verwenden Sie PowerShell, um den Umgebungspfad zu ändern.
Wenn Sie PowerShell-Community-Erweiterungen verwenden, lautet der richtige Befehl zum Hinzufügen eines Pfads zum Umgebungsvariablenpfad:
Add-PathVariable "C:\NewFolderToAddToTheList" -Target Machine
Alle Antworten, die auf eine dauerhafte Änderung schließen lassen, haben dasselbe Problem: Sie beschädigen den Pfadregistrierungswert.
SetEnvironmentVariable
wandelt den REG_EXPAND_SZ
-Wert %SystemRoot%\system32
in einen REG_SZ
-Wert von C:\Windows\system32
.
Alle anderen Variablen im Pfad gehen ebenfalls verloren. Das Hinzufügen neuer mit %myNewPath%
funktioniert nicht mehr.
Hier ist ein Skript Set-PathVariable.ps1
, das ich zur Behebung dieses Problems verwende:
[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
}
Ich erkläre das Problem ausführlicher in einem Blogbeitrag .
Dadurch wird der Pfad für die aktuelle Sitzung festgelegt und der Benutzer wird aufgefordert, die Sitzung dauerhaft hinzuzufügen:
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'
}
}
Sie können diese Funktion zu Ihrem Standardprofil (Microsoft.PowerShell_profile.ps1
) hinzufügen, das sich normalerweise unter %USERPROFILE%\Documents\WindowsPowerShell
befindet.
Die meisten Antworten beziehen sich nicht auf UAC . Dies deckt UAC-Probleme ab.
Installieren Sie zuerst die PowerShell Community Extensions: choco install pscx
über http://chocolatey.org/ (möglicherweise müssen Sie Ihre Shell-Umgebung neu starten).
Dann aktivieren Sie pscx
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #allows scripts to run from the interwebs, such as pcsx
Dann benutze Invoke-Elevated
Invoke-Elevated {Add-PathVariable $args[0] -Target Machine} -ArgumentList $MY_NEW_DIR
Als Jonathan Leaders erwähnte hier ist es wichtig, den Befehl/das Skript erhöht auszuführen, um Umgebungsvariablen für 'machine' ändern zu können, aber das Ausführen einiger Befehle, die erhöht sind, muss nicht sein mit den Community-Erweiterungen, also möchte ich JeanTsanswer so modifizieren und erweitern, dass das Ändern von Maschinenvariablen auch dann ausgeführt werden kann, wenn das Skript selbst nicht als erhöht ausgeführt wird:
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
}
}
Aufbauend auf @Michael Kropats answer habe ich einen Parameter hinzugefügt, um den neuen Pfad vor der vorhandenen Variable PATH
zu setzen, und eine Prüfung, um das Hinzufügen eines nicht vorhandenen Pfads zu vermeiden:
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 ';'
}
}
}
}
MEIN VORSCHLAG IS DIESE EINE Ich habe das getestet, um C:\Oracle\x64\bin dauerhaft zu Path hinzuzufügen, und das funktioniert einwandfrei.
$ENV:PATH
Der erste Weg ist einfach zu tun:
$ENV:PATH=”$ENV:PATH;c:\path\to\folder”
Diese Änderung ist jedoch nicht von Dauer, denn $ env: path wird auf den vorherigen Wert zurückgesetzt, sobald Sie Ihr Powershell-Terminal schließen und es wieder öffnen. Das liegt daran, dass Sie die Änderung auf der Sitzungsebene und nicht auf der Quellenebene (dies ist die Registrierungsebene) vorgenommen haben. Führen Sie die folgenden Schritte aus, um den globalen Wert von $ env: path anzuzeigen:
Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH
oder genauer:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path
Um dies zu ändern, erfassen wir zuerst den ursprünglichen Pfad, der geändert werden muss:
$oldpath = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).path
Nun definieren wir, wie der neue Pfad aussehen soll. In diesem Fall hängen wir einen neuen Ordner an:
$newpath = “$oldpath;c:\path\to\folder”
Hinweis: Stellen Sie sicher, dass $ newpath so aussieht, wie er aussehen soll. Andernfalls könnten Sie Ihr Betriebssystem beschädigen.
Wenden Sie jetzt den neuen Wert an:
Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH -Value $newPath
Überprüfen Sie nun noch einmal, ob es so aussieht, wie Sie es erwarten:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PATH).Path
Sie können jetzt Ihr Powershell-Terminal neu starten (oder sogar einen Neustart durchführen) und sehen, dass es nicht mehr auf den alten Wert zurückgesetzt wird. Beachten Sie, dass sich die Reihenfolge der Pfade möglicherweise in alphabetischer Reihenfolge ändert. Stellen Sie daher sicher, dass Sie die gesamte Zeile überprüfen. Zur Vereinfachung können Sie die Ausgabe in Zeilen aufteilen, indem Sie das Semikolon als Trennzeichen verwenden:
($env:path).split(“;”)
@SBF und @Michael, bitte erlauben Sie mir, an der Party teilzunehmen.
Ich habe versucht, Ihren Code ein wenig zu optimieren, um ihn kompakter zu gestalten.
Ich verlasse mich auf Powershells Typenzwang, bei dem Zeichenfolgen automatisch in Enumewerte konvertiert werden, sodass ich das Nachschlagewörterbuch nicht definiert habe.
Ich habe auch den Block herausgezogen, der den neuen Pfad basierend auf einer Bedingung zur Liste hinzufügt, so dass die Arbeit einmal ausgeführt und in einer Variablen zur Wiederverwendung gespeichert wird.
Sie wird dann abhängig vom Parameter $ PathContainer dauerhaft oder nur auf die Sitzung angewendet.
Wir können den Codeblock in eine Funktion oder eine ps1-Datei einfügen, die wir direkt vom Befehl Prompt aus aufrufen. Ich bin mit DevEnvAddPath.ps1 gegangen.
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;
Ich mache etwas Ähnliches für eine 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;
Bisher scheinen sie zu funktionieren. Ich freue mich über jede Rückmeldung.
Die Frage und die verschiedenen Antworten haben mich wirklich zum Nachdenken gebracht.
Öffnen Sie PowerShell und führen Sie Folgendes aus:
[Environment]::SetEnvironmentVariable("PATH", "$ENV:PATH;<path to exe>", "USER")
In Powershell können Sie zum Verzeichnis der Umgebungsvariablen navigieren, indem Sie Folgendes eingeben:
Set-Location Env:
Dadurch gelangen Sie in das Verzeichnis Env:>. Aus diesem Verzeichnis heraus:
Geben Sie Folgendes ein, um alle Umgebungsvariablen anzuzeigen:
Env:\> Get-ChildItem
Geben Sie Folgendes ein, um eine bestimmte Umgebungsvariable anzuzeigen:
Env:\> $Env:<variable name>, e.g. $Env:Path
Geben Sie Folgendes ein, um eine Umgebungsvariable festzulegen:
Env:\> $Env:<variable name> = "<new-value>", e.g. $Env:Path="C:\Users\"
Geben Sie Folgendes ein, um eine Umgebungsvariable zu entfernen:
Env:\> remove-item Env:<variable name>, e.g. remove-item Env:SECRET_KEY
Weitere Informationen finden Sie hier: https://docs.Microsoft.com/en-us/powershell/module/Microsoft.powershell.core/about/about_environment_variables?view=powershell-6