How to update PATH variable permanently from Windows command line?

242,740

Solution 1

The documentation on how to do this can be found on MSDN. The key extract is this:

To programmatically add or modify system environment variables, add them to the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment registry key, then broadcast a WM_SETTINGCHANGE message with lParam set to the string "Environment". This allows applications, such as the shell, to pick up your updates.

Note that your application will need elevated admin rights in order to be able to modify this key.

You indicate in the comments that you would be happy to modify just the per-user environment. Do this by editing the values in HKEY_CURRENT_USER\Environment. As before, make sure that you broadcast a WM_SETTINGCHANGE message.

You should be able to do this from your Java application easily enough using the JNI registry classes.

Solution 2

You can use:

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

However, setx will truncate the stored string to 1024 bytes, potentially corrupting the PATH.

/M will change the PATH in HKEY_LOCAL_MACHINE instead of HKEY_CURRENT_USER. In other words, a system variable, instead of the user's. For example:

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

You have to keep in mind, the new PATH is not visible in your current cmd.exe.

But if you look in the registry or on a new cmd.exe with "set p" you can see the new value.

Solution 3

I caution against using the command

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

to modify the PATH variable because of a "feature" of its implementation. On many (most?) installations these days the variable will be lengthy - setx will truncate the stored string to 1024 bytes, potentially corrupting the PATH (see the discussion here).

(I signed up specifically to flag this issue, and so lack the site reputation to directly comment on the answer posted on May 2 '12. My thanks to beresfordt for adding such a comment)

Solution 4

This Python-script[*] does exactly that:

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

Below are some usage examples, assuming it has been saved in a file called setenv.py somewhere in your current path. Note that in these examples i didn't have admin-rights, so the changes affected only my local user's registry tree:

> 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

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

Solution 5

For reference purpose, for anyone searching how to change the path via code, I am quoting a useful post by a Delphi programmer from this web page: http://www.tek-tips.com/viewthread.cfm?qid=686382

TonHu (Programmer) 22 Oct 03 17:57 I found where I read the original posting, it's here: http://news.jrsoftware.org/news/innosetup.isx/msg02129....

The excerpt of what you would need is this:

You must specify the string "Environment" in LParam. In Delphi you'd do it this way:

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

It was suggested by Jordan Russell, http://www.jrsoftware.org, the author of (a.o.) InnoSetup, ("Inno Setup is a free installer for Windows programs. First introduced in 1997, Inno Setup today rivals and even surpasses many commercial installers in feature set and stability.") (I just would like more people to use InnoSetup )

HTH

Share:
242,740
vale4674
Author by

vale4674

Updated on October 30, 2020

Comments

  • vale4674
    vale4674 over 3 years

    If I execute set PATH=%PATH%;C:\\Something\\bin from the command line (cmd.exe) and then execute echo %PATH% I see this string added to the PATH. If I close and open the command line, that new string is not in PATH.

    How can I update PATH permanently from the command line for all processes in the future, not just for the current process?

    I don't want to do this by going to System Properties → Advanced → Environment variables and update PATH there.

    This command must be executed from a Java application (please see my other question).

  • David Heffernan
    David Heffernan over 12 years
    Yes, using the JNI registry classes. A bigger issue is that your app probably doesn't run elevated. Do you know how to make it do that? If you only want a small portion of your app to run elevated (i.e. just to do this change) then the simplest solution is a very simple C++ app to do the job, marked with the app manifest, and then executed as a separate process which provokes the UAC dialog.
  • kichik
    kichik over 12 years
    You can also edit HKEY_CURRENT_USER\Environment to avoid elevation requirement.
  • vale4674
    vale4674 over 12 years
    @David Heffernan Yes only this thing has to run elevated. So your suggestion is to write C++ application and execute it from my java application? Can you provide me some example code or link on how to do this?
  • kichik
    kichik over 12 years
    Yep. Just like David said. Only you don't elevation. I should also mention this will modify the environment for the current user only.
  • David Heffernan
    David Heffernan over 12 years
    You need to separate this into a separate process so that you only force a UAC dialog when modifying system PATH. It just needs a simple C++ app with a few registry reads and writes, followed by a SendMessage. Set the requestedExecutionLevel to requireAdministrator in the app manifest.
  • vale4674
    vale4674 over 12 years
    @kichik Can you please provide me example command for updating this? I just wan't to add C:\Program Files\Program to the PATH. Can this update be run from CMD? If so then I can run the command with Runtime.getRuntime().exec("my command"); It is acceptable that this will modify PATH only for the current user.
  • vale4674
    vale4674 over 12 years
    @David Heffernan I am confused now, do I need that C++ program or not? kichink confused me when he said that it can be done from java app. I am not sure if he is thinking also that I need C++ program.
  • kichik
    kichik over 12 years
    If I were you, I'd just handle all this in the installer of your application. Every decent installation framework can change the environment.
  • David Heffernan
    David Heffernan over 12 years
    If you need to elevate then you need a separate process. Otherwise you are forced to running your entire app elevated which is bad practice and your users will hate you! If you just wish to change the per-user environment variable then you can modify the registry settings in HKCU\Environment.
  • vale4674
    vale4674 over 12 years
    @kichik That sure is the best way for the job but my application does not have an installation, it's just a runnable .jar and it is simpler for user just to run it from everywhere rather than have an installation. Also, my app designed for all platforms.
  • David Heffernan
    David Heffernan over 12 years
    Oh, and @kichik is right, if this is a one time operation then do it as part of installation which is the one time it is reasonable to assume that you have admin rights.
  • kichik
    kichik over 12 years
    There is no cross platform way you can permanently change the environment. Make your life and the user's life easier by creating an installer or at least a wrapper for Windows.
  • vale4674
    vale4674 over 12 years
    I know that there isn't cross platform environment change, that thing would me done only if the app is run on Windows. I already took a look at IzPack installer but it looks complicated to modify it. I'll take a look at Launch4j.
  • Corey Ogburn
    Corey Ogburn over 11 years
    Is there a way to use setx to change the machine's path instead of the user's path?
  • panny
    panny over 11 years
    From here you can tell it might be possible to set a variable not only for the currently logged in user but for the machine by using /m at the end of the command, on windows xp and 7. I haven't tried it though.
  • Nam G VU
    Nam G VU over 10 years
    I got the error when running setx command "Default option is not allowed more than '2' time" How to bypass it?
  • Nam G VU
    Nam G VU over 10 years
    I missed the quote for the value of PATH
  • Nam G VU
    Nam G VU over 10 years
    setx doesn't store the PATH value to the actual system variable!
  • Lzh
    Lzh over 10 years
    Interestingly, I had the correct path in my registry but cmd didn't get it until I ran setx. Thanks +1, but why??!!
  • Nam G VU
    Nam G VU almost 10 years
    setx cmd doesn't store the PATH value to the system variables. It makes changes to user variables instead.
  • Danny Lo
    Danny Lo over 9 years
    It does if you use /M just as panny mentioned it above. For an instance: setx PATH "%PATH%;C:\Somepath" /M
  • cubuspl42
    cubuspl42 over 9 years
    As other said, this does not update your system PATH but duplicates entries from system PATH into user's PATH...
  • Qwerty
    Qwerty over 9 years
    A possible drawback might be that all variables within PATH will get resolved.
  • David Heffernan
    David Heffernan about 9 years
    You have to modify the registry. Also, the cast to Integer is poor. Cast to LPARAM instead for 64 bit compatibility.
  • beresfordt
    beresfordt almost 9 years
    @KilgoreCod comments: I caution against using the command: On many (most?) installations these days the PATH variable will be lengthy - setx will truncate the stored string to 1024 bytes, potentially corrupting the PATH (see the discussion here superuser.com/q/812754).
  • Martin Smith
    Martin Smith over 8 years
    @beresfordt - Wish I'd seen that comment first. I've edited the warning into the answer.
  • Admin
    Admin almost 8 years
  • wlad
    wlad over 7 years
    When I run setx PATH "%PATH%;C:\\Program Files\\R\\R-3.3.2\\bin", I get ERROR: Invalid syntax. Default option is not allowed more than '2' time(s).
  • Laurence
    Laurence about 6 years
    I try to echo out the path it's already over 1200bytes. any other way instead of setx?
  • jwzumwalt
    jwzumwalt over 5 years
    Great script. I use HotKey but don't know how or what I need to do to add the script to it. Can you offer help, offer a link, or explain what needs to be done?