Gibt es einen Befehl zum Aktualisieren von Umgebungsvariablen an der Eingabeaufforderung in Windows?

480

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?

Eric Schoonover
quelle
38
Tatsächlich muss jedes Programm, das sie sehen muss, neu gestartet werden. Die Umgebung wird beim Start in den Speicher des Prozesses kopiert und hat daher keinerlei Verbindung mehr zu den systemdefinierten Envvars.
Joey
15
Nachdem ich diese gelesen hatte, stellte ich fest, dass es keinen Löffel gibt ;) In der realen Welt starten Sie einfach cmd neu.
n611x007
Kein Befehl, also keine Antwort, aber es gibt Unterstützung für die Verwendung der Win32-API, wenn ich Folgendes richtig gelesen habe: support.microsoft.com/en-us/help/104011/… Sollte in der Lage sein, diese Zeile in eine zu kompilieren einfaches C-Programm und führen Sie es nach Aktualisierungen der Umgebungsvariablen aus.
Charles Grunwald
WM_SETTINGCHANGE (die von @CharlesGrunwald erwähnte Win32-API) funktioniert laut diesem Thread nicht für cmd.exe-Fenster: github.com/chocolatey/choco/issues/1589 - aus diesem Grund haben sie den Befehl
refresheshenv geschrieben

Antworten:

137

Sie können die Systemumgebungsvariablen mit einem vbs-Skript erfassen, benötigen jedoch ein bat-Skript, um die aktuellen Umgebungsvariablen tatsächlich zu ändern. Dies ist also eine kombinierte Lösung.

Erstellen Sie eine Datei resetvars.vbsmit diesem Code und speichern Sie sie im Pfad:

Set oShell = WScript.CreateObject("WScript.Shell")
filename = oShell.ExpandEnvironmentStrings("%TEMP%\resetvars.bat")
Set objFileSystem = CreateObject("Scripting.fileSystemObject")
Set oFile = objFileSystem.CreateTextFile(filename, TRUE)

set oEnv=oShell.Environment("System")
for each sitem in oEnv 
    oFile.WriteLine("SET " & sitem)
next
path = oEnv("PATH")

set oEnv=oShell.Environment("User")
for each sitem in oEnv 
    oFile.WriteLine("SET " & sitem)
next

path = path & ";" & oEnv("PATH")
oFile.WriteLine("SET PATH=" & path)
oFile.Close

Erstellen Sie einen anderen Dateinamen resetvars.bat, der diesen Code enthält, denselben Speicherort:

@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"

Wenn Sie die Umgebungsvariablen aktualisieren möchten, führen Sie sie einfach aus resetvars.bat


Entschuldigung :

Die beiden Hauptprobleme, die ich bei dieser Lösung hatte, waren

ein. Ich konnte keine einfache Möglichkeit finden, Umgebungsvariablen aus einem vbs-Skript zurück an die Eingabeaufforderung zu exportieren, und

b. Die Umgebungsvariable PATH ist eine Verkettung der PATH-Variablen des Benutzers und des Systems.

Ich bin mir nicht sicher, wie die allgemeine Regel für widersprüchliche Variablen zwischen Benutzer und System lautet. Daher habe ich mich dafür entschieden, das System vom Benutzer außer Kraft zu setzen, außer in der PATH-Variablen, die speziell behandelt wird.

Ich benutze den seltsamen vbs + bat + temporären bat-Mechanismus, um das Problem des Exportierens von Variablen aus vbs zu umgehen.

Hinweis : Dieses Skript löscht keine Variablen.

Dies kann wahrscheinlich verbessert werden.

HINZUGEFÜGT

Wenn Sie die Umgebung von einem Cmd-Fenster in ein anderes exportieren müssen, verwenden Sie dieses Skript (nennen wir es exportvars.vbs):

Set oShell = WScript.CreateObject("WScript.Shell")
filename = oShell.ExpandEnvironmentStrings("%TEMP%\resetvars.bat")
Set objFileSystem = CreateObject("Scripting.fileSystemObject")
Set oFile = objFileSystem.CreateTextFile(filename, TRUE)

set oEnv=oShell.Environment("Process")
for each sitem in oEnv 
    oFile.WriteLine("SET " & sitem)
next
oFile.Close

Führen Sie exportvars.vbsin dem Fenster , das Sie exportieren möchten , aus , wechseln Sie dann zu dem Fenster , das Sie exportieren möchten auf , und geben Sie :

"%TEMP%\resetvars.bat"
itsadok
quelle
2
Vielleicht können Sie die temporäre Datei vermeiden, indem Sie FOR / F "tokens = 1, *" %% c IN ('resetvars.vbs') DO-Konstrukt
tzot
2
Wie ich in meiner Antwort gesagt habe "oder manuell mit SET in der vorhandenen Eingabeaufforderung hinzufügen." Das ist es, was dies effektiv tut. Gute Antwort.
Kev
2
@itsadok - Da dies nun die akzeptierte Antwort ist, sollten Sie zu Beginn eine kurze Erklärung hinzufügen, um das Skript in einen Kontext zu setzen. Weisen Sie darauf hin, dass es nicht möglich ist, eine Änderung von env var an eine offene cmd.exe weiterzugeben, ohne sie manuell wie oben zu aktualisieren oder cmd.exe neu zu starten.
Kev
Das Skript behandelt den Anwendungsfall des globalen Änderns von Umgebungsvariablen in "Arbeitsplatz ... Umgebungsvariablen". Wenn jedoch eine Umgebungsvariable in einer cmd.exe geändert wird, wird sie vom Skript nicht an eine andere laufende cmd.exe weitergegeben, die meiner Meinung nach ausgeführt wird wahrscheinlich ein häufiges Szenario.
Kev
1
@Keyslinger: Das ist eigentlich nicht möglich. Jedes erzeugte Programm kann seine eigene Umgebung aktualisieren, jedoch nicht die der laufenden cmd.exe-Instanz. Eine Batchdatei KANN die cmd.exe-Umgebung aktualisieren, da sie in derselben Instanz von cmd.exe ausgeführt wird.
Ben Voigt
112

Hier ist, was Chocolatey verwendet.

https://github.com/chocolatey/choco/blob/master/src/chocolatey.resources/redirects/RefreshEnv.cmd

@echo off
::
:: RefreshEnv.cmd
::
:: Batch file to read environment variables from registry and
:: set session variables to these values.
::
:: With this batch file, there should be no need to reload command
:: environment every time you want environment changes to propagate

echo | set /p dummy="Reading environment variables from registry. Please wait... "

goto main

:: Set one environment variable from registry key
:SetFromReg
    "%WinDir%\System32\Reg" QUERY "%~1" /v "%~2" > "%TEMP%\_envset.tmp" 2>NUL
    for /f "usebackq skip=2 tokens=2,*" %%A IN ("%TEMP%\_envset.tmp") do (
        echo/set %~3=%%B
    )
    goto :EOF

:: Get a list of environment variables from registry
:GetRegEnv
    "%WinDir%\System32\Reg" QUERY "%~1" > "%TEMP%\_envget.tmp"
    for /f "usebackq skip=2" %%A IN ("%TEMP%\_envget.tmp") do (
        if /I not "%%~A"=="Path" (
            call :SetFromReg "%~1" "%%~A" "%%~A"
        )
    )
    goto :EOF

:main
    echo/@echo off >"%TEMP%\_env.cmd"

    :: Slowly generating final file
    call :GetRegEnv "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" >> "%TEMP%\_env.cmd"
    call :GetRegEnv "HKCU\Environment">>"%TEMP%\_env.cmd" >> "%TEMP%\_env.cmd"

    :: Special handling for PATH - mix both User and System
    call :SetFromReg "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" Path Path_HKLM >> "%TEMP%\_env.cmd"
    call :SetFromReg "HKCU\Environment" Path Path_HKCU >> "%TEMP%\_env.cmd"

    :: Caution: do not insert space-chars before >> redirection sign
    echo/set Path=%%Path_HKLM%%;%%Path_HKCU%% >> "%TEMP%\_env.cmd"

    :: Cleanup
    del /f /q "%TEMP%\_envset.tmp" 2>nul
    del /f /q "%TEMP%\_envget.tmp" 2>nul

    :: Set these variables
    call "%TEMP%\_env.cmd"

    echo | set /p dummy="Done"
    echo .
anonymer Feigling
quelle
65
+1 Wenn Sie Chocolatey installiert haben, können Sie einfach ausführen RefreshEnv, um aktualisierte Umgebungsvariablen in Ihre aktuelle Sitzung aufzunehmen.
Martin Valgur
2
Dies ist eine unglaublich nützliche Dienstprogramm-Software, vielen Dank für das Teilen.
Sabuncu
10
Hinweis: Chocolatey hat Repos verschoben und die neueste Version dieses Skripts finden Sie hier (mit einigen Fehlerkorrekturen): github.com/chocolatey/choco/blob/master/src/…
Michael Burr
1
sollte das auch funktionieren Powershell? Es scheint nur cmd.exefür mich zu funktionieren .
Craq
1
Es funktioniert für mich in PowerShell, @craq. Ausführen von Windows10 x64.
Mazunki
100

Unter Windows 7/8/10 können Sie Chocolatey installieren, das ein Skript für dieses integrierte Programm enthält.

Geben Sie nach der Installation von Chocolatey einfach ein refreshenv.

lustig
quelle
Dies ist eine gültige Antwort. Es wäre schön, von einem Mann zu hören, der sie abgelehnt hat
the_joric
2
Was mache ich falsch? $> refreshesv 'refreshesv' wird nicht als interner oder externer Befehl, bedienbares Programm oder Batchdatei erkannt.
Aclokay
@aclokay Nicht sicher. Bitte geben Sie weitere Details zu Ihrer Systemkonfektion zum Debuggen an. In der Zwischenzeit können Sie hier auf ein ähnliches offenes Thema verweisen. github.com/chocolatey/choco/issues/250
lustiger
Bei mir funktioniert es auch nicht. Ich bin auf W7 Professional, vielleicht funktioniert es nur in vollständigeren Versionen.
auch
1
Wenn Ihr Skript vorzeitig aktualisiert wird (wie bei mir), können Sie stattdessen "RefreshEnv.cmd aufrufen" verwenden. (siehe github.com/chocolatey/choco/issues/1461 )
sfiss
59

Von Natur aus gibt es keine eingebaute für Windows Mechanismus zum Weitergeben einer Umgebungsvariablen zum Hinzufügen / Ändern / Entfernen an eine bereits ausgeführte cmd.exe, entweder von einer anderen cmd.exe oder von "Arbeitsplatz -> Eigenschaften -> Erweiterte Einstellungen ->" Umgebungsvariablen".

Wenn Sie eine neue Umgebungsvariable außerhalb des Bereichs einer vorhandenen offenen Eingabeaufforderung ändern oder hinzufügen, müssen Sie entweder die Eingabeaufforderung neu starten oder manuell mit SET in der vorhandenen Eingabeaufforderung hinzufügen.

Die zuletzt akzeptierte Antwort zeigt eine teilweise Umgehung durch manuelles Aktualisieren aller Umgebungsvariablen in einem Skript. Das Skript behandelt den Anwendungsfall des globalen Änderns von Umgebungsvariablen in "Arbeitsplatz ... Umgebungsvariablen". Wenn jedoch eine Umgebungsvariable in einer cmd.exe geändert wird, wird sie vom Skript nicht an eine andere laufende cmd.exe weitergegeben.

Kev
quelle
Wenn jemand eine funktionierende Lösung für dieses Problem hat, werde ich regelmäßig einchecken und möglicherweise die akzeptierte Antwort ändern.
Eric Schoonover
1
Dies sollte nicht die akzeptierte Antwort sein, nur weil sie die gestellte Frage nicht beantwortet. Diese Frage sollte ohne akzeptierte Antwort bleiben, bis eine gefunden wird.
Shoosh
4
Und ärgerlicherweise zählen zusätzliche Instanzen von cmd.exe nicht. Sie müssen alle getötet werden, bevor sich die Änderung in einer neuen cmd.exe widerspiegelt.
6
Die negativen Kommentare und die Abwärtsmarkierung dieser Antwort zeigen, wie zeitweise der Stapelüberlauf unterbrochen ist. Kev hat die richtige Antwort gegeben. Nur weil es dir nicht gefällt, ist es kein Grund, es zu notieren.
David Arno
Kev beantwortet die Frage definitiv. Die Frage ist, dass es keine eingebaute Lösung gibt.
Eric Schoonover
40

Ich bin auf diese Antwort gestoßen, bevor ich schließlich eine einfachere Lösung gefunden habe.

Starten Sie einfach explorer.exeim Task-Manager neu.

Ich habe nicht getestet, aber möglicherweise müssen Sie auch Ihre Eingabeaufforderung erneut öffnen.

Gutschrift an Timo Huovinen hier: Knoten nicht erkannt, obwohl erfolgreich installiert (wenn dies Ihnen geholfen hat, geben Sie bitte die Gutschrift für den Kommentar dieses Mannes).

wharding28
quelle
Ich bin hier angekommen, weil ich versucht habe, Visual Studio ein externes Tool hinzuzufügen, damit ich eine Eingabeaufforderung im Stammverzeichnis meiner Lösung öffnen kann, wie in diesem Blog beschrieben: neverindoubtnet.blogspot.com/2012/10/… ... und Ich hatte ähnliche Probleme ... Ich habe versucht, "git" in meiner Pfadvariablen anzuzeigen. Ich habe die git-Verzeichnisse zur PATH-Variablen hinzugefügt, aber dann werden sie nicht in der Eingabeaufforderung angezeigt, die ich in Visual Studio öffnen würde. Die einfache Lösung bestand darin, Visual Studio neu zu starten. Dann waren die neuen Ergänzungen zur PATH-Variablen in cmd sichtbar.
David Barrows
4
Diese Lösung hilft mir in Windows 10
ganchito55
7
Die Frage war: "Gibt es einen Befehl, den ich ausführen könnte, ohne CMD neu zu starten ?"
Florian F
Ok vom Task-Manager konnte ich explorer.exe nicht neu starten, sondern nur beenden. Ich habe es getan, aber meine Taskleiste ist defekt. Um Explorer zu starten, ist es wirklich einfach. Lassen Sie uns "Strg + Umschalt + Escape" -> Datei -> "Neue Aufgabe ausführen" -> "explorer.exe" die Arbeit für mich erledigen. Und ja, schließlich wurde env var im neuen cmd-Fenster verwendet. Vielen Dank für alles
Oscar
Gute Lösung, danke! So erweitern und adressieren Sie den Kommentar von @Oscar: Starten Sie ein cmdFenster als Administrator. Verwenden Sie den Befehl taskkill /f /im explorer.exe && explorer.exe. Dadurch wird der Prozess explorer.exe beendet und neu gestartet.
S3DEV
32

Dies funktioniert unter Windows 7: SET PATH=%PATH%;C:\CmdShortcuts

getestet durch Eingabe von echo% PATH% und es hat funktioniert, gut. Auch eingestellt, wenn Sie ein neues cmd öffnen, sind diese lästigen Neustarts nicht mehr erforderlich :)

kristofer månsson
quelle
1
Funktioniert nicht für "new cmd" für mich (Win7 x64). Siehe Bildschirmvideo
Igor
26
Dies löst die gestellte Frage nicht und sollte es auch nicht. Die ursprüngliche Frage ist, wie eine Umgebungsvariable auf einen Wert aktualisiert werden kann, der außerhalb dieses Terminals festgelegt wurde.
Csauve
Obwohl dies die Frage nicht beantwortet, bietet es die Hälfte der am besten funktionierenden Lösung. Ich benutze dies - für jede Variable, die ich einstelle - dann öffne ich das Bedienfeld und füge die Umgebungsvariable global hinzu. Ich mag es nicht, setxweil es die aktuelle Umgebung erbt, die möglicherweise geänderte Variablen enthält und nicht das, was ich dauerhaft möchte. Auf diese Weise kann ich vermeiden, die Konsole neu zu starten, um die Variablen zu verwenden, und gleichzeitig das Problem vermeiden, dass sie in Zukunft nicht mehr global verfügbar sind.
dgo
25

Verwenden Sie "setx" und starten Sie die Eingabeaufforderung cmd neu

Für diesen Job gibt es ein Befehlszeilenprogramm mit dem Namen " setx ". Es ist zum Lesen und Schreiben env-Variablen. Die Variablen bleiben bestehen, nachdem das Befehlsfenster geschlossen wurde.

"Erstellt oder ändert Umgebungsvariablen in der Benutzer- oder Systemumgebung, ohne dass Programmierung oder Skripterstellung erforderlich sind. Der Befehl setx ruft auch die Werte von Registrierungsschlüsseln ab und schreibt sie in Textdateien."

Hinweis: Mit diesem Tool erstellte oder geänderte Variablen sind in zukünftigen Befehlsfenstern verfügbar, jedoch nicht im aktuellen CMD.exe-Befehlsfenster. Sie müssen also neu starten.

Wenn setxfehlt:


Oder ändern Sie die Registrierung

MSDN sagt:

Um Systemumgebungsvariablen programmgesteuert hinzuzufügen oder zu ändern, fügen Sie sie dem Registrierungsschlüssel HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment hinzu und senden Sie dann eine WM_SETTINGCHANGE- Nachricht, wobei lParam auf die Zeichenfolge " Environment " gesetzt ist.

Auf diese Weise können Anwendungen wie die Shell Ihre Updates abrufen.

Jens A. Koch
quelle
1
Könnten Sie die Verwendung von setx zum Lesen einer Umgebungsvariablen erweitern? Ich habe die verschiedenen Dokumentationen durchgesehen und sehe sie einfach nicht. : - /
Mark Ribau
2
setx VARIABLE -k "HKEY_LOCAL_MACHINE \ Software \ Microsoft \ WindowsNT \ CurrentVersion \ CurrentVersion" echo% VARIABLE%
Jens A. Koch
3
aktuelle Systemumgebung: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLEaktuelle Benutzerumgebung: HKEY_CURRENT_USER\Environment\VARIABLE
Mark Ribau
5
setx /? In einem Hinweis heißt es: "Auf einem lokalen System sind von diesem Tool erstellte oder geänderte Variablen in zukünftigen Befehlsfenstern verfügbar, jedoch nicht im aktuellen CMD.exe-Befehlsfenster." OP wollte das aktuelle cmd aktualisieren.
Superole
4
Käufer aufgepasst! Wenn Sie eine lange haben besonders %PATH%dann setxkann dies zu 1024 Bytes gestutzt! Und einfach so verschwand sein Abend
FaCE
15

Das Aufrufen dieser Funktion hat bei mir funktioniert:

VOID Win32ForceSettingsChange()
{
    DWORD dwReturnValue;
    ::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
Brian Weed
quelle
8
und nicht alle Programme hören diese Nachricht (in der Tat wahrscheinlich die meisten von ihnen nicht)
Rehan Khwaja
Nein, es funktioniert auch für Nicht-GUI-Programme. Was das Abhören von Programmen betrifft ... das Problem, wenn sichergestellt werden soll, dass ein neu gestartetes Programm die aktualisierte Umgebung erhält, und dies gibt Ihnen dies.
user2023370
11

Die beste Methode, die ich mir ausgedacht habe, war, einfach eine Registrierungsabfrage durchzuführen. Hier ist mein Beispiel.

In meinem Beispiel habe ich eine Installation mit einer Batch-Datei durchgeführt, die neue Umgebungsvariablen hinzugefügt hat. Ich musste Dinge damit tun, sobald die Installation abgeschlossen war, konnte aber keinen neuen Prozess mit diesen neuen Variablen erzeugen. Ich habe das Laichen eines anderen Explorer-Fensters getestet und auf cmd.exe zurückgerufen. Dies hat funktioniert, aber unter Vista und Windows 7 wird der Explorer nur als einzelne Instanz und normalerweise als angemeldete Person ausgeführt. Dies würde bei der Automatisierung fehlschlagen, da ich meine Administrator-Creds dazu benötige Führen Sie Dinge aus, unabhängig davon, ob Sie vom lokalen System oder als Administrator auf der Box ausgeführt werden. Die Einschränkung besteht darin, dass Dinge wie der Pfad nicht behandelt werden, sondern nur einfache Umgebungsvariablen. Dies ermöglichte es mir, einen Stapel zu verwenden, um in ein Verzeichnis (mit Leerzeichen) zu gelangen und in Dateien zu kopieren, in denen .exes usw. ausgeführt werden. Dies wurde heute aus den Ressourcen von may auf stackoverflow.com geschrieben

Orginal Batch ruft neue Batch auf:

testenvget.cmd SDROOT (oder was auch immer die Variable ist)

@ECHO OFF
setlocal ENABLEEXTENSIONS
set keyname=HKLM\System\CurrentControlSet\Control\Session Manager\Environment
set value=%1
SET ERRKEY=0

REG QUERY "%KEYNAME%" /v "%VALUE%" 2>NUL| FIND /I "%VALUE%"
IF %ERRORLEVEL% EQU 0 (
ECHO The Registry Key Exists 
) ELSE (
SET ERRKEY=1
Echo The Registry Key Does not Exist
)

Echo %ERRKEY%
IF %ERRKEY% EQU 1 GOTO :ERROR

FOR /F "tokens=1-7" %%A IN ('REG QUERY "%KEYNAME%" /v "%VALUE%" 2^>NUL^| FIND /I "%VALUE%"') DO (
ECHO %%A
ECHO %%B
ECHO %%C
ECHO %%D
ECHO %%E
ECHO %%F
ECHO %%G
SET ValueName=%%A
SET ValueType=%%B
SET C1=%%C
SET C2=%%D
SET C3=%%E
SET C4=%%F
SET C5=%%G
)

SET VALUE1=%C1% %C2% %C3% %C4% %C5%
echo The Value of %VALUE% is %C1% %C2% %C3% %C4% %C5%
cd /d "%VALUE1%"
pause
REM **RUN Extra Commands here**
GOTO :EOF

:ERROR
Echo The the Enviroment Variable does not exist.
pause
GOTO :EOF

Es gibt auch eine andere Methode, die ich mir aus verschiedenen Ideen ausgedacht habe. Siehe unten. Dies wird im Grunde die neueste Pfadvariable aus der Registrierung erhalten, dies wird jedoch eine Reihe von Problemen verursachen, da die Registrierungsabfrage Variablen an sich geben wird, was bedeutet, dass überall dort, wo es eine Variable gibt, dies nicht funktioniert, um dieses Problem zu bekämpfen Verdoppeln Sie im Grunde den Weg. Sehr böse. Die am meisten bevorzugte Methode wäre: Set Path =% Path%; C: \ Programme \ Software .... \

Unabhängig davon, ob es sich um die neue Batch-Datei handelt, seien Sie bitte vorsichtig.

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
set org=%PATH%
for /f "tokens=2*" %%A in ('REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path ^|FIND /I "Path"') DO (
SET path=%%B
)
SET PATH=%org%;%PATH%
set path
Christopher Holmes
quelle
8

Der einfachste Weg, dem Pfad eine Variable hinzuzufügen, ohne die aktuelle Sitzung neu zu starten, besteht darin, die Eingabeaufforderung zu öffnen und Folgendes einzugeben:

PATH=(VARIABLE);%path%

und drücke enter .

Geben Sie ein, um zu überprüfen, ob Ihre Variable geladen ist

PATH

und drücken enter. Die Variable ist jedoch nur ein Teil des Pfads, bis Sie neu starten.

Richard Woodruff
quelle
hat bei mir nicht funktioniert, konnte nicht auf Binärdateien in der
Pfadvariablen
7

Dies ist möglich, indem die Umgebungstabelle innerhalb eines bestimmten Prozesses selbst überschrieben wird.

Als Proof of Concept habe ich diese Beispiel-App geschrieben, die gerade eine einzelne (bekannte) Umgebungsvariable in einem cmd.exe-Prozess bearbeitet hat:

typedef DWORD (__stdcall *NtQueryInformationProcessPtr)(HANDLE, DWORD, PVOID, ULONG, PULONG);

int __cdecl main(int argc, char* argv[])
{
    HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
    NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");

    int processId = atoi(argv[1]);
    printf("Target PID: %u\n", processId);

    // open the process with read+write access
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, processId);
    if(hProcess == NULL)
    {
        printf("Error opening process (%u)\n", GetLastError());
        return 0;
    }

    // find the location of the PEB
    PROCESS_BASIC_INFORMATION pbi = {0};
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
    if(status != 0)
    {
        printf("Error ProcessBasicInformation (0x%8X)\n", status);
    }
    printf("PEB: %p\n", pbi.PebBaseAddress);

    // find the process parameters
    char *processParamsOffset = (char*)pbi.PebBaseAddress + 0x20; // hard coded offset for x64 apps
    char *processParameters = NULL;
    if(ReadProcessMemory(hProcess, processParamsOffset, &processParameters, sizeof(processParameters), NULL))
    {
        printf("UserProcessParameters: %p\n", processParameters);
    }
    else
    {
        printf("Error ReadProcessMemory (%u)\n", GetLastError());
    }

    // find the address to the environment table
    char *environmentOffset = processParameters + 0x80; // hard coded offset for x64 apps
    char *environment = NULL;
    ReadProcessMemory(hProcess, environmentOffset, &environment, sizeof(environment), NULL);
    printf("environment: %p\n", environment);

    // copy the environment table into our own memory for scanning
    wchar_t *localEnvBlock = new wchar_t[64*1024];
    ReadProcessMemory(hProcess, environment, localEnvBlock, sizeof(wchar_t)*64*1024, NULL);

    // find the variable to edit
    wchar_t *found = NULL;
    wchar_t *varOffset = localEnvBlock;
    while(varOffset < localEnvBlock + 64*1024)
    {
        if(varOffset[0] == '\0')
        {
            // we reached the end
            break;
        }
        if(wcsncmp(varOffset, L"ENVTEST=", 8) == 0)
        {
            found = varOffset;
            break;
        }
        varOffset += wcslen(varOffset)+1;
    }

    // check to see if we found one
    if(found)
    {
        size_t offset = (found - localEnvBlock) * sizeof(wchar_t);
        printf("Offset: %Iu\n", offset);

        // write a new version (if the size of the value changes then we have to rewrite the entire block)
        if(!WriteProcessMemory(hProcess, environment + offset, L"ENVTEST=def", 12*sizeof(wchar_t), NULL))
        {
            printf("Error WriteProcessMemory (%u)\n", GetLastError());
        }
    }

    // cleanup
    delete[] localEnvBlock;
    CloseHandle(hProcess);

    return 0;
}

Beispielausgabe:

>set ENVTEST=abc

>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528

>set ENVTEST
ENVTEST=def

Anmerkungen

Dieser Ansatz wäre auch auf Sicherheitsbeschränkungen beschränkt. Wenn das Ziel auf einer höheren Höhe oder einem höheren Konto (z. B. SYSTEM) ausgeführt wird, haben wir keine Berechtigung, seinen Speicher zu bearbeiten.

Wenn Sie dies mit einer 32-Bit-App tun möchten, ändern sich die oben angegebenen fest codierten Offsets auf 0x10 bzw. 0x48. Diese Offsets können gefunden werden, indem die Strukturen _PEB und _RTL_USER_PROCESS_PARAMETERS in einem Debugger ausgegeben werden (z. B. in WinDbg dt _PEBunddt _RTL_USER_PROCESS_PARAMETERS ).

Um den Proof-of-Concept in das zu ändern, was das OP benötigt, werden lediglich die aktuellen System- und Benutzerumgebungsvariablen (wie in der Antwort von @ tsadok dokumentiert) aufgelistet und die gesamte Umgebungstabelle in den Speicher des Zielprozesses geschrieben.

Bearbeiten: Die Größe des Umgebungsblocks wird auch in der Struktur _RTL_USER_PROCESS_PARAMETERS gespeichert, der Speicher wird jedoch auf dem Prozessheap zugewiesen. Von einem externen Prozess aus hätten wir also nicht die Möglichkeit, die Größe zu ändern und ihn zu vergrößern. Ich habe mit VirtualAllocEx herumgespielt, um zusätzlichen Speicher im Zielprozess für den Umgebungsspeicher zuzuweisen, und konnte eine völlig neue Tabelle festlegen und lesen. Leider stürzt jeder Versuch, die Umgebung auf normale Weise zu ändern, ab und brennt, da die Adresse nicht mehr auf den Heap verweist (sie stürzt in RtlSizeHeap ab).

Josh Poley
quelle
6

Umgebungsvariablen werden in HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Session Manager \ Environment gespeichert.

Viele der nützlichen Umgebungsvariablen, wie z. B. Path, werden als REG_SZ gespeichert. Es gibt verschiedene Möglichkeiten, auf die Registrierung zuzugreifen, einschließlich REGEDIT:

REGEDIT /E &lt;filename&gt; "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"

Die Ausgabe beginnt mit magischen Zahlen. Um es mit dem Befehl find zu durchsuchen, muss es eingegeben und umgeleitet werden:type <filename> | findstr -c:\"Path\"

Wenn Sie also nur die Pfadvariable in Ihrer aktuellen Befehlssitzung mit den Systemeigenschaften aktualisieren möchten, funktioniert das folgende Batch-Skript einwandfrei:

RefreshPath.cmd:

    @echo aus

    REM Diese Lösung fordert eine Erhöhung an, um aus der Registrierung lesen zu können.

    falls vorhanden% temp% \ env.reg del% temp% \ env.reg / q / f

    REGEDIT / E% temp% \ env.reg "HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Session Manager \ Environment"

    falls nicht vorhanden% temp% \ env.reg (
       echo "Registrierung kann nicht an temporären Speicherort geschrieben werden"
       Ausfahrt 1
       )

    SETLOCAL EnableDelayedExpansion

    für / f "tokens = 1,2 * delims ==" %% i in ('type% temp% \ env.reg ^ | findstr -c: \ "Path \" =') do (
       set upath = %% ~ j
       echo! upath: \\ = \! >% temp% \ newpath
       )

     ENDLOCAL

     für / f "tokens = *" %% i in (% temp% \ newpath) setze path = %% i
Algonaut
quelle
5
Umgebungsvariablen werden nicht in der Registrierung gespeichert. In der Registrierung wird eine Vorlage gespeichert , aus der Programme wie Windows Explorer ihre Umgebungsvariablen (neu) erstellen, wenn sie dazu aufgefordert werden . Die tatsächlichen Umgebungsvariablen sind pro Prozess und werden im eigenen Adressraum jedes Prozesses gespeichert, zunächst von seinem übergeordneten Prozess geerbt und danach nach Lust und Laune des Prozesses geändert.
JdeBP
5

Versuchen Sie, als Administrator eine neue Eingabeaufforderung zu öffnen. Dies funktionierte für mich unter Windows 10. (Ich weiß, dass dies eine alte Antwort ist, aber ich musste dies teilen, weil es absurd ist, nur dafür ein VBS-Skript schreiben zu müssen).

Estebro
quelle
5

Der Neustart des Explorers hat dies für mich getan, aber nur für neue cmd-Terminals.

Das Terminal, für das ich den Pfad festgelegt habe, konnte die neue Pfadvariable bereits sehen (in Windows 7).

taskkill /f /im explorer.exe && explorer.exe
Vince
quelle
5

Das Verwirrende könnte sein, dass es einige Stellen gibt, an denen das cmd gestartet werden kann. In meinem Fall habe ich cmd über den Windows Explorer ausgeführt und die Umgebungsvariablen haben sich nicht geändert, während beim Starten von cmd über "run" (Windows-Taste + r) die Umgebungsvariablen geändert wurden .

In meinem Fall musste ich nur den Windows Explorer-Prozess über den Task-Manager beenden und ihn dann über den Task-Manager erneut starten .

Sobald ich dies getan hatte, hatte ich Zugriff auf die neue Umgebungsvariable von einem cmd, der aus dem Windows Explorer erzeugt wurde.

Daniel Fensterheim
quelle
3

Ich verwende den folgenden Code in meinen Batch-Skripten:

if not defined MY_ENV_VAR (
    setx MY_ENV_VAR "VALUE" > nul
    set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%

Durch die Verwendung von SET nach SETX ist es möglich, die "lokale" Variable direkt zu verwenden, ohne das Befehlsfenster neu zu starten. Und beim nächsten Lauf wird die Umgebungsvariable verwendet.

Sebastian
quelle
Während ich verstehe, was Sie getan haben, möchte er höchstwahrscheinlich etwas für parallele Skripte. Ein Skript setzt Globals, während ein anderes sie liest. Andernfalls macht es keinen Sinn, setx einzubeziehen, set wäre ausreichend.
JasonXA
3

Ich mochte den Ansatz, dem schokoladig folgte, wie in der Antwort eines anonymen Feiglings angegeben, da es sich um einen reinen Batch-Ansatz handelt. Es bleiben jedoch eine temporäre Datei und einige temporäre Variablen übrig. Ich habe eine sauberere Version für mich gemacht.

Machen Sie refreshEnv.batirgendwo auf Ihrem eine Datei PATH. Aktualisieren Sie Ihre Konsolenumgebung durch Ausführen refreshEnv.

@ECHO OFF
REM Source found on https://github.com/DieterDePaepe/windows-scripts
REM Please share any improvements made!

REM Code inspired by http://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w

IF [%1]==[/?] GOTO :help
IF [%1]==[/help] GOTO :help
IF [%1]==[--help] GOTO :help
IF [%1]==[] GOTO :main

ECHO Unknown command: %1
EXIT /b 1 

:help
ECHO Refresh the environment variables in the console.
ECHO.
ECHO   refreshEnv       Refresh all environment variables.
ECHO   refreshEnv /?        Display this help.
GOTO :EOF

:main
REM Because the environment variables may refer to other variables, we need a 2-step approach.
REM One option is to use delayed variable evaluation, but this forces use of SETLOCAL and
REM may pose problems for files with an '!' in the name.
REM The option used here is to create a temporary batch file that will define all the variables.

REM Check to make sure we don't overwrite an actual file.
IF EXIST %TEMP%\__refreshEnvironment.bat (
  ECHO Environment refresh failed!
  ECHO.
  ECHO This script uses a temporary file "%TEMP%\__refreshEnvironment.bat", which already exists. The script was aborted in order to prevent accidental data loss. Delete this file to enable this script.
  EXIT /b 1
)

REM Read the system environment variables from the registry.
FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"`) DO (
  REM /I -> ignore casing, since PATH may also be called Path
  IF /I NOT [%%I]==[PATH] (
    ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat
  )
)

REM Read the user environment variables from the registry.
FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment`) DO (
  REM /I -> ignore casing, since PATH may also be called Path
  IF /I NOT [%%I]==[PATH] (
    ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat
  )
)

REM PATH is a special variable: it is automatically merged based on the values in the
REM system and user variables.
REM Read the PATH variable from the system and user environment variables.
FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PATH`) DO (
  ECHO SET PATH=%%K>>%TEMP%\__refreshEnvironment.bat
)
FOR /F "usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment /v PATH`) DO (
  ECHO SET PATH=%%PATH%%;%%K>>%TEMP%\__refreshEnvironment.bat
)

REM Load the variable definitions from our temporary file.
CALL %TEMP%\__refreshEnvironment.bat

REM Clean up after ourselves.
DEL /Q %TEMP%\__refreshEnvironment.bat

ECHO Environment successfully refreshed.
DieterDP
quelle
gilt dies auch für% CLIENTNAME%? - hat bei mir nicht funktioniert - stackoverflow.com/questions/37550160/…
Igor L.
% CLIENTNAME% ist in meiner Umgebung nicht verfügbar. Wenn Sie Ihre Frage lesen, gehe ich davon aus, dass dies durch einen externen Prozess festgelegt wurde. (Wenn ein Prozess einen untergeordneten Prozess startet, kann er die Umgebung für dieses untergeordnete Element anpassen.) Da es nicht Teil der tatsächlichen Umgebungsvariablen ist, wird es von diesem Skript nicht aktualisiert.
DieterDP
Hallo @DieterDP, deine Lösung funktioniert bei mir! Ich verwende Windows 10 auf einem 64-Bit-Computer. Ich erhalte die Fehlermeldung: "FEHLER: Das System konnte den angegebenen Registrierungsschlüssel oder -wert nicht finden." Trotzdem ist die Aktualisierung der Umgebungsvariablen erfolgreich. Woher kommt der Fehler?
K. Mulier
Schwer zu sagen, ohne es selbst zu testen, aber ich vermute, dass sich die Registrierungsstruktur auf W10 geringfügig unterscheidet. Wenn Sie Lust dazu haben, versuchen Sie, den Fehler zu beheben, indem Sie die Befehle in der Befehlszeile ausführen.
DieterDP
2

Wenn es sich nur um eine (oder einige) bestimmte Variablen handelt, die Sie ändern möchten, ist meiner Meinung nach der einfachste Weg eine Problemumgehung : Legen Sie sie einfach in Ihrer Umgebung UND in Ihrer aktuellen Konsolensitzung fest

  • Mit Set wird die Variable in Ihre aktuelle Sitzung eingefügt
  • SetX fügt die Variable in die Umgebung ein, jedoch NICHT in Ihre aktuelle Sitzung

Ich habe dieses einfache Batch-Skript, um meinen Maven von Java7 auf Java8 zu ändern (beide sind env. Vars). Der Batch-Ordner befindet sich in meiner PATH - Variable , sodass ich immer ' j8 ' und in meiner Konsole und in der Umgebung meine JAVA_HOME-Variable aufrufen kann wird geändert:

j8.bat:

@echo off
set JAVA_HOME=%JAVA_HOME_8%
setx JAVA_HOME "%JAVA_HOME_8%"

Bis jetzt funktioniert das am besten und einfachsten. Sie möchten wahrscheinlich, dass dies in einem Befehl enthalten ist, aber in Windows ist es einfach nicht vorhanden ...

Jeroen van Dijk-Jun
quelle
2

Die Lösung, die ich seit einigen Jahren verwende:

@echo off
rem Refresh PATH from registry.
setlocal
set USR_PATH=
set SYS_PATH=
for /F "tokens=3* skip=2" %%P in ('%SystemRoot%\system32\reg.exe query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PATH') do @set "SYS_PATH=%%P %%Q"
for /F "tokens=3* skip=2" %%P in ('%SystemRoot%\system32\reg.exe query "HKCU\Environment" /v PATH') do @set "USR_PATH=%%P %%Q"
if "%SYS_PATH:~-1%"==" " set "SYS_PATH=%SYS_PATH:~0,-1%"
if "%USR_PATH:~-1%"==" " set "USR_PATH=%USR_PATH:~0,-1%"
endlocal & call set "PATH=%SYS_PATH%;%USR_PATH%"
goto :EOF

Edit: Woops, hier ist die aktualisierte Version.

Charles Grunwald
quelle
Ich mag deine Antwort. Stellen Sie die gleiche Antwort auf meine Frage hier stackoverflow.com/q/61473551/1082063 und ich werde es als akzeptiert die Antwort. Vielen Dank.
David I. McIntosh
1

Es gibt keinen geraden Weg, wie Kev sagte. In den meisten Fällen ist es einfacher, eine andere CMD-Box zu erzeugen. Noch ärgerlicher ist, dass laufende Programme auch keine Änderungen bemerken (obwohl IIRC möglicherweise eine Broadcast-Nachricht zu sehen hat, um über solche Änderungen informiert zu werden).

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

PhiLho
quelle
1

Ich benutze dieses Powershell-Skript, um es der PATH- Variablen hinzuzufügen . 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%"
Iulian Dita
quelle
1

Vielen Dank, dass Sie diese Frage gestellt haben, die auch im Jahr 2019 sehr interessant ist (in der Tat ist es nicht einfach, das Shell-Cmd zu erneuern, da es sich um eine einzelne Instanz handelt, wie oben erwähnt), da durch das Erneuern von Umgebungsvariablen in Windows viele Automatisierungsaufgaben ohne ausgeführt werden können Die Befehlszeile muss manuell neu gestartet werden.

Wir verwenden dies beispielsweise, um die Bereitstellung und Konfiguration von Software auf einer großen Anzahl von Computern zu ermöglichen, die wir regelmäßig neu installieren. Und ich muss zugeben, dass ein Neustart der Befehlszeile während der Bereitstellung unserer Software sehr unpraktisch wäre und es erforderlich machen würde, Problemumgehungen zu finden, die nicht unbedingt angenehm sind. Kommen wir 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 die neuen verfügbaren Umgebungsvariablen aufrufen. In einem typischen Fall können wir beispielsweise npm direkt aufrufen, um in derselben Sitzung bestimmte Pakete wie die folgenden zu installieren, wenn wir nodeJS zuvor mit cmd mithilfe von unbeaufsichtigten Befehlen installiert haben, nachdem die Funktion aufgerufen wurde.

[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. Beachten Sie nun, dass cmd nach Abschluss der Aufgabe immer noch keinen Zugriff auf die neuen Umgebungsvariablen hat, selbst wenn das Powershell-Skript diese in seiner eigenen Sitzung aktualisiert hat. Deshalb erledigen wir alle erforderlichen Aufgaben im Powershell-Skript, das natürlich dieselben Befehle wie cmd aufrufen kann.

Andy McRae
quelle
0

Bearbeiten: Dies funktioniert nur, wenn die von Ihnen vorgenommenen Umgebungsänderungen auf das Ausführen einer Batchdatei zurückzuführen sind.

Wenn eine Batch-Datei mit beginnt SETLOCAL, wird sie beim Beenden immer wieder in Ihre ursprüngliche Umgebung zurückgeführt, selbst wenn Sie vergessen haben, ENDLOCALvor dem Beenden des Batches aufzurufen , oder wenn sie unerwartet abgebrochen wird.

Fast jede Batch-Datei, mit der ich schreibe, beginnt, SETLOCALda ich in den meisten Fällen nicht möchte, dass die Nebenwirkungen von Umgebungsänderungen bestehen bleiben. In Fällen, in denen bestimmte Änderungen an Umgebungsvariablen außerhalb der Batchdatei weitergegeben werden sollen, ENDLOCALsieht meine letzte wie folgt aus:

ENDLOCAL & (
  SET RESULT1=%RESULT1%
  SET RESULT2=%RESULT2%
)
Wardies
quelle
-1

Um dies zu lösen, habe ich die Umgebungsvariable mit BOTH setx und set geändert und dann alle Instanzen von explorer.exe neu gestartet. Auf diese Weise erhält jeder nachfolgend gestartete Prozess die neue Umgebungsvariable.

Mein Batch-Skript dazu:

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. Lesen Sie jedoch den Beitrag von Kev, um zu erfahren, warum dies erforderlich ist

Jens Hykkelbjerg
quelle