Como atualizar a variável PATH permanentemente na linha de comando do Windows?

122

Se eu executar a set PATH=%PATH%;C:\\Something\\binpartir da linha de comando ( cmd.exe) e, em seguida, executar echo %PATH%, vejo essa sequência adicionada ao PATH. Se eu fechar e abrir a linha de comando, essa nova sequência não estará no PATH.

Como posso atualizar o PATH permanentemente a partir da linha de comando para todos os processos no futuro, não apenas para o processo atual?

Não quero fazer isso acessando Propriedades do sistema → Avançado → Variáveis ​​de ambiente e atualize o PATH lá.

Este comando deve ser executado a partir de um aplicativo Java (consulte minha outra pergunta ).

vale4674
fonte
5
Usando o powershell, é bastante simples o stackoverflow.com/questions/714877/… . Usando cmd, não tenho certeza. Talvez você precise modificar o registro ou extrair um assembly .net de alguma forma.
Austen Holmes
1
Como eu disse, eu tenho que fazer isso de dentro do aplicativo java. Eu pensei apenas para executar algum comando cmd useng java'sRuntime.getRuntime().exec("my command");
vale4674

Respostas:

43

A documentação sobre como fazer isso pode ser encontrada no MSDN . A extração da chave é esta:

Para adicionar ou modificar programaticamente variáveis ​​de ambiente do sistema, adicione-as à chave de registro HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment e depois transmita uma WM_SETTINGCHANGEmensagem com lParam definido para a cadeia "Environment". Isso permite que aplicativos, como o shell, obtenham suas atualizações.

Observe que seu aplicativo precisará de direitos de administrador elevados para poder modificar essa chave.

Você indica nos comentários que ficaria feliz em modificar apenas o ambiente por usuário. Faça isso editando os valores em HKEY_CURRENT_USER \ Environment . Como antes, verifique se você transmitiu uma WM_SETTINGCHANGEmensagem.

Você deve conseguir fazer isso a partir do seu aplicativo Java com bastante facilidade usando as classes de registro JNI.

David Heffernan
fonte
1
Sim, usando as classes de registro JNI. Um problema maior é que seu aplicativo provavelmente não é executado elevado. Você sabe como fazer isso? Se você deseja que apenas uma pequena parte do seu aplicativo seja executada elevada (ou seja, apenas para fazer essa alteração), a solução mais simples é um aplicativo C ++ muito simples para realizar o trabalho, marcado com o manifesto do aplicativo e depois executado como um processo separado que provoca o diálogo do UAC.
David Heffernan
1
Você também pode editar HKEY_CURRENT_USER\Environmentpara evitar os requisitos de elevação.
Kichik
@ David Heffernan Sim, apenas essa coisa tem que correr elevado. Então, sua sugestão é escrever um aplicativo C ++ e executá-lo no meu aplicativo java? Você pode me fornecer um exemplo de código ou link sobre como fazer isso?
precisa saber é o seguinte
Sim. Assim como David disse. Só você não eleva. Também devo mencionar que isso modificará o ambiente apenas para o usuário atual.
Kichik
Você precisa separar isso em um processo separado, para forçar apenas um diálogo do UAC ao modificar o PATH do sistema. Ele só precisa de um aplicativo C ++ simples, com algumas leituras e gravações no registro, seguidas por uma SendMessage. Defina requestedExecutionLevelcomo requireAdministratorno manifesto do aplicativo.
David Heffernan,
145

Você pode usar:

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

No entanto, setxtruncará a cadeia armazenada para 1024 bytes, potencialmente corrompendo o PATH.

/Mvai mudar o PATHem HKEY_LOCAL_MACHINEvez de HKEY_CURRENT_USER. Em outras palavras, uma variável do sistema, em vez do usuário. Por exemplo:

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

Você deve ter em mente que o novo PATH não é visível no seu atual cmd.exe.

Mas se você olhar no registro ou em um novo cmd.execom "set p"você, poderá ver o novo valor.

panny
fonte
2
Existe uma maneira de setxalterar o caminho da máquina em vez do caminho do usuário?
Corey Ogburn
4
A partir daqui, você pode dizer que pode ser possível definir uma variável não apenas para o usuário conectado no momento, mas para a máquina usando /mno final do comando, no Windows XP e no 7. Ainda não tentei.
panny
1
Eu recebi o erro ao executar o setxcomando "Opção padrão não é permitida mais que o tempo '2'" Como ignorá-lo?
Nam G VU
12
Comentários do @KilgoreCod: Eu aviso contra o uso do comando: Em muitas instalações (a maioria?) Hoje em dia a variável PATH será longa - o setx truncará a string armazenada em 1024 bytes, potencialmente corrompendo o PATH (consulte a discussão aqui superuser.com/ q / 812754 ).
beresfordt
2
Eu tento ecoar o caminho que já tem mais de 1200 bytes. alguma outra maneira em vez de setx?
lawphotog
37

Eu aviso contra o uso do comando

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

para modificar a variável PATH devido a um "recurso" de sua implementação. Em muitas instalações (a maioria?) Atualmente, a variável será longa - setxtruncará a cadeia armazenada para 1024 bytes, potencialmente corrompendo o PATH (consulte a discussão aqui ).

( Eu me inscrevi especificamente para sinalizar esse problema e, portanto, não tenho a reputação do site para comentar diretamente a resposta postada em 2 de maio de 12. Meus agradecimentos a beresfordt por adicionar esse comentário )

KilgoreCod
fonte
9

Este script Python [*] faz exatamente isso:

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

Abaixo estão alguns exemplos de uso, supondo que ele tenha sido salvo em um arquivo chamado setenv.pyem algum lugar do seu caminho atual. Observe que nesses exemplos eu não tinha direitos de administrador , portanto as alterações afetaram apenas a árvore de registro do meu usuário 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
fonte
4

Para fins de referência, para quem procura alterar o caminho via código, estou citando uma publicação útil de um programador Delphi nesta página da web: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (Programador) 22 de outubro 03 17:57 Encontrei onde li a postagem original, que está aqui: http://news.jrsoftware.org/news/innosetup.isx/msg02129 ....

O trecho do que você precisa é este:

Você deve especificar a sequência "Ambiente" no LParam. No Delphi, você faria da seguinte maneira:

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

Foi sugerido por Jordan Russell, http://www.jrsoftware.org , autor de (ao) InnoSetup, ("O Inno Setup é um instalador gratuito para programas Windows. Introduzido pela primeira vez em 1997, o Inno Setup hoje rivaliza e até supera muitos instaladores comerciais no conjunto de recursos e estabilidade. ") (Eu gostaria que mais pessoas usassem o InnoSetup)

HTH

Steve F
fonte
Você precisa modificar o registro. Além disso, a conversão para Inteiro é ruim. Em vez disso, transmita para LPARAM para compatibilidade de 64 bits.
David Heffernan
4

Em uma rede corporativa, onde o usuário tem acesso limitado e usa aplicativos portáteis, existem estes truques de linha de comando:

  1. Consultar as variáveis de usuário env: reg query "HKEY_CURRENT_USER\Environment". Use "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"para LOCAL_MACHINE.
  2. Adicionar nova variável de usuário env: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Use REG_EXPAND_SZpara caminhos que contenham outras variáveis ​​%%.
  3. Excluir variável env existente: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
razvanone
fonte
3

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

inclui todas as chamadas necessárias da API do Windows que podem ser refatoradas para suas necessidades. Na verdade, é uma GUI do AutoHotkey para alterar o PATH do sistema facilmente. Precisa ser executado como administrador.

Evgeni Sergeev
fonte
Leia a pergunta. Novamente.
precisa saber é o seguinte
Ótimo roteiro. Eu uso o HotKey, mas não sei como ou o que preciso fazer para adicionar o script a ele. Você pode oferecer ajuda, oferecer um link ou explicar o que precisa ser feito?
Jwzumwalt # 5/18