如何从Windows命令行永久更新PATH变量?


122

如果我set PATH=%PATH%;C:\\Something\\bin从命令行(cmd.exe)执行然后执行,echo %PATH%我会看到此字符串已添加到PATH。如果我关闭并打开命令行,则该新字符串不在PATH中。

将来如何从命令行永久更新PATH,而不仅限于当前进程?

我不想通过转到“系统属性”→“高级”→“环境变量”并在那里更新PATH来执行此操作。

该命令必须从Java应用程序执行(请参阅我的其他问题)。


5
使用powershell,这是相当简单的stackoverflow.com/questions/714877/…。我不确定使用cmd。您可能必须修改注册表或以某种方式引入.net程序集。
奥斯汀·福尔摩斯

1
正如我所说,我必须在Java应用程序中执行此操作。我以为只是使用Java执行某些cmd命令Runtime.getRuntime().exec("my command");
vale4674 2011年

Answers:


43

有关如何执行此操作的文档可以在MSDN上找到。关键摘录是这样的:

要以编程方式添加或修改系统环境变量,请将它们添加到HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment注册表项中,然后广播一条WM_SETTINGCHANGE消息,其中lParam设置为字符串“ Environment”。这样,外壳程序之类的应用程序就可以获取您的更新。

请注意,您的应用程序将需要提升的管理员权限才能修改此密钥。

您可以在评论中指出您很乐意仅修改每个用户的环境。通过编辑HKEY_CURRENT_USER \ Environment中的值来执行此操作。和以前一样,请确保您广播了一条WM_SETTINGCHANGE消息。

您应该能够使用JNI注册表类在Java应用程序中轻松地完成此操作。


1
是的,使用JNI注册表类。更大的问题是您的应用程序可能未提升运行。你知道如何做到这一点吗?如果您只希望应用程序的一小部分运行提升(即仅执行此更改),那么最简单的解决方案是执行该工作的非常简单的C ++应用程序,该应用程序带有应用程序清单标记,然后作为单独的进程执行,引发UAC对话框。
David Heffernan

1
您也可以编辑HKEY_CURRENT_USER\Environment以避免高程要求。
kichik 2011年

@David Heffernan是的,只有这件事必须提高。因此,您的建议是编写C ++应用程序并从我的Java应用程序执行它?您能否提供一些示例代码或有关如何执行此操作的链接?
vale4674 2011年

是的 就像大卫说的那样。只有你不抬高。我还应该提到这只会修改当前用户的环境。
kichik 2011年

您需要将其分为一个单独的过程,以便仅在修改系统PATH时强制执行UAC对话框。它只需要一个简单的C ++应用程序,并具有一些注册表读取和写入,然后是一个SendMessage。将requestedExecutionLevelrequireAdministrator在应用程序清单。
David Heffernan

145

您可以使用:

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

但是,setx会将存储的字符串截断为1024个字节,可能会损坏PATH。

/M将更改PATHin HKEY_LOCAL_MACHINE而不是HKEY_CURRENT_USER。换句话说,是系统变量,而不是用户变量。例如:

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

您必须记住,新的PATH在您当前的中不可见cmd.exe

但是,如果您查看注册表或使用新的注册表cmd.exe,则"set p"可以看到新值。


2
有没有一种方法可以setx用来更改机器的路径而不是用户的路径?
科里·奥格本

4
这里可以看出,不仅可能为当前登录的用户设置变量,而且还可以通过/m在命令的末尾在Windows XP和Windows 7上使用此机器来设置变量。我没有尝试过。
panny

1
运行setx命令“默认选项的允许时间不超过'2'的时间” 时出现错误,如何绕过它?
Nam G VU 2013年

12
@KilgoreCod注释:我警告不要使用该命令:如今在许多(大多数?)安装中,PATH变量会很长-setx将存储的字符串截断为1024个字节,可能会损坏PATH(请参见此处的讨论superuser.com/ q / 812754)。
beresfordt 2015年

2
我尝试回显已经超过1200bytes的路径。还有其他方法来代替setx吗?
lawphotog

37

我警告不要使用该命令

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

修改PATH变量,因为其实现具有“功能”。如今,在许多(大多数?)安装中,变量将很长- setx会将存储的字符串截断为1024个字节,从而可能损坏PATH(请参阅此处的讨论)。

我专门注册以标记此问题,因此缺乏站点声誉,无法直接对12年5月2日发布的答案发表评论。感谢beresfordt添加了此评论


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当前路径中某个位置的文件中。请注意,在这些示例中,我没有admin权限,因此更改仅影响本地用户的注册表树:

> 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/


4

作为参考,对于任何寻求通过代码更改路径的人,我在此网页上引用了Delphi程序员的有用文章:http : //www.tek-tips.com/viewthread.cfm?qid=686382

TonHu(程序员)2006年10月22日17:57我在哪里阅读了原始帖子,它在这里:http : //news.jrsoftware.org/news/innosetup.isx/msg02129 ....

您需要的摘录如下:

您必须在LParam中指定字符串“ Environment”。在Delphi中,您可以这样进行:

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

它是由(ao)InnoSetup的作者Jordan Russell(http://www.jrsoftware.org)提出的。(“ Inno Setup是Windows程序的免费安装程序。InnoSetup于1997年首次推出,如今可与甚至超过许多其他公司竞争。功能和稳定性方面的商业安装程序。”)(我想让更多的人使用InnoSetup)

高温超导


您必须修改注册表。同样,对整数的转换也很差。强制转换为LPARAM以获得64位兼容性。
David Heffernan


4

在企业网络中,用户只有有限的访问权限并使用便携式应用程序,这些命令行技巧有:

  1. 查询用户环境变量:reg query "HKEY_CURRENT_USER\Environment"。使用"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"的LOCAL_MACHINE。
  2. 添加新的用户环境变量:reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ。使用REG_EXPAND_SZ含有其他%%变量路径。
  3. 删除现有的环境变量:reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir

3

该脚本 http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

包括所有必要的Windows API调用,可以根据需要对其进行重构。它实际上是一个AutoHotkey GUI,可以轻松更改系统路径。需要以管理员身份运行。


阅读问题。再次。
jiggunjer

很棒的剧本。我使用HotKey,但不知道将脚本添加到其中的方法或需要做的事情。您可以提供帮助,提供链接或解释需要做什么吗?
jwzumwalt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.