10

How do I permanently add the path to system's environment variable "PATH"?

I want to only add the path if it does not already exist.

Also I want to remove all paths that contain a folder name such as \myprogram whether it be:

C:\path\to\myprogram\dist; or D:\another\path\to\myprogram\dist;

5 Answers 5

13

Here's something that does what you want which is similar to code in the jaraco.windows project. And like it, only uses built-in Python modules—so doesn't require first downloading and installing the pywin32 extensions. Plus it's Python 2.6+ and 3.x compatible and supports Unicode environment variables and values (directory paths in this case).

Note that Windows administrator rights are required to change the permanent system-level environment variables.

import ctypes
from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM, LPVOID
LRESULT = LPARAM  # synonymous
import os
import sys
try:
    import winreg
    unicode = str
except ImportError:
    import _winreg as winreg  # Python 2.x

class Environment(object):
    path = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
    hklm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
    key = winreg.OpenKey(hklm, path, 0, winreg.KEY_READ | winreg.KEY_WRITE)
    SendMessage = ctypes.windll.user32.SendMessageW
    SendMessage.argtypes = HWND, UINT, WPARAM, LPVOID
    SendMessage.restype = LRESULT
    HWND_BROADCAST = 0xFFFF
    WM_SETTINGCHANGE = 0x1A
    NO_DEFAULT_PROVIDED = object()

    def get(self, name, default=NO_DEFAULT_PROVIDED):
        try:
            value = winreg.QueryValueEx(self.key, name)[0]
        except WindowsError:
            if default is self.NO_DEFAULT_PROVIDED:
                raise ValueError("No such registry key", name)
            value = default
        return value

    def set(self, name, value):
        if value:
            winreg.SetValueEx(self.key, name, 0, winreg.REG_EXPAND_SZ, value)
        else:
            winreg.DeleteValue(self.key, name)
        self.notify()

    def notify(self):
        self.SendMessage(self.HWND_BROADCAST, self.WM_SETTINGCHANGE, 0, u'Environment')

Environment = Environment()  # singletion - create instance

PATH_VAR = 'PATH'

def append_path_envvar(addpath):
    def canonical(path):
        path = unicode(path.upper().rstrip(os.sep))
        return winreg.ExpandEnvironmentStrings(path)  # Requires Python 2.6+
    canpath = canonical(addpath)
    curpath = Environment.get(PATH_VAR, '')
    if not any(canpath == subpath
                for subpath in canonical(curpath).split(os.pathsep)):
        Environment.set(PATH_VAR, os.pathsep.join((curpath, addpath)))

def remove_envvar_path(folder):
    """ Remove *all* paths in PATH_VAR that contain the folder path. """
    curpath = Environment.get(PATH_VAR, '')
    folder = folder.upper()
    keepers = [subpath for subpath in curpath.split(os.pathsep)
                if folder not in subpath.upper()]
    Environment.set(PATH_VAR, os.pathsep.join(keepers))

Sample usage:

print(Environment.get('path'))
append_path_envvar(r'C:\path\to\myprogram\dist')
append_path_envvar(r'D:\another\path\to\myprogram\dist')
print(Environment.get('path'))
remove_envvar_path(r'\myprogram')  # remove *both* added paths
print(Environment.get('path'))
Sign up to request clarification or add additional context in comments.

4 Comments

Brilliant! It really answers the question the best way. Saved me 2 hours.
@Vasily: You're welcome. Note I just made a few minor improvements, if you're interested.
That is great. But what about user environment variables? You code can only remove env var from system, not user's ones.
@Gauthier: That's because the question is about modifying the system-level environment variables. I would assume the user's variables are simply stored somewhere else in the registry — probably HKEY_CURRENT_USER\Environment.
11
+50
import _winreg as reg
import win32gui
import win32con


# read the value
key = reg.OpenKey(reg.HKEY_CURRENT_USER, 'Environment', 0, reg.KEY_ALL_ACCESS)
# use this if you need to modify the system variable and if you have admin privileges
#key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 0, reg.KEY_ALL_ACCESS) 
try
    value, _ = reg.QueryValueEx(key, 'PATH')
except WindowsError:
    # in case the PATH variable is undefined
    value = ''

# modify it
value = ';'.join([s for s in value.split(';') if not r'\myprogram' in s])

# write it back
reg.SetValueEx(key, 'PATH', 0, reg.REG_EXPAND_SZ, value)
reg.CloseKey(key)

# notify the system about the changes
win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')

1 Comment

Note that win32gui and win32con are contained in the package pywin32. At least in version 301 of pywin32, you need to do import win32.win32gui as win32gui instead of import win32gui.
1

There is a python package pathtub (I am the author), which can do the job. You can read the code and docs on GitHub.

Installing

pip install pathtub

Example usage

Reading Path

from pathtub import get_path

# Getting path (can be 'process' (default), 'user' or 'machine')
user_path = get_path('user')

print(user_path)
# C:\Program Files\Java\jdk-13.0.1\bin;C:\Programs;C:\Programs\apache-maven-3.6.2\bin;C:\Programs\cloc;C:\Programs\fciv;C:\Python\Python37;C:\Python\Python37\lib\site-packages\pywin32_system32;C:\Python\Python37\Scripts;C:\texlive\2018\bin\win32;C:\Users\USER\AppData\Local\Microsoft\WindowsApps;C:\Users\USER\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\USER\AppData\Roaming\npm

Adding to path

from pathtub import add_to_path
added = add_to_path(r'C:\Add this folder\to user path', mode='user')

print(added)
#True

# Adding duplicate entries is prevented
added = add_to_path(r'C:\Add this folder\to user path', mode='user')

print(added)
#False

Removing from Path

removed = remove_from_path(r'C:\Add this folder\to user path', mode='user')

print(removed)
#True

# Removing non-existing folder just returns False
removed = remove_from_path(r'C:\Add this folder\to user path', mode='user')

print(removed)
#False

Requirements

Current implementation (v.1.1.2) uses Powershell for the permanent Path modifications. I have only tested this with newer (Python 3.7 and 3.8), but I guess it should work also on some older versions.

Comments

0

I am inferring from the paths in your question that your are interested in doing this on the Windows platform.

The documentation describes the process:

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.

2 Comments

Do you know of any python libraries or simple scripts that take parameters and do the work for you?
win32xxx can do send message, and winreg does registry
-1

You should check os.environ. It's a dictionary that can be manipulated directly or via os.putenv:

Set the environment variable named varname to the string value. Such changes to the environment affect subprocesses started with os.system(), popen() or fork() and execv().

Hence:

>>> import os
>>> os.environ["PATH"] =  path_old + ":/tmp/hallo" 
>>> os.environ["PATH"] 
'/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/vendor_perl:/usr/bin/core_perl:/tmp/hallo'

[update]

according to this answer you can make them persistent via windows registry

1 Comment

You cannot "magically" make the changes to os.environ persistent using windows registry. You must write a concrete value there. You do not need to modify os.environ in order to do this. Moreover, you don't need to read it: the value of os.environ["PATH"] is composed of two values: user PATH and system PATH, which are stored in different registry keys. You should read a corresponding registry value instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.