Jak trwale zaktualizować zmienną PATH z wiersza poleceń systemu Windows?


122

Jeśli wykonuję set PATH=%PATH%;C:\\Something\\binz wiersza poleceń ( cmd.exe), a następnie wykonuję echo %PATH%, widzę ten ciąg dodany do PATH. Jeśli zamknę i otworzę wiersz poleceń, tego nowego ciągu nie ma w PATH.

Jak mogę trwale zaktualizować PATH z wiersza poleceń dla wszystkich procesów w przyszłości, a nie tylko dla bieżącego procesu?

Nie chcę tego robić, przechodząc do Właściwości systemu → Zaawansowane → Zmienne środowiskowe i aktualizując ścieżkę w tym miejscu.

To polecenie musi być wykonane z aplikacji Java (zobacz moje inne pytanie ).


5
Korzystając z PowerShell, jest to dość proste stackoverflow.com/questions/714877/… . Używając cmd, nie jestem pewien. Może być konieczne zmodyfikowanie rejestru lub pobranie zestawu .net.
— Austen Holmes

1
Jak powiedziałem, muszę to zrobić z poziomu aplikacji java. Pomyślałem tylko o wykonaniu polecenia cmd useng java'sRuntime.getRuntime().exec("my command");
— vale4674

Odpowiedzi:


43

Dokumentację, jak to zrobić, można znaleźć w witrynie MSDN . Kluczowy fragment jest następujący:

Aby programowo dodać lub zmodyfikować zmienne środowiskowe systemu, dodaj je do klucza rejestru HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment , a następnie rozgłaszaj WM_SETTINGCHANGEkomunikat z lParam ustawionym na ciąg „Environment”. Dzięki temu aplikacje, takie jak powłoka, mogą pobierać aktualizacje.

Pamiętaj, że Twoja aplikacja będzie potrzebować podwyższonych uprawnień administratora, aby móc modyfikować ten klucz.

W komentarzach wskazujesz, że z przyjemnością zmodyfikowałbyś tylko środowisko dla każdego użytkownika. Zrób to, edytując wartości w HKEY_CURRENT_USER \ Environment . Tak jak poprzednio, upewnij się, że nadajesz WM_SETTINGCHANGEwiadomość.

Powinieneś być w stanie zrobić to z łatwością z poziomu aplikacji Java, używając klas rejestru JNI.


1
Tak, używając klas rejestru JNI. Większy problem polega na tym, że Twoja aplikacja prawdopodobnie nie działa z podwyższonym poziomem uprawnień. Czy wiesz, jak to zrobić? Jeśli chcesz, aby tylko niewielka część Twojej aplikacji działała z podwyższonym poziomem uprawnień (tj. Tylko po to, aby dokonać tej zmiany), najprostszym rozwiązaniem jest bardzo prosta aplikacja C ++ do wykonania zadania, oznaczona manifestem aplikacji, a następnie wykonana jako oddzielny proces, który wywołuje okno dialogowe UAC.
— David Heffernan

1
Możesz także edytować, HKEY_CURRENT_USER\Environmentaby uniknąć wymogu podniesienia.
— kichik

@David Heffernan Tak, tylko to musi działać na podwyższonym poziomie. Więc twoja sugestia jest taka, aby napisać aplikację w C ++ i uruchomić ją z mojej aplikacji java? Czy możesz podać przykładowy kod lub link, jak to zrobić?
— vale4674

Tak. Tak jak powiedział David. Tylko ty nie masz elewacji. Powinienem również wspomnieć, że zmodyfikuje to środowisko tylko dla bieżącego użytkownika.
— kichik

Musisz podzielić to na osobny proces, aby wymusić okno dialogowe UAC tylko podczas modyfikowania ŚCIEŻKI systemowej. Wystarczy prosta aplikacja C ++ z kilkoma odczytami i zapisami rejestru, a następnie SendMessage. Ustaw requestedExecutionLevelsię requireAdministratorw pliku manifestu aplikacji.
— David Heffernan

145

Możesz użyć:

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

Jednak setxspowoduje obcięcie przechowywanego ciągu do 1024 bajtów, potencjalnie uszkadzając PATH.

/Mzmieni PATHw HKEY_LOCAL_MACHINEzamiast HKEY_CURRENT_USER. Innymi słowy, zmienna systemowa zamiast użytkownika. Na przykład:

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

Musisz pamiętać, że nowa PATH nie jest widoczna w Twoim obecnym cmd.exe.

Ale jeśli spojrzeć w rejestrze lub na nowy cmd.exez "set p"was może zobaczyć nową wartość.


2
Czy istnieje sposób setxzmiany ścieżki komputera zamiast ścieżki użytkownika?
— Corey Ogburn,

4
Od tutaj można powiedzieć, może to być możliwe, aby ustawić zmienną nie tylko dla aktualnie zalogowanego użytkownika, ale na maszynie za pomocą /mna końcu polecenia, na Windows XP i 7. Nie próbowałem go jednak.
— panny

1
setxWystąpił błąd podczas wykonywania polecenia „Domyślna opcja nie może być dłuższa niż„ 2 ”czas”. Jak to ominąć?
— Nam G VU

12
Komentarze @KilgoreCod: Przestrzegam przed użyciem polecenia: W wielu (większości?) Instalacjach obecnie zmienna PATH będzie długa - setx obetnie zapisany ciąg do 1024 bajtów, potencjalnie uszkadzając PATH (zobacz dyskusję tutaj superuser.com/ q / 812754 ).
— beresfordt

2
Próbuję odtworzyć ścieżkę, która ma już ponad 1200 bajtów. jakikolwiek inny sposób zamiast setx?
— lawphotog

37

Przestrzegam przed użyciem polecenia

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

zmodyfikować zmienną PATH ze względu na „cechę” jej implementacji. W wielu (większości?) Instalacjach w dzisiejszych czasach zmienna będzie długa - setxskróci przechowywany ciąg do 1024 bajtów, potencjalnie uszkadzając PATH (patrz dyskusja tutaj ).

( Zapisałem się specjalnie, aby oznaczyć ten problem, więc brakuje mi reputacji witryny, aby bezpośrednio komentować odpowiedź opublikowaną 2 maja 2012 r. Dziękuję beresfordt za dodanie takiego komentarza )


9

Ten skrypt Pythona [*] robi dokładnie to:

"""
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:])

Poniżej znajduje się kilka przykładów użycia, zakładając, że został on zapisany w pliku o nazwie setenv.pygdzieś w bieżącej ścieżce. Zauważ, że w tych przykładach nie miałem uprawnień administratora , więc zmiany dotyczyły tylko drzewa rejestru mojego lokalnego użytkownika:

> 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

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


4

Dla celów informacyjnych, dla każdego, kto szuka sposobu zmiany ścieżki za pomocą kodu, cytuję przydatny post napisany przez programistę Delphi z tej strony internetowej: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (programista) 22 października 03 17:57 Znalazłem miejsce, w którym przeczytałem oryginalny post, jest tutaj: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

Fragment tego, czego potrzebujesz, jest następujący:

W LParam należy określić ciąg „Środowisko”. W Delphi zrobiłbyś to w ten sposób:

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

Zasugerował go Jordan Russell, http://www.jrsoftware.org , autor (ao) InnoSetup („Inno Setup to darmowy instalator programów dla systemu Windows. Wprowadzony po raz pierwszy w 1997 roku, dzisiaj Inno Setup rywalizuje, a nawet przewyższa komercyjne instalatory w zestawie funkcji i stabilności. ”) (Chciałbym tylko, aby więcej osób korzystało z InnoSetup)

HTH


Musisz zmodyfikować rejestr. Również obsada na Integer jest kiepska. Zamiast tego przesyłaj do LPARAM w celu zapewnienia zgodności z 64-bitową.
— David Heffernan


4

W sieci firmowej, w której użytkownik ma ograniczony dostęp i korzysta z aplikacji przenośnych, istnieją następujące sztuczki wiersza poleceń:

  1. Kwerendy zmienne env użytkownik: reg query "HKEY_CURRENT_USER\Environment". Użyj "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"dla LOCAL_MACHINE.
  2. Dodaj nową zmienną env użytkownik: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Użyj REG_EXPAND_SZdla ścieżek zawierających inne zmienne %%.
  3. Usuń istniejącą zmienną env: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.

3

Ten skrypt http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

zawiera wszystkie niezbędne wywołania interfejsu API systemu Windows, które można ponownie dostosować do swoich potrzeb. W rzeczywistości jest to GUI AutoHotkey do łatwej zmiany ŚCIEŻKI systemu. Musi być uruchomiony jako administrator.


Przeczytaj pytanie. Jeszcze raz.
— jiggunjer,

Świetny scenariusz. Używam HotKey, ale nie wiem, jak i co muszę zrobić, aby dodać do niego skrypt. Czy możesz zaoferować pomoc, podać link lub wyjaśnić, co należy zrobić?
— jwzumwalt
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.