124

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).

Matthias Braun
  • 24,493
  • 16
  • 114
  • 144
vale4674
  • 3,931
  • 13
  • 41
  • 72
  • 5
    Using powershell, it's fairly straightfoward http://stackoverflow.com/questions/714877/setting-windows-powershell-path-variable. Using cmd, I'm not sure. You may have to modify the registry or pull in a .net assembly somehow. – Austen Holmes Dec 02 '11 at 15:12
  • 1
    As I said, I have to do this from within java application. I thought just to execute some cmd command useng java's `Runtime.getRuntime().exec("my command");` – vale4674 Dec 02 '11 at 15:56
  • Does this answer your question? [Adding a directory to the PATH environment variable in Windows](https://stackoverflow.com/questions/9546324/adding-a-directory-to-the-path-environment-variable-in-windows) – Dave Jarvis May 09 '21 at 19:29

7 Answers7

145

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.

Michael Mrozek
  • 149,906
  • 24
  • 156
  • 163
panny
  • 2,156
  • 4
  • 22
  • 25
  • 2
    Is there a way to use `setx` to change the machine's path instead of the user's path? – Corey Ogburn Jan 16 '13 at 04:11
  • 4
    From [here](http://ss64.com/nt/setx.html) 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. – panny Jan 20 '13 at 03:37
  • 1
    I got the error when running `setx` command "Default option is not allowed more than '2' time" How to bypass it? – Nam G VU Dec 17 '13 at 17:27
  • 1
    I missed the quote for the value of PATH – Nam G VU Dec 17 '13 at 17:33
  • setx doesn't store the PATH value to the actual system variable! – Nam G VU Dec 17 '13 at 17:48
  • Interestingly, I had the correct path in my registry but cmd didn't get it until I ran setx. Thanks +1, but why??!! – Mzn Dec 28 '13 at 18:25
  • `setx` cmd doesn't store the PATH value to the system variables. It makes changes to user variables instead. – Nam G VU Jun 14 '14 at 11:44
  • It does if you use `/M` just as panny mentioned it above. For an instance: `setx PATH "%PATH%;C:\Somepath" /M` – Danny Lo Oct 18 '14 at 14:23
  • As other said, this does not update your system PATH but _duplicates_ entries from system PATH into user's PATH... – cubuspl42 Dec 10 '14 at 21:04
  • A possible drawback might be that all variables within `PATH` will get resolved. – Qwerty Dec 29 '14 at 13:15
  • 12
    @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 http://superuser.com/q/812754). – beresfordt Jun 16 '15 at 19:25
  • @beresfordt - Wish I'd seen that comment first. I've edited the warning into the answer. – Martin Smith Jan 27 '16 at 10:37
  • 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)`. – ogogmad Jan 04 '17 at 10:03
  • 2
    I try to echo out the path it's already over 1200bytes. any other way instead of setx? – lawphotog Mar 05 '18 at 11:36
43

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.

David Heffernan
  • 572,264
  • 40
  • 974
  • 1,389
  • 1
    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. – David Heffernan Dec 02 '11 at 15:46
  • 1
    You can also edit `HKEY_CURRENT_USER\Environment` to avoid elevation requirement. – kichik Dec 02 '11 at 15:49
  • @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? – vale4674 Dec 02 '11 at 15:53
  • Yep. Just like David said. Only you don't elevation. I should also mention this will modify the environment for the current user only. – kichik Dec 02 '11 at 15:56
  • 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. – David Heffernan Dec 02 '11 at 15:56
  • @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 Dec 02 '11 at 16:03
  • @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. – vale4674 Dec 02 '11 at 16:06
  • If I were you, I'd just handle all this in the installer of your application. Every decent installation framework can change the environment. – kichik Dec 02 '11 at 16:10
  • 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. – David Heffernan Dec 02 '11 at 16:12
  • @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. – vale4674 Dec 02 '11 at 16:14
  • 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. – David Heffernan Dec 02 '11 at 16:15
  • 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](https://www.google.com/search?q=java+win32+wrapper). – kichik Dec 02 '11 at 16:18
  • 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. – vale4674 Dec 02 '11 at 16:26
38

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)

Community
  • 1
  • 1
KilgoreCod
  • 381
  • 3
  • 3
9

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/

ankostis
  • 6,471
  • 2
  • 37
  • 54
4

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

Svish
  • 138,188
  • 158
  • 423
  • 589
Steve F
  • 1,418
  • 1
  • 21
  • 46
  • You have to modify the registry. Also, the cast to Integer is poor. Cast to LPARAM instead for 64 bit compatibility. – David Heffernan Apr 17 '15 at 21:41
  • Here is example http://github.com/gilligan/snesdev/blob/1253994/tools/cc65-2.13.2/packages/windows/wm_envchange.c –  May 29 '16 at 06:50
4

In a corporate network, where the user has only limited access and uses portable apps, there are these command line tricks:

  1. Query the user env variables: reg query "HKEY_CURRENT_USER\Environment". Use "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" for LOCAL_MACHINE.
  2. Add new user env variable: reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ. Use REG_EXPAND_SZ for paths containing other %% variables.
  3. Delete existing env variable: reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir.
razvanone
  • 980
  • 12
  • 24
3

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

includes all the necessary Windows API calls which can be refactored for your needs. It is actually an AutoHotkey GUI to change the System PATH easily. Needs to be run as an Administrator.

War10ck
  • 11,732
  • 7
  • 38
  • 50
Evgeni Sergeev
  • 18,558
  • 15
  • 94
  • 112
  • 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? – jwzumwalt Sep 05 '18 at 05:21