¿Cómo actualizar la variable PATH de forma permanente desde la línea de comandos de Windows?

122

Si ejecuto set PATH=%PATH%;C:\\Something\\bindesde la línea de comando ( cmd.exe) y luego ejecuto echo %PATH%, veo esta cadena agregada a la RUTA. Si cierro y abro la línea de comando, esa nueva cadena no está en PATH.

¿Cómo puedo actualizar PATH permanentemente desde la línea de comando para todos los procesos en el futuro, no solo para el proceso actual?

No quiero hacer esto yendo a Propiedades del sistema → Avanzado → Variables de entorno y actualice PATH allí.

Este comando debe ejecutarse desde una aplicación Java (consulte mi otra pregunta ).

vale4674
fuente
5
Usando powershell, es bastante sencillo stackoverflow.com/questions/714877/… . Usando cmd, no estoy seguro. Es posible que tenga que modificar el registro o extraer un ensamblado .net de alguna manera.
Austen Holmes
1
Como dije, tengo que hacer esto desde la aplicación Java. Pensé solo en ejecutar algún comando cmd usando java'sRuntime.getRuntime().exec("my command");
vale4674

Respuestas:

43

La documentación sobre cómo hacer esto se puede encontrar en MSDN . El extracto clave es este:

Para agregar o modificar mediante programación variables de entorno del sistema, agréguelas a la clave de registro HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment , luego transmita un WM_SETTINGCHANGEmensaje con lParam configurado en la cadena "Environment". Esto permite que las aplicaciones, como el shell, recojan sus actualizaciones.

Tenga en cuenta que su aplicación necesitará derechos de administrador elevados para poder modificar esta clave.

En los comentarios, indica que le gustaría modificar solo el entorno por usuario. Haga esto editando los valores en HKEY_CURRENT_USER \ Environment . Como antes, asegúrese de transmitir un WM_SETTINGCHANGEmensaje.

Debería poder hacer esto desde su aplicación Java con bastante facilidad utilizando las clases de registro JNI.

David Heffernan
fuente
1
Sí, usando las clases de registro JNI. Un problema mayor es que su aplicación probablemente no se ejecute de forma elevada. ¿Sabes cómo hacer eso? Si solo desea que una pequeña parte de su aplicación se ejecute de forma elevada (es decir, solo para hacer este cambio), la solución más simple es una aplicación C ++ muy simple para hacer el trabajo, marcada con el manifiesto de la aplicación y luego ejecutada como un proceso separado que provoca el diálogo UAC.
David Heffernan
1
También puede editar HKEY_CURRENT_USER\Environmentpara evitar el requisito de elevación.
kichik
@David Heffernan Sí, solo esto tiene que funcionar elevado. Entonces, ¿su sugerencia es escribir una aplicación C ++ y ejecutarla desde mi aplicación Java? ¿Puede proporcionarme un código de ejemplo o un enlace sobre cómo hacer esto?
vale4674
Sí. Como dijo David. Solo que no tienes elevación. También debo mencionar que esto modificará el entorno solo para el usuario actual.
kichik
Debe separar esto en un proceso separado para que solo fuerce un cuadro de diálogo UAC al modificar la RUTA del sistema. Solo necesita una aplicación C ++ simple con algunas lecturas y escrituras de registro, seguidas de SendMessage. Establezca requestedExecutionLevela requireAdministratoren el manifiesto de la aplicación.
David Heffernan
145

Puedes usar:

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

Sin embargo, setxtruncará la cadena almacenada a 1024 bytes, lo que podría dañar la RUTA.

/Mcambiará el PATHen en HKEY_LOCAL_MACHINElugar de HKEY_CURRENT_USER. En otras palabras, una variable del sistema, en lugar del usuario. Por ejemplo:

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

Tienes que tener en cuenta que el nuevo PATH no es visible en tu actual cmd.exe.

Pero si miras en el registro o en una nueva cmd.execon "set p"puedes ver el nuevo valor.

panny
fuente
2
¿Hay alguna forma de utilizar setxpara cambiar la ruta de la máquina en lugar de la ruta del usuario?
Corey Ogburn
4
Desde aquí puede decir que es posible establecer una variable no solo para el usuario actualmente conectado sino para la máquina usando /mal final del comando, en Windows XP y 7. Sin embargo, no lo he probado.
panny
1
Recibí el error al ejecutar el setxcomando "La opción predeterminada no se permite más de '2' veces" ¿Cómo omitirla?
Nam G VU
12
Comentarios de @KilgoreCod: advierto contra el uso del comando: en muchas (¿la mayoría?) Instalaciones en estos días, la variable PATH será larga: setx truncará la cadena almacenada a 1024 bytes, corrompiendo potencialmente la PATH (vea la discusión aquí superuser.com/ q / 812754 ).
beresfordt
2
Intento repetir el camino que ya tiene más de 1200 bytes. de alguna otra forma en lugar de setx?
lawphotog
37

Advierto contra el uso del comando

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

para modificar la variable PATH debido a una "característica" de su implementación. En muchas instalaciones (¿la mayoría?) De estos días, la variable será larga: setxtruncará la cadena almacenada a 1024 bytes, lo que podría dañar la RUTA (ver la discusión aquí ).

( Me inscribí específicamente para señalar este problema, por lo que no tengo la reputación del sitio para comentar directamente la respuesta publicada el 2 de mayo de 2012. Mi agradecimiento a beresfordt por agregar tal comentario )

KilgoreCod
fuente
9

Este script de Python [*] hace exactamente eso:

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

A continuación se muestran algunos ejemplos de uso, suponiendo que se haya guardado en un archivo llamado setenv.pyen algún lugar de su ruta actual. Tenga en cuenta que en estos ejemplos no tenía derechos de administrador , por lo que los cambios afectaron solo al árbol de registro de mi usuario local:

> 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

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

ankostis
fuente
4

Como referencia, para cualquiera que busque cómo cambiar la ruta a través del código, estoy citando una publicación útil de un programador de Delphi de esta página web: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (Programador) 22 de octubre de 03 17:57 Encontré donde leí la publicación original, está aquí: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

El extracto de lo que necesitaría es este:

Debe especificar la cadena "Entorno" en LParam. En Delphi lo harías de esta manera:

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

Fue sugerido por Jordan Russell, http://www.jrsoftware.org , el autor de (ao) InnoSetup, ("Inno Setup es un instalador gratuito para programas de Windows. Presentado por primera vez en 1997, Inno Setup hoy rivaliza e incluso supera a muchos instaladores comerciales en el conjunto de características y la estabilidad ") (solo me gustaría que más personas usaran InnoSetup)

HTH

Steve F
fuente
Tienes que modificar el registro. Además, la conversión a Integer es pobre. Transmitir a LPARAM en su lugar para compatibilidad de 64 bits.
David Heffernan
4

En una red corporativa, donde el usuario solo tiene acceso limitado y usa aplicaciones portátiles, existen estos trucos de línea de comando:

  1. Consultar las variables env usuario: reg query "HKEY_CURRENT_USER\Environment". Utilizar "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"para LOCAL_MACHINE.
  2. Añadir nueva variable de entorno de usuario: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Úselo REG_EXPAND_SZpara rutas que contengan otras %% variables.
  3. Eliminar variable de entorno existente: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
razvanone
fuente
3

Este script http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

incluye todas las llamadas a la API de Windows necesarias que se pueden refactorizar para sus necesidades. En realidad, es una GUI de AutoHotkey para cambiar fácilmente la RUTA del sistema. Debe ejecutarse como administrador.

Evgeni Sergeev
fuente
Lea la pregunta. De nuevo.
jiggunjer
Gran guión. Utilizo HotKey pero no sé cómo o qué debo hacer para agregarle el script. ¿Puede ofrecer ayuda, ofrecer un enlace o explicar lo que se debe hacer?
jwzumwalt