Как постоянно обновлять переменную PATH из командной строки Windows?

122

Если я выполняю set PATH=%PATH%;C:\\Something\\binиз командной строки ( cmd.exe), а затем выполняю, echo %PATH%я вижу, что эта строка добавлена ​​в PATH. Если я закрою и открою командную строку, этой новой строки нет в PATH.

Как я могу постоянно обновлять PATH из командной строки для всех процессов в будущем, а не только для текущего процесса?

Я не хочу этого делать, перейдя в Свойства системы → Дополнительно → Переменные среды и обновив там PATH.

Эта команда должна выполняться из приложения Java (см. Мой другой вопрос ).

vale4674
источник
5
Используя powershell, это довольно просто. Stackoverflow.com/questions/714877/… . Используя cmd, я не уверен. Возможно, вам придется изменить реестр или каким-то образом вытащить сборку .net.
Остин Холмс
1
Как я уже сказал, я должен делать это из Java-приложения. Я думал просто выполнить какую-то команду cmd с использованием java'sRuntime.getRuntime().exec("my command");
vale4674 02

Ответы:

43

Документацию о том, как это сделать, можно найти на MSDN . Ключевой отрывок таков:

Чтобы программно добавить или изменить системные переменные среды, добавьте их в раздел реестра HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment , а затем передайте WM_SETTINGCHANGEсообщение с параметром lParam, установленным на строку «Environment». Это позволяет приложениям, таким как оболочка, получать ваши обновления.

Обратите внимание, что вашему приложению потребуются повышенные права администратора, чтобы иметь возможность изменять этот ключ.

Вы указываете в комментариях, что были бы счастливы изменить только среду для каждого пользователя. Сделайте это, отредактировав значения в HKEY_CURRENT_USER \ Environment . Как и раньше, убедитесь, что вы транслируете WM_SETTINGCHANGEсообщение.

Вы должны легко сделать это из своего Java-приложения, используя классы реестра JNI.

Дэвид Хеффернан
источник
1
Да, с использованием классов реестра JNI. Более серьезная проблема заключается в том, что ваше приложение, вероятно, не работает с повышенными правами. Вы знаете, как это сделать? Если вы хотите, чтобы только небольшая часть вашего приложения запускалась с повышенными правами (то есть просто для внесения этого изменения), то простейшим решением является очень простое приложение C ++ для выполнения этой работы, отмеченное манифестом приложения, а затем выполняемое как отдельный процесс, который вызывает диалог UAC.
Дэвид Хеффернан
1
Вы также можете редактировать, HKEY_CURRENT_USER\Environmentчтобы избежать требований к высоте.
kichik 02
@ Дэвид Хеффернан Да, только эта штука должна работать на повышенных уровнях. Итак, вы предлагаете написать приложение на C ++ и выполнить его из моего java-приложения? Можете ли вы предоставить мне пример кода или ссылку о том, как это сделать?
vale4674 02
Ага. Как и сказал Дэвид. Только ты не возвышаешься. Я также должен упомянуть, что это изменит среду только для текущего пользователя.
kichik 02
Вам нужно выделить это в отдельный процесс, чтобы вы вызывали диалог UAC только при изменении системного PATH. Ему просто нужно простое приложение C ++ с несколькими операциями чтения и записи в реестр, за которыми следует SendMessage. Установите requestedExecutionLevelдля requireAdministratorв приложении манифеста.
Дэвид Хеффернан
145

Ты можешь использовать:

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

Однако setxсохраненная строка будет усечена до 1024 байтов, что может привести к повреждению PATH.

/Mбудет меняться PATHв HKEY_LOCAL_MACHINEвместо HKEY_CURRENT_USER. Другими словами, системная переменная, а не пользовательская. Например:

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

Вы должны иметь в виду, что новый PATH не отображается в вашем текущем cmd.exe.

Но если вы посмотрите в реестре или на новый cmd.exeс "set p"вами может увидеть новое значение.

Panny
источник
2
Есть ли способ setxизменить путь к машине вместо пути пользователя?
Кори Огберн
4
Из здесь вы можете сказать , что это можно было бы установить переменную не только для текущего пользователя , но для машины, используя /mв конце команды, на Windows Xp и 7. Я не пробовал , хотя.
panny
1
Я получил ошибку при запуске setxкоманды «Параметр по умолчанию не допускается более 2 раз» Как обойти это?
Nam G VU
12
Комментарии @KilgoreCod: я предостерегаю от использования команды: на многих (большинстве?) Установок в наши дни переменная PATH будет длинной - setx усечет сохраненную строку до 1024 байтов, потенциально повреждая PATH (см. Обсуждение здесь superuser.com/ q / 812754 ).
beresfordt
2
Я пытаюсь повторить путь, который уже превышает 1200 байт. по-другому вместо setx?
lawphotog 05
37

Я предостерегаю от использования команды

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

для изменения переменной PATH из-за «особенности» ее реализации. На многих (большинстве?) Установок в наши дни переменная будет длинной - setxбудет усекать сохраненную строку до 1024 байтов, потенциально повреждая PATH (см. Обсуждение здесь ).

( Я подписался специально, чтобы отметить эту проблему, и поэтому у меня нет репутации сайта, чтобы напрямую комментировать ответ, опубликованный 2 мая 2012 года. Благодарю beresfordt за добавление такого комментария )

KilgoreCod
источник
9

Этот Python-скрипт [*] делает именно это:

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

Ниже приведены некоторые примеры использования, если он был сохранен в файле, который называется setenv.pyгде-то по вашему текущему пути. Обратите внимание, что в этих примерах у меня не было прав администратора , поэтому изменения коснулись только дерева реестра моего локального пользователя:

> 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

[*] Взято из: http://code.activestate.com/recipes/416087-persistent-environment-variables-on-windows/

ankostis
источник
4

Для справки, для тех, кто ищет, как изменить путь с помощью кода, я цитирую полезное сообщение программиста Delphi с этой веб-страницы: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (Программист) 22 окт. 03, 17:57 Я нашел то место, где я прочитал исходное сообщение, оно здесь: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

Вот отрывок из того, что вам понадобится:

Вы должны указать строку «Environment» в LParam. В Delphi это можно сделать так:

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

Это было предложено Джорданом Расселом, http://www.jrsoftware.org , автором (ao) InnoSetup, («Inno Setup - это бесплатный установщик для программ Windows. Впервые представленный в 1997 году, Inno Setup сегодня конкурирует и даже превосходит многие коммерческие установщики с набором функций и стабильностью. ") (Я просто хотел бы, чтобы больше людей использовали InnoSetup)

НТН

Стив Ф
источник
Вам необходимо изменить реестр. Также плохое приведение к Integer. Вместо этого используйте LPARAM для 64-битной совместимости.
Дэвид Хеффернан
4

В корпоративной сети, где пользователь имеет только ограниченный доступ и использует портативные приложения, существуют следующие уловки командной строки:

  1. Запрос переменных пользователя ENV: reg query "HKEY_CURRENT_USER\Environment". Используйте "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"для LOCAL_MACHINE.
  2. Добавить новую переменную пользователя ENV: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Используется REG_EXPAND_SZдля путей, содержащих другие переменные %%.
  3. Удалить существующую переменную ENV: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
razvanone
источник
3

Этот скрипт http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

включает все необходимые вызовы Windows API, которые можно отредактировать для ваших нужд. На самом деле это графический интерфейс AutoHotkey, позволяющий легко изменить системный путь. Требуется запускать от имени администратора.

Евгений Сергеев
источник
Прочтите вопрос. Очередной раз.
jiggunjer
Отличный сценарий. Я использую HotKey, но не знаю, как и что мне нужно сделать, чтобы добавить к нему скрипт. Можете ли вы предложить помощь, предложить ссылку или объяснить, что нужно сделать?
jwzumwalt 05