Wie kann ich die PATH-Variable dauerhaft über die Windows-Befehlszeile aktualisieren?

122

Wenn ich set PATH=%PATH%;C:\\Something\\binüber die Befehlszeile ( cmd.exe) ausführe und dann ausführe, wird echo %PATH%diese Zeichenfolge dem PATH hinzugefügt. Wenn ich die Befehlszeile schließe und öffne, befindet sich diese neue Zeichenfolge nicht in PATH.

Wie kann ich PATH über die Befehlszeile für alle zukünftigen Prozesse dauerhaft aktualisieren, nicht nur für den aktuellen Prozess?

Ich möchte dies nicht tun, indem ich zu Systemeigenschaften → Erweitert → Umgebungsvariablen gehe und dort PATH aktualisiere.

Dieser Befehl muss von einer Java-Anwendung ausgeführt werden (siehe meine andere Frage ).

vale4674
quelle
5
Mit Powershell ist es ziemlich einfach, stackoverflow.com/questions/714877/… . Mit cmd bin ich mir nicht sicher. Möglicherweise müssen Sie die Registrierung ändern oder eine .net-Assembly aufrufen.
Austen Holmes
1
Wie gesagt, ich muss dies aus der Java-Anwendung heraus tun. Ich dachte nur, um einen cmd Befehl useng java's auszuführenRuntime.getRuntime().exec("my command");
vale4674

Antworten:

43

Die Dokumentation dazu finden Sie auf MSDN . Der Schlüsselextrakt lautet:

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_SETTINGCHANGENachricht mit lParam, das auf die Zeichenfolge "Environment" gesetzt ist. Auf diese Weise können Anwendungen wie die Shell Ihre Updates abrufen.

Beachten Sie, dass Ihre Anwendung erhöhte Administratorrechte benötigt, um diesen Schlüssel ändern zu können.

In den Kommentaren geben Sie an, dass Sie gerne nur die Umgebung pro Benutzer ändern würden. Bearbeiten Sie dazu die Werte in HKEY_CURRENT_USER \ Environment . Stellen Sie nach wie vor sicher, dass Sie eine WM_SETTINGCHANGENachricht senden .

Sie sollten dies mit Ihrer Java-Anwendung mithilfe der JNI-Registrierungsklassen problemlos tun können.

David Heffernan
quelle
1
Ja, mit den JNI-Registrierungsklassen. Ein größeres Problem ist, dass Ihre App wahrscheinlich nicht erhöht ausgeführt wird. Weißt du, wie man das macht? Wenn Sie nur möchten, dass ein kleiner Teil Ihrer App erhöht ausgeführt wird (dh nur um diese Änderung vorzunehmen), ist die einfachste Lösung eine sehr einfache C ++ - App, die den Job ausführt, mit dem App-Manifest markiert und dann als separater Prozess ausgeführt wird provoziert den UAC-Dialog.
David Heffernan
1
Sie können auch bearbeiten HKEY_CURRENT_USER\Environment, um Höhenanforderungen zu vermeiden.
Kichik
@ David Heffernan Ja, nur dieses Ding muss erhöht laufen. Ihr Vorschlag ist also, eine C ++ - Anwendung zu schreiben und sie von meiner Java-Anwendung aus auszuführen? Können Sie mir einen Beispielcode oder einen Link dazu geben?
vale4674
Ja. Genau wie David gesagt hat. Nur du nicht Höhe. Ich sollte auch erwähnen, dass dies die Umgebung nur für den aktuellen Benutzer ändert.
Kichik
Sie müssen dies in einen separaten Prozess aufteilen, damit Sie nur beim Ändern des Systempfads einen UAC-Dialog erzwingen. Es benötigt lediglich eine einfache C ++ - App mit einigen Lese- und Schreibvorgängen in der Registrierung, gefolgt von einer SendMessage. Stellen Sie die requestedExecutionLevelauf requireAdministratordem App - Manifest.
David Heffernan
145

Sie können verwenden:

setx PATH "%PATH%;C:\\Something\\bin"

Die setxgespeicherte Zeichenfolge wird jedoch auf 1024 Byte abgeschnitten, wodurch möglicherweise der PATH beschädigt wird.

/Mwird das PATHin HKEY_LOCAL_MACHINEanstelle von ändern HKEY_CURRENT_USER. Mit anderen Worten, eine Systemvariable anstelle der des Benutzers. Beispielsweise:

SETX /M PATH "%PATH%;C:\your path with spaces"

Sie müssen bedenken, dass der neue PFAD in Ihrem aktuellen nicht sichtbar ist cmd.exe.

Aber wenn Sie in der Registrierung oder auf einem neuen cmd.exemit suchen "set p", können Sie den neuen Wert sehen.

Panny
quelle
2
Gibt es eine Möglichkeit, setxden Pfad des Computers anstelle des Benutzerpfads zu ändern?
Corey Ogburn
4
Von hier können Sie es in Benutzern eine Variable nicht nur für die aktuell angemeldeten gesetzt sein könnte sagen möglich , aber für die Maschine durch den Einsatz /mam Ende des Befehls, auf Windows XP und 7 ich es allerdings nicht versucht habe.
Panny
1
Ich habe den Fehler beim Ausführen des setxBefehls "Standardoption ist nicht länger als '2' zulässig" erhalten. Wie kann ich ihn umgehen?
Nam G VU
12
@ KilgoreCod-Kommentare: Ich warne davor, den Befehl zu verwenden: Bei vielen (den meisten?) Installationen wird die PATH-Variable heutzutage lang sein - setx schneidet die gespeicherte Zeichenfolge auf 1024 Byte ab und beschädigt möglicherweise den PATH (siehe Diskussion hier superuser.com/). q / 812754 ).
Beresfordt
2
Ich versuche, den Pfad wiederzugeben, der bereits über 1200 Byte beträgt. irgendein anderer Weg anstelle von Setx?
Lawphotog
37

Ich warne davor, den Befehl zu verwenden

setx PATH "%PATH%;C:\Something\bin"

Ändern der PATH-Variablen aufgrund eines "Features" ihrer Implementierung. Bei vielen (den meisten?) Installationen ist die Variable heutzutage langwierig - setxschneidet die gespeicherte Zeichenfolge auf 1024 Byte ab und beschädigt möglicherweise den PATH (siehe Diskussion hier ).

( Ich habe mich speziell angemeldet, um dieses Problem zu kennzeichnen, und daher fehlt mir der Ruf der Website, die am 2. Mai 12 veröffentlichte Antwort direkt zu kommentieren. Ich danke beresfordt für das Hinzufügen eines solchen Kommentars. )

KilgoreCod
quelle
9

Dieses Python-Skript [*] macht genau das:

"""
Show/Modify/Append registry env-vars (ie `PATH`) and notify Windows-applications to pickup changes.

First attempts to show/modify HKEY_LOCAL_MACHINE (all users), and 
if not accessible due to admin-rights missing, fails-back 
to HKEY_CURRENT_USER.
Write and Delete operations do not proceed to user-tree if all-users succeed.

Syntax: 
    {prog}                  : Print all env-vars. 
    {prog}  VARNAME         : Print value for VARNAME. 
    {prog}  VARNAME   VALUE : Set VALUE for VARNAME. 
    {prog}  +VARNAME  VALUE : Append VALUE in VARNAME delimeted with ';' (i.e. used for `PATH`). 
    {prog}  -VARNAME        : Delete env-var value. 

Note that the current command-window will not be affected, 
changes would apply only for new command-windows.
"""

import winreg
import os, sys, win32gui, win32con

def reg_key(tree, path, varname):
    return '%s\%s:%s' % (tree, path, varname) 

def reg_entry(tree, path, varname, value):
    return '%s=%s' % (reg_key(tree, path, varname), value)

def query_value(key, varname):
    value, type_id = winreg.QueryValueEx(key, varname)
    return value

def yield_all_entries(tree, path, key):
    i = 0
    while True:
        try:
            n,v,t = winreg.EnumValue(key, i)
            yield reg_entry(tree, path, n, v)
            i += 1
        except OSError:
            break ## Expected, this is how iteration ends.

def notify_windows(action, tree, path, varname, value):
    win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
    print("---%s %s" % (action, reg_entry(tree, path, varname, value)), file=sys.stderr)

def manage_registry_env_vars(varname=None, value=None):
    reg_keys = [
        ('HKEY_LOCAL_MACHINE', r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'),
        ('HKEY_CURRENT_USER', r'Environment'),
    ]
    for (tree_name, path) in reg_keys:
        tree = eval('winreg.%s'%tree_name)
        try:
            with winreg.ConnectRegistry(None, tree) as reg:
                with winreg.OpenKey(reg, path, 0, winreg.KEY_ALL_ACCESS) as key:
                    if not varname:
                        for regent in yield_all_entries(tree_name, path, key):
                            print(regent)
                    else:
                        if not value:
                            if varname.startswith('-'):
                                varname = varname[1:]
                                value = query_value(key, varname)
                                winreg.DeleteValue(key, varname)
                                notify_windows("Deleted", tree_name, path, varname, value)
                                break  ## Don't propagate into user-tree.
                            else:
                                value = query_value(key, varname)
                                print(reg_entry(tree_name, path, varname, value))
                        else:
                            if varname.startswith('+'):
                                varname = varname[1:]
                                value = query_value(key, varname) + ';' + value
                            winreg.SetValueEx(key, varname, 0, winreg.REG_EXPAND_SZ, value)
                            notify_windows("Updated", tree_name, path, varname, value)
                            break  ## Don't propagate into user-tree.
        except PermissionError as ex:
            print("!!!Cannot access %s due to: %s" % 
                    (reg_key(tree_name, path, varname), ex), file=sys.stderr)
        except FileNotFoundError as ex:
            print("!!!Cannot find %s due to: %s" % 
                    (reg_key(tree_name, path, varname), ex), file=sys.stderr)

if __name__=='__main__':
    args = sys.argv
    argc = len(args)
    if argc > 3:
        print(__doc__.format(prog=args[0]), file=sys.stderr)
        sys.exit()

    manage_registry_env_vars(*args[1:])

Im Folgenden finden Sie einige Verwendungsbeispiele, vorausgesetzt, sie wurden in einer Datei gespeichert, die setenv.pyirgendwo in Ihrem aktuellen Pfad aufgerufen wird. Beachten Sie, dass ich in diesen Beispielen keine Administratorrechte hatte , sodass die Änderungen nur den Registrierungsbaum meines lokalen Benutzers betrafen:

> REM ## Print all env-vars
> setenv.py
!!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
HKEY_CURRENT_USER\Environment:PATH=...
...

> REM ## Query env-var:
> setenv.py PATH C:\foo
!!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
!!!Cannot find HKEY_CURRENT_USER\Environment:PATH due to: [WinError 2] The system cannot find the file specified

> REM ## Set env-var:
> setenv.py PATH C:\foo
!!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo

> REM ## Append env-var:
> setenv.py +PATH D:\Bar
!!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo;D:\Bar

> REM ## Delete env-var:
> setenv.py -PATH
!!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
---Deleted HKEY_CURRENT_USER\Environment:PATH

[*] Angepasst von: http://code.activestate.com/recipes/416087-persistent-environment-variables-on-windows/

Ankostis
quelle
4

Als Referenz zitiere ich für alle, die suchen, wie der Pfad über Code geändert werden kann, einen nützlichen Beitrag eines Delphi-Programmierers von dieser Webseite: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (Programmierer) 22 Okt 03 17:57 Ich habe gefunden, wo ich den Originalbeitrag gelesen habe. Er befindet sich hier: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

Der Auszug von dem, was Sie brauchen würden, ist folgender:

Sie müssen die Zeichenfolge "Umgebung" in LParam angeben. In Delphi würden Sie es so machen:

 SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, Integer(PChar('Environment')));

Es wurde von Jordan Russell, http://www.jrsoftware.org , dem Autor von (ao) InnoSetup, vorgeschlagen kommerzielle Installer in Bezug auf Funktionsumfang und Stabilität. ") (Ich möchte nur, dass mehr Leute InnoSetup verwenden.)

HTH

Steve F.
quelle
Sie müssen die Registrierung ändern. Außerdem ist die Umwandlung in Integer schlecht. Zur 64-Bit-Kompatibilität stattdessen in LPARAM umwandeln.
David Heffernan
4

In einem Unternehmensnetzwerk, in dem der Benutzer nur eingeschränkten Zugriff hat und tragbare Apps verwendet, gibt es folgende Befehlszeilentricks:

  1. Fragen Sie die Benutzer-Env-Variablen ab : reg query "HKEY_CURRENT_USER\Environment". Verwendung "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"für LOCAL_MACHINE.
  2. Neue Benutzer-Umgebungsvariable hinzufügen : reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Verwenden Sie diese REG_EXPAND_SZOption für Pfade, die andere %% -Variablen enthalten.
  3. Vorhandene env-Variable löschen : reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
Razvanon
quelle
3

Dieses Skript http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

Enthält alle erforderlichen Windows-API-Aufrufe, die für Ihre Anforderungen überarbeitet werden können. Es ist eigentlich eine AutoHotkey-GUI, um den Systempfad einfach zu ändern. Muss als Administrator ausgeführt werden.

Evgeni Sergeev
quelle
Lies die Frage. Nochmal.
Jiggunjer
Tolles Drehbuch. Ich verwende HotKey, weiß aber nicht, wie oder was ich tun muss, um das Skript hinzuzufügen. Können Sie Hilfe anbieten, einen Link anbieten oder erklären, was zu tun ist?
Jwzumwalt