685 Stimmen

Gibt es einen Befehl zum Aktualisieren von Umgebungsvariablen über die Eingabeaufforderung in Windows?

Wenn ich eine Umgebungsvariable ändere oder hinzufüge, muss ich die Eingabeaufforderung neu starten. Gibt es einen Befehl, den ich ausführen könnte, ohne CMD neu zu starten?

2voto

Andy McRae Punkte 381

Vielen Dank für diese Frage, die auch im Jahr 2019 noch interessant ist (in der Tat ist es nicht einfach, die Shell cmd zu erneuern, da es sich, wie oben erwähnt, um eine einzelne Instanz handelt), denn die Erneuerung von Umgebungsvariablen in Windows ermöglicht es, viele Automatisierungsaufgaben zu erledigen, ohne die Befehlszeile manuell neu starten zu müssen.

Wir nutzen dies zum Beispiel, um Software auf einer großen Anzahl von Rechnern zu installieren und zu konfigurieren, die wir regelmäßig neu installieren. Und ich muss zugeben, dass es sehr unpraktisch wäre, die Befehlszeile während der Bereitstellung unserer Software neu starten zu müssen, und dass wir nach Umgehungslösungen suchen müssten, die nicht unbedingt angenehm sind. Kommen wir nun zu unserem Problem. Wir gehen wie folgt vor.

1 - Wir haben ein Batch-Skript, das wiederum ein Powershell-Skript wie dieses aufruft

[Datei: task.cmd] .

cmd > powershell.exe -executionpolicy unrestricted -File C:\path_here\refresh.ps1

2 - Danach erneuert das Skript refresh.ps1 die Umgebungsvariablen mithilfe von Registrierungsschlüsseln (GetValueNames() usw.). Dann müssen wir im selben Powershell-Skript nur noch die neuen verfügbaren Umgebungsvariablen aufrufen. In einem typischen Fall, wenn wir zum Beispiel NodeJS zuvor mit cmd unter Verwendung von Silent-Befehlen installiert haben, können wir nach dem Aufruf der Funktion direkt npm aufrufen, um in derselben Sitzung bestimmte Pakete wie folgt zu installieren.

[Datei: refresh.ps1]

function Update-Environment {
    $locations = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session  Manager\Environment',
                 'HKCU:\Environment'
    $locations | ForEach-Object {
        $k = Get-Item $_
        $k.GetValueNames() | ForEach-Object {
            $name  = $_
            $value = $k.GetValue($_)

            if ($userLocation -and $name -ieq 'PATH') {
                $env:Path += ";$value"
            } else {

                Set-Item -Path Env:\$name -Value $value
            }
        }
        $userLocation = $true
    }
}
Update-Environment
#Here we can use newly added environment variables like for example npm install.. 
npm install -g create-react-app serve

Sobald das Powershell-Skript beendet ist, fährt das Cmd-Skript mit anderen Aufgaben fort. Zu beachten ist, dass cmd nach Abschluss der Aufgabe immer noch keinen Zugriff auf die neuen Umgebungsvariablen hat, auch wenn das Powershell-Skript diese in seiner eigenen Sitzung aktualisiert hat. Deshalb führen wir alle erforderlichen Aufgaben im Powershell-Skript aus, das natürlich die gleichen Befehle wie cmd aufrufen kann.

1voto

PhiLho Punkte 39496

Es gibt keinen geraden Weg, wie Kev sagte. In den meisten Fällen ist es einfacher, eine weitere CMD-Box zu erzeugen. Noch ärgerlicher ist, dass laufende Programme von Änderungen nichts mitbekommen (obwohl es, soweit ich mich erinnere, eine Broadcast-Nachricht gibt, mit der man über solche Änderungen informiert wird).

Es war schon schlimmer: In älteren Windows-Versionen musste man sich erst abmelden und dann wieder anmelden, um die Änderungen zu berücksichtigen...

1voto

noname Punkte 1208

Ich verwende dieses Powershell-Skript zum Hinzufügen zum PATH variabel. Mit ein wenig Anpassung kann es auch in Ihrem Fall funktionieren, glaube ich.

#REQUIRES -Version 3.0

if (-not ("win32.nativemethods" -as [type])) {
    # import sendmessagetimeout from win32
    add-type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
   IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
   uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"@
}

$HWND_BROADCAST = [intptr]0xffff;
$WM_SETTINGCHANGE = 0x1a;
$result = [uintptr]::zero

function global:ADD-PATH
{
    [Cmdletbinding()]
    param ( 
        [parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)] 
        [string] $Folder
    )

    # See if a folder variable has been supplied.
    if (!$Folder -or $Folder -eq "" -or $Folder -eq $null) { 
        throw 'No Folder Supplied. $ENV:PATH Unchanged'
    }

    # Get the current search path from the environment keys in the registry.
    $oldPath=$(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path

    # See if the new Folder is already in the path.
    if ($oldPath | Select-String -SimpleMatch $Folder){ 
        return 'Folder already within $ENV:PATH' 
    }

    # Set the New Path and add the ; in front
    $newPath=$oldPath+';'+$Folder
    Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath -ErrorAction Stop

    # Show our results back to the world
    return 'This is the new PATH content: '+$newPath

    # notify all windows of environment block change
    [win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [uintptr]::Zero, "Environment", 2, 5000, [ref]$result)
}

function global:REMOVE-PATH {
    [Cmdletbinding()]
    param ( 
        [parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)]
        [String] $Folder
    )

    # See if a folder variable has been supplied.
    if (!$Folder -or $Folder -eq "" -or $Folder -eq $NULL) { 
        throw 'No Folder Supplied. $ENV:PATH Unchanged'
    }

    # add a leading ";" if missing
    if ($Folder[0] -ne ";") {
        $Folder = ";" + $Folder;
    }

    # Get the Current Search Path from the environment keys in the registry
    $newPath=$(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path

    # Find the value to remove, replace it with $NULL. If it's not found, nothing will change and you get a message.
    if ($newPath -match [regex]::Escape($Folder)) { 
        $newPath=$newPath -replace [regex]::Escape($Folder),$NULL 
    } else { 
        return "The folder you mentioned does not exist in the PATH environment" 
    }

    # Update the Environment Path
    Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath -ErrorAction Stop

    # Show what we just did
    return 'This is the new PATH content: '+$newPath

    # notify all windows of environment block change
    [win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [uintptr]::Zero, "Environment", 2, 5000, [ref]$result)
}

# Use ADD-PATH or REMOVE-PATH accordingly.

#Anything to Add?

#Anything to Remove?

REMOVE-PATH "%_installpath_bin%"

-1voto

Um dieses Problem zu lösen, habe ich die Umgebungsvariable mit BEIDEN Methoden, setx und set, geändert und dann alle Instanzen von explorer.exe neu gestartet. Auf diese Weise hat jeder anschließend gestartete Prozess die neue Umgebungsvariable.

Mein Batch-Skript, um dies zu tun:

setx /M ENVVAR "NEWVALUE"
set ENVVAR="NEWVALUE"

taskkill /f /IM explorer.exe
start explorer.exe >nul
exit

Das Problem bei diesem Ansatz ist, dass alle derzeit geöffneten Explorer-Fenster geschlossen werden, was wahrscheinlich eine schlechte Idee ist - aber lesen Sie den Beitrag von Kev, um zu erfahren, warum dies notwendig ist

-1voto

wardies Punkte 1031

Bearbeiten: Dies funktioniert nur, wenn die Umgebungsänderungen, die Sie vornehmen, das Ergebnis der Ausführung einer Batch-Datei sind.

Beginnt eine Batch-Datei mit SETLOCAL dann wird es sich beim Beenden immer in die ursprüngliche Umgebung zurückentwickeln, selbst wenn Sie vergessen, die ENDLOCAL bevor der Batch beendet wird, oder wenn er unerwartet abbricht.

Fast jede Batch-Datei, die ich schreibe, beginnt mit SETLOCAL da ich in den meisten Fällen nicht möchte, dass die Nebeneffekte von Umgebungsänderungen bestehen bleiben. In den Fällen, in denen ich möchte, dass bestimmte Umgebungsvariablenänderungen außerhalb der Batchdatei weitergegeben werden, ist meine letzte ENDLOCAL sieht so aus:

ENDLOCAL & (
  SET RESULT1=%RESULT1%
  SET RESULT2=%RESULT2%
)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X