Comment mettre à jour la variable PATH de manière permanente à partir de la ligne de commande Windows?

122

Si j'exécute à set PATH=%PATH%;C:\\Something\\binpartir de la ligne de commande ( cmd.exe) puis que echo %PATH%je l' exécute, je vois cette chaîne ajoutée au PATH. Si je ferme et ouvre la ligne de commande, cette nouvelle chaîne n'est pas dans PATH.

Comment puis-je mettre à jour PATH de manière permanente à partir de la ligne de commande pour tous les processus à l'avenir, pas seulement pour le processus actuel?

Je ne veux pas faire cela en allant dans Propriétés système → Avancé → Variables d'environnement et mettre à jour PATH ici.

Cette commande doit être exécutée depuis une application Java (voir mon autre question ).

vale4674
la source
5
En utilisant PowerShell, c'est assez simple stackoverflow.com/questions/714877/… . En utilisant cmd, je ne suis pas sûr. Vous devrez peut-être modifier le Registre ou extraire un assembly .net d'une manière ou d'une autre.
Austen Holmes
1
Comme je l'ai dit, je dois le faire depuis l'application java. J'ai pensé juste à exécuter une commande cmd useng java'sRuntime.getRuntime().exec("my command");
vale4674

Réponses:

43

La documentation expliquant comment procéder se trouve sur MSDN . L'extrait clé est le suivant:

Pour ajouter ou modifier par programme des variables d'environnement système, ajoutez-les à la clé de registre HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment , puis WM_SETTINGCHANGEdiffusez un message avec lParam défini sur la chaîne «Environnement». Cela permet aux applications, telles que le shell, de récupérer vos mises à jour.

Notez que votre application aura besoin de droits d'administrateur élevés pour pouvoir modifier cette clé.

Vous indiquez dans les commentaires que vous seriez heureux de modifier uniquement l'environnement par utilisateur. Pour ce faire, modifiez les valeurs dans HKEY_CURRENT_USER \ Environment . Comme auparavant, assurez-vous de diffuser un WM_SETTINGCHANGEmessage.

Vous devriez pouvoir le faire à partir de votre application Java assez facilement en utilisant les classes de registre JNI.

David Heffernan
la source
1
Oui, en utilisant les classes de registre JNI. Un problème plus important est que votre application ne fonctionne probablement pas en mode élevé. Savez-vous comment faire cela? Si vous ne voulez qu'une petite partie de votre application s'exécute en élévation (c'est-à-dire juste pour faire ce changement), la solution la plus simple est une application C ++ très simple pour faire le travail, marquée avec le manifeste de l'application, puis exécutée comme un processus séparé qui provoque le dialogue UAC.
David Heffernan
1
Vous pouvez également modifier HKEY_CURRENT_USER\Environmentpour éviter l'exigence d'élévation.
kichik
@David Heffernan Oui, seule cette chose doit être élevée. Donc, votre suggestion est d'écrire une application C ++ et de l'exécuter à partir de mon application java? Pouvez-vous me fournir un exemple de code ou un lien sur la façon de procéder?
vale4674
Oui. Tout comme David l'a dit. Seulement vous ne faites pas d'élévation. Je dois également mentionner que cela modifiera l'environnement pour l'utilisateur actuel uniquement.
kichik
Vous devez séparer cela en un processus distinct afin de ne forcer qu'une boîte de dialogue UAC lors de la modification du PATH système. Il a juste besoin d'une simple application C ++ avec quelques lectures et écritures de registre, suivies d'un SendMessage. Définissez le requestedExecutionLevelsur requireAdministratordans le manifeste de l'application.
David Heffernan
145

Vous pouvez utiliser:

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

Cependant, setxtronquera la chaîne stockée à 1024 octets, corrompant potentiellement le PATH.

/Mchangera l' entrée PATHau HKEY_LOCAL_MACHINElieu de HKEY_CURRENT_USER. En d'autres termes, une variable système, au lieu de l'utilisateur. Par exemple:

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

Vous devez garder à l'esprit que le nouveau PATH n'est pas visible dans votre courant cmd.exe.

Mais si vous regardez dans le registre ou sur un nouveau cmd.exeavec "set p"vous pouvez voir la nouvelle valeur.

pany
la source
2
Existe-t-il un moyen d'utiliser setxpour modifier le chemin de la machine au lieu du chemin de l'utilisateur?
Corey Ogburn
4
De là, vous pouvez dire qu'il pourrait être possible de définir une variable non seulement pour l'utilisateur actuellement connecté, mais pour la machine en utilisant /mà la fin de la commande, sur Windows XP et 7. Je ne l'ai pas essayé cependant.
panny
1
J'ai eu l'erreur lors de l'exécution de la setxcommande "L'option par défaut n'est pas autorisée plus de '2' fois" Comment la contourner?
Nam G VU
12
Commentaires @KilgoreCod: Je mets en garde contre l'utilisation de la commande: sur de nombreuses (la plupart?) Installations ces jours-ci, la variable PATH sera longue - setx tronquera la chaîne stockée à 1024 octets, corrompant potentiellement le PATH (voir la discussion ici superuser.com/ q / 812754 ).
beresfordt
2
J'essaye de faire écho au chemin qui dépasse déjà 1200 octets. d'une autre manière au lieu de setx?
lawphotog
37

Je mets en garde contre l'utilisation de la commande

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

pour modifier la variable PATH en raison d'une "fonctionnalité" de son implémentation. Sur de nombreuses (la plupart?) Installations ces jours-ci, la variable sera longue - setxtronquera la chaîne stockée à 1024 octets, corrompant potentiellement le PATH (voir la discussion ici ).

( Je me suis inscrit spécifiquement pour signaler ce problème et je n'ai donc pas la réputation du site pour commenter directement la réponse publiée le 2 mai 2012. Merci à beresfordt d'avoir ajouté un tel commentaire )

KilgoreCod
la source
9

Ce script Python [*] fait exactement cela:

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

Vous trouverez ci-dessous quelques exemples d'utilisation, en supposant qu'il a été enregistré dans un fichier appelé setenv.pyquelque part dans votre chemin actuel. Notez que dans ces exemples, je n'avais pas de droits d'administrateur , donc les changements n'ont affecté que l'arborescence de registre de mon utilisateur 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

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

Ankostis
la source
4

À titre de référence, pour quiconque cherche comment changer le chemin via le code, je cite un article utile d'un programmeur Delphi à partir de cette page Web: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (programmeur) 22 oct 03 17:57 J'ai trouvé où j'ai lu l'article original, c'est ici: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

L'extrait de ce dont vous auriez besoin est le suivant:

Vous devez spécifier la chaîne "Environnement" dans LParam. Dans Delphi, vous le feriez de cette façon:

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

Il a été suggéré par Jordan Russell, http://www.jrsoftware.org , l'auteur de (ao) InnoSetup, ("Inno Setup est un installateur gratuit pour les programmes Windows. Introduit pour la première fois en 1997, Inno Setup rivalise aujourd'hui et dépasse même de nombreux installateurs commerciaux dans l'ensemble des fonctionnalités et la stabilité. ") (Je voudrais juste que plus de personnes utilisent InnoSetup)

HTH

Steve F
la source
Vous devez modifier le registre. De plus, la conversion en Integer est médiocre. Diffusez plutôt vers LPARAM pour une compatibilité 64 bits.
David Heffernan
4

Dans un réseau d'entreprise, où l'utilisateur n'a qu'un accès limité et utilise des applications portables, il existe ces astuces de ligne de commande:

  1. Interroger les variables d'environnement utilisateur: reg query "HKEY_CURRENT_USER\Environment". À utiliser "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"pour LOCAL_MACHINE.
  2. Ajouter une nouvelle variable d'environnement utilisateur: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. À utiliser REG_EXPAND_SZpour les chemins contenant d'autres variables %%.
  3. Supprimer variable env existante: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
razvanone
la source
3

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

inclut tous les appels d'API Windows nécessaires qui peuvent être refactorisés selon vos besoins. Il s'agit en fait d'une interface graphique AutoHotkey pour changer facilement le PATH système. Doit être exécuté en tant qu'administrateur.

Evgeni Sergeev
la source
Lisez la question. Encore.
jiggunjer
Excellent scénario. J'utilise HotKey mais je ne sais pas comment ou ce que je dois faire pour y ajouter le script. Pouvez-vous offrir de l'aide, proposer un lien ou expliquer ce qui doit être fait?
jwzumwalt