python脚本可以持久地更改Windows环境变量吗? (典雅)

时间:2009-01-28 17:00:54

标签: python windows scripting batch-file

继我的previous question之后,是否有可能制作一个持久更改Windows环境变量的Python脚本?

一旦python解释器终止,对os.environ的更改不会保留。如果我在UNIX上编写脚本,我可能会这样做:

set foo=`myscript.py`

但是,唉,cmd.exe没有像sh的反向行为那样的东西。我已经看到了一个非常冗长的解决方案......它确实非常可靠,我们可以改进这个:

for /f "tokens=1* delims=" %%a in ('python  ..\myscript.py') do set path=%path%;%%a

当然,微软的想法有一个比这更好的解决方案!

注意this question的完全重复。

5 个答案:

答案 0 :(得分:5)

您可能想尝试由Mark Hammond开发的Python Win32 Extensions,它包含在ActivePython中(或可以单独安装)。您可以在Hammond's and Robinson's book中了解如何执行许多与Windows相关的任务。

使用 PyWin32 访问windows COM对象,Python程序可以使用WScript.Shell对象的Environment Property - 环境变量的集合

答案 1 :(得分:3)

Windows为每个进程独立存储在Registry中的值设置环境变量。

但是,名为setx.exe的Windows XP Service Pack 2 Support Tools中有一个工具允许您从命令行更改全局环境变量。

答案 2 :(得分:3)

我使用win32api的解决方案:

import os, sys, win32api, win32con
'''Usage: appendenv.py envvar data_to_append'''
def getenv_system(varname, default=None):
    '''
    Author: Denis Barmenkov <barmenkov at bpc.ru>

    Copyright: this code is free, but if you want to use it, 
               please keep this multiline comment along with function source. 
               Thank you.

    2006-01-28 15:30
    '''
    v = default
    try:
        rkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
        try:
            v = str(win32api.RegQueryValueEx(rkey, varname)[0])
            v = win32api.ExpandEnvironmentStrings(v)
        except:
            pass
    finally:
        win32api.RegCloseKey(rkey)
    return v

#My set function
def setenv_system(varname, value):
    try:
        rkey = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',0 ,win32con.KEY_WRITE)
        try:
            win32api.RegSetValueEx(rkey, varname, 0, win32con.REG_SZ, value)
            return True
        except Exception, (error):
            pass
    finally:
        win32api.RegCloseKey(rkey)
    return False

if len(sys.argv) == 3:
    value = getenv_system(sys.argv[1])
    if value:
        setenv_system(sys.argv[1],value + ";" + sys.argv[2])
        print "OK! %s = %s" % (sys.argv[1], getenv_system(sys.argv[1]))
    else:
        print "ERROR: No such environment variable. (%s)" % sys.argv[1]
else:
    print "Usage: appendenv.py envvar data_to_append"

答案 3 :(得分:2)

link提供了使用内置winreg库的解决方案。

(copypasta)

import sys
from subprocess import check_call
if sys.hexversion > 0x03000000:
    import winreg
else:
    import _winreg as winreg

class Win32Environment:
    """Utility class to get/set windows environment variable"""

    def __init__(self, scope):
        assert scope in ('user', 'system')
        self.scope = scope
        if scope == 'user':
            self.root = winreg.HKEY_CURRENT_USER
            self.subkey = 'Environment'
        else:
            self.root = winreg.HKEY_LOCAL_MACHINE
            self.subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'

    def getenv(self, name):
        key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_READ)
        try:
            value, _ = winreg.QueryValueEx(key, name)
        except WindowsError:
            value = ''
        return value

    def setenv(self, name, value):
        # Note: for 'system' scope, you must run this as Administrator
        key = winreg.OpenKey(self.root, self.subkey, 0, winreg.KEY_ALL_ACCESS)
        winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
        winreg.CloseKey(key)
        # For some strange reason, calling SendMessage from the current process
        # doesn't propagate environment changes at all.
        # TODO: handle CalledProcessError (for assert)
        check_call('''\
"%s" -c "import win32api, win32con; assert win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')"''' % sys.executable)

答案 4 :(得分:1)

你啰嗦的解决方案可能是最好的主意;我不相信这可以直接来自Python。本文提出了另一种方法,使用临时批处理文件:

http://code.activestate.com/recipes/159462/