2009-07-06 23 views
16

如何持久地從Python腳本修改Windows環境變量? (這是setup.py腳本)從Python修改Windows環境變量的界面

我正在尋找一個標準函數或模塊來使用它。我已經熟悉了registry way of doing it,但任何有關這方面的意見也是值得歡迎的。

+0

你的意思是持續性的環境變量(比如'setx'命令)還是改變當前進程的變量(比如'set'命令)?事實上,ActiveState上有一個配方表明沒有標準模塊,除非它是非常新的。 – 2009-07-06 07:57:41

+0

是的,持續地,我已經更新了這個問題 – sharkin 2009-07-06 08:29:09

+0

Duplicate:http://stackoverflow.com/questions/263005/is-it-possible-to-change-the-environment-of-a-parent-process-in- python – 2009-07-06 12:28:14

回答

20

使用SETX有一些缺點,特別是如果你想追加到環境變量(例如PATH SETX%PATH%; C:\ mypath中)這將每次運行它的時候一再追加到路徑,它可以成爲一個問題。更糟糕的是,它不區分機器路徑(存儲在HKEY_LOCAL_MACHINE中)和用戶路徑(存儲在HKEY_CURRENT_USER中)。您在命令提示符下看到的環境變量由這兩個值的串聯組成。因此,呼籲SETX前:

user PATH == u 
machine PATH == m 
%PATH% == m;u 

> setx PATH %PATH%;new 

Calling setx sets the USER path by default, hence now: 
user PATH == m;u;new 
machine PATH == m 
%PATH% == m;m;u;new 

系統路徑不可避免地在%PATH%環境變量每次調用SETX時間追加到PATH複製。這些更改是永久性的,不會因重新啓動而重置,因此會在整個機器的使用期限內累積。

在DOS中試圖彌補這一點是超出我的能力。所以我轉向了Python。我想出了今天的解決方案,通過調整註冊表,包括附加到路徑,而不引入重複設置環境變量,如下:

from os import system, environ 
import win32con 
from win32gui import SendMessage 
from _winreg import (
    CloseKey, OpenKey, QueryValueEx, SetValueEx, 
    HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, 
    KEY_ALL_ACCESS, KEY_READ, REG_EXPAND_SZ, REG_SZ 
) 

def env_keys(user=True): 
    if user: 
     root = HKEY_CURRENT_USER 
     subkey = 'Environment' 
    else: 
     root = HKEY_LOCAL_MACHINE 
     subkey = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment' 
    return root, subkey 


def get_env(name, user=True): 
    root, subkey = env_keys(user) 
    key = OpenKey(root, subkey, 0, KEY_READ) 
    try: 
     value, _ = QueryValueEx(key, name) 
    except WindowsError: 
     return '' 
    return value 


def set_env(name, value): 
    key = OpenKey(HKEY_CURRENT_USER, 'Environment', 0, KEY_ALL_ACCESS) 
    SetValueEx(key, name, 0, REG_EXPAND_SZ, value) 
    CloseKey(key) 
    SendMessage(
     win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment') 


def remove(paths, value): 
    while value in paths: 
     paths.remove(value) 


def unique(paths): 
    unique = [] 
    for value in paths: 
     if value not in unique: 
      unique.append(value) 
    return unique 


def prepend_env(name, values): 
    for value in values: 
     paths = get_env(name).split(';') 
     remove(paths, '') 
     paths = unique(paths) 
     remove(paths, value) 
     paths.insert(0, value) 
     set_env(name, ';'.join(paths)) 


def prepend_env_pathext(values): 
    prepend_env('PathExt_User', values) 
    pathext = ';'.join([ 
     get_env('PathExt_User'), 
     get_env('PathExt', user=False) 
    ]) 
    set_env('PathExt', pathext) 



set_env('Home', '%HomeDrive%%HomePath%') 
set_env('Docs', '%HomeDrive%%HomePath%\docs') 
set_env('Prompt', '$P$_$G$S') 

prepend_env('Path', [ 
    r'%SystemDrive%\cygwin\bin', # Add cygwin binaries to path 
    r'%HomeDrive%%HomePath%\bin', # shortcuts and 'pass-through' bat files 
    r'%HomeDrive%%HomePath%\docs\bin\mswin', # copies of standalone executables 
]) 

# allow running of these filetypes without having to type the extension 
prepend_env_pathext(['.lnk', '.exe.lnk', '.py']) 

它不影響當前進程或父進程,但它會影響運行後打開的所有cmd窗口,而不需要重新啓動,並且可以安全地編輯和重新運行多次,而不會引入任何重複。

1

註冊表的方式是,如果你想永久修改它的一切,我想這是你想要的,因爲它在setup.py。

暫時只是你的過程,然後os.environ是訣竅。

1

在os模塊中,有getenv和putenv函數。然而,似乎運行putenv不能正常工作,並且必須使用Windows註冊表而不是

this discussion

4

這可能是一樣容易使用外部Windows setx命令:

C:\>set NEWVAR 
Environment variable NEWVAR not defined 

C:\>python 
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on 
win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import os 
>>> os.system('setx NEWVAR newvalue') 
0 
>>> os.getenv('NEWVAR') 
>>> ^Z 


C:\>set NEWVAR 
Environment variable NEWVAR not defined 

現在打開一個新的命令提示符:

C:\>set NEWVAR 
NEWVAR=newvalue 

正如你所看到的,既不setx套當前會話的變量,也不是父進程的變量(第一個命令提示符)。但它確實將該變量永久地設置在註冊表中以用於將來的過程。

我認爲根本沒有辦法改變父進程的環境(如果有的話,我很樂意聽到它!)。

3

我試圖通過程序來改變當前DOS會話的環境,這一定是千年前的事了。問題是:該程序在其自己的DOS shell中運行,因此它必須在其父環境中運行。它從DOS信息塊開始,沿着內存控制塊鏈遍歷,以查找該父級環境的位置。一旦我發現如何做到這一點,我對操縱環境變量的需求就消失了。我給你下面的Turbo Pascal的代碼,但我想有至少三種更好的方法來達到目的:

  1. 創建一個批處理文件:(一)調用Python腳本(或無論什麼),它會生成一個包含相應SET命令的臨時批處理文件; (b)調用臨時批處理文件(SET命令在當前shell中執行);和(c)刪除臨時批處理文件。

  2. 創建一個Python腳本,將類似「VAR1 = val1 \ nVAR2 = val2 \ nVAR3 = val3 \ n」的內容寫入標準輸出。使用這種方式在批處理文件:

    for /f "delims=|" %%X in ('callYourPythonScript') do set %%X

    等瞧:變量VAR1,VAR2和VAR3都被賦予了值。

  3. 修改Windows註冊表並按照Alexander Prokofyev所述的here所述廣播設置更改。

而且這裏去帕斯卡代碼(你可能需要一個荷蘭語字典和Pascal編程的書),只是報告的內存位置的程序。它仍然似乎在Windows XP下工作,不管它報告我們正在運行DOS 5.00。這只是第一個開始,爲了操縱選定的環境,要做很多低級編程。而作爲指針結構可能看起來是正確的,我不那麼肯定,如果1994年的環境模型仍持有這些天...

program MCBKETEN; 
uses dos, HexConv; 

{----------------------------------------------------------------------------} 
{ Programma: MCBKETEN.EXE             } 
{ Broncode : MCBKETEN.PAS             } 
{ Doel  : Tocht langs de MCB's met rapportage       } 
{ Datum : 11 januari 1994            } 
{ Auteur : Meindert Meindertsma           } 
{ Versie : 1.00               } 
{----------------------------------------------------------------------------} 

type 
    MCB_Ptr  = ^MCB; 
{ MCB_PtrPtr = ^MCB_Ptr; vervallen wegens DOS 2.11 -- zie verderop } 
    MCB   = record 
        Signatuur : char; 
        Eigenaar  : word; 
        Paragrafen : word; 
        Gereserveerd : array[1..3] of byte; 
        Naam   : array[1..8] of char; 
       end; 
    BlokPtr  = ^BlokRec; 
    BlokRec  = record 
        Vorige  : BlokPtr; 
        DitSegment, 
        Paragrafen : word; 
        Signatuur : string[6]; 
        Eigenaar, 
        Omgeving  : word; 
        Functie  : String4; 
        Oorsprong, 
        Pijl   : char; 
        KorteNaam : string[8]; 
        LangeNaam : string; 
        Volgende  : BlokPtr; 
       end; 
    PSP_Ptr  = ^PSP; 
    PSP   = record 
        Vulsel1  : array[1..44] of byte; 
        Omgeving  : word; 
        Vulsel2  : array[47..256] of byte; 
       end; 

var 
    Zone     : string[5]; 
    ProgGevonden, 
    EindeKeten, 
    Dos3punt2    : boolean; 
    Regs     : registers; 
    ActMCB    : MCB_Ptr; 
    EersteSchakel, Schakel, 
    LaatsteSchakel  : BlokPtr; 
    ActPSP    : PSP_Ptr; 
    EersteProg, 
    Meester, Ouder, 
    TerugkeerSegment, 
    TerugkeerOffset, 
    TerugkeerSegment2, 
    OuderSegment   : word; 
    Specificatie   : string[8]; 
    ReleaseNummer   : string[2]; 
    i      : byte; 


{----------------------------------------------------------------------------} 
{ PROCEDURES EN FUNCTIES             } 
{----------------------------------------------------------------------------} 

function Coda (Omgeving : word; Paragrafen : word) : string; 

var 
    i   : longint; 
    Vorige, Deze : char; 
    Streng  : string; 

begin 
    i := 0; 
    Deze := #0; 
    repeat 
     Vorige := Deze; 
     Deze := char (ptr (Omgeving, i)^); 
     inc (i); 
    until ((Vorige = #0) and (Deze = #0)) or (i div $10 >= Paragrafen); 
    if (i + 3) div $10 < Paragrafen then begin 
     Vorige := char (ptr (Omgeving, i)^); 
     inc (i); 
     Deze := char (ptr (Omgeving, i)^); 
     inc (i); 
     if (Vorige = #01) and (Deze = #0) then begin 
     Streng := ''; 
     Deze := char (ptr (Omgeving, i)^); 
     inc (i); 
     while (Deze <> #0) and (i div $10 < Paragrafen) do begin 
      Streng := Streng + Deze; 
      Deze := char (ptr (Omgeving, i)^); 
      inc (i); 
     end; 
     Coda := Streng; 
     end 
     else Coda := ''; 
    end 
    else Coda := ''; 
end {Coda}; 


{----------------------------------------------------------------------------} 
{ HOOFDPROGRAMMA               } 
{----------------------------------------------------------------------------} 

BEGIN 
    {----- Initiatie -----} 
    Zone   := 'Lower'; 
    ProgGevonden := FALSE; 
    EindeKeten  := FALSE; 
    Dos3punt2  := (dosversion >= $1403) and (dosversion <= $1D03); 
    Meester   := $0000; 
    Ouder   := $0000; 
    Specificatie[0] := #8; 
    str (hi (dosversion) : 2, ReleaseNummer); 
    if ReleaseNummer[1] = ' ' then ReleaseNummer[1] := '0'; 

    {----- Pointer naar eerste MCB ophalen ------} 
    Regs.AH := $52; { functie $52 geeft adres van DOS Info Block in ES:BX } 
    msdos (Regs); 
{ ActMCB := MCB_PtrPtr (ptr (Regs.ES, Regs.BX - 4))^; NIET onder DOS 2.11 } 
    ActMCB := ptr (word (ptr (Regs.ES, Regs.BX - 2)^), $0000); 

    {----- MCB-keten doorlopen -----} 
    new (EersteSchakel); 
    EersteSchakel^.Vorige := nil; 
    Schakel    := EersteSchakel; 
    repeat 
     with Schakel^ do begin 
     DitSegment := seg (ActMCB^); 
     Paragrafen := ActMCB^.Paragrafen; 
     if DitSegment + Paragrafen >= $A000 then 
      Zone := 'Upper'; 
     Signatuur := Zone + ActMCB^.Signatuur; 
     Eigenaar := ActMCB^.Eigenaar; 
     ActPSP  := ptr (Eigenaar, 0); 
     if not ProgGevonden then EersteProg := DitSegment + 1; 
     if Eigenaar >= EersteProg 
      then Omgeving := ActPSP^.Omgeving 
      else Omgeving := 0; 
     if DitSegment + 1 = Eigenaar then begin 
      ProgGevonden := TRUE; 
      Functie  := 'Prog'; 
      KorteNaam[0] := #0; 
      while (ActMCB^.Naam[ ord (KorteNaam[0]) + 1 ] <> #0) and 
        (KorteNaam[0] < #8) do 
      begin 
       inc (KorteNaam[0]); 
       KorteNaam[ ord (KorteNaam[0]) ] := 
        ActMCB^.Naam[ ord (KorteNaam[0]) ]; 
      end; 
      if Eigenaar = prefixseg then begin 
       TerugkeerSegment := word (ptr (prefixseg, $000C)^); 
       TerugkeerOffset := word (ptr (prefixseg, $000A)^); 
       LangeNaam  := '-----> Terminate Vector = '  + 
            WordHex (TerugkeerSegment) + ':' + 
            WordHex (TerugkeerOffset)  ; 
      end 
      else 
       LangeNaam := ''; 
     end {if ÆProgØ} 
     else begin 
      if Eigenaar = $0008 then begin 
       if ActMCB^.Naam[1] = 'S' then 
        case ActMCB^.Naam[2] of 
        'D' : Functie := 'SysD'; 
        'C' : Functie := 'SysP'; 
        else Functie := 'Data'; 
        end {case} 
       else  Functie := 'Data'; 
       KorteNaam := ''; 
       LangeNaam := ''; 
      end {if Eigenaar = $0008} 
      else begin 
       if DitSegment + 1 = Omgeving then begin 
        Functie := 'Env '; 
        LangeNaam := Coda (Omgeving, Paragrafen); 
        if EersteProg = Eigenaar then Meester := Omgeving; 
       end {if ÆEnvØ} 
       else begin 
        move (ptr (DitSegment + 1, 0)^, Specificatie[1], 8); 
        if (Specificatie = 'PATH=' + #0 + 'CO') or 
        (Specificatie = 'COMSPEC='  ) or 
        (Specificatie = 'OS=DRDOS'  ) then 
        begin 
        Functie := 'Env' + chr (39); 
        LangeNaam := Coda (DitSegment + 1, Paragrafen); 
        if (EersteProg = Eigenaar) and 
         (Meester = $0000 ) 
        then 
         Meester := DitSegment + 1; 
        end 
        else begin 
        if Eigenaar = 0 
         then Functie := 'Free' 
         else Functie := 'Data'; 
        LangeNaam := ''; 
        if (EersteProg = Eigenaar) and 
         (Meester = $0000 ) 
        then 
         Meester := DitSegment + 1; 
        end; 
       end {else: not ÆEnvØ}; 
       KorteNaam := ''; 
      end {else: Eigenaar <> $0008}; 
     end {else: not ÆProgØ}; 

     {----- KorteNaam redigeren -----} 
     for i := 1 to length (KorteNaam) do 
      if KorteNaam[i] < #32 then KorteNaam[i] := '.'; 
     KorteNaam := KorteNaam + '  '; 

     {----- Oorsprong vaststellen -----} 
     if EersteProg = Eigenaar 
      then Oorsprong := '*' 
      else Oorsprong := ' '; 

     {----- Actueel proces (uitgaande Pijl) vaststellen -----} 
     if Eigenaar = prefixseg 
      then Pijl := '>' 
      else Pijl := ' '; 
     end {with Schakel^}; 

    {----- MCB-opeenvolging onderzoeken/schakelverloop vaststellen -----} 
     if (Zone = 'Upper') and (ActMCB^.Signatuur = 'Z') then begin 
     Schakel^.Volgende := nil; 
     EindeKeten  := TRUE; 
     end 
     else begin 
     ActMCB := ptr (seg (ActMCB^) + ActMCB^.Paragrafen + 1, 0); 
     if ((ActMCB^.Signatuur <> 'M') and (ActMCB^.Signatuur <> 'Z')) or 
      ($FFFF - ActMCB^.Paragrafen < seg (ActMCB^)    ) 
     then begin 
      Schakel^.Volgende := nil; 
      EindeKeten  := TRUE; 
     end 
     else begin 
      new (LaatsteSchakel); 
      Schakel^.Volgende  := LaatsteSchakel; 
      LaatsteSchakel^.Vorige := Schakel; 
      Schakel    := LaatsteSchakel; 
     end {else: (ÆMØ or ÆZØ) and Æteveel_ParagrafenØ}; 
     end {else: ÆLowerØ or not ÆZØ}; 
    until EindeKeten; 

    {----- Terugtocht -----} 
    while Schakel <> nil do with Schakel^ do begin 

    {----- Ouder-proces vaststellen -----} 
     TerugkeerSegment2 := TerugkeerSegment + (TerugkeerOffset div $10); 
     if (DitSegment    <= TerugkeerSegment2) and 
     (DitSegment + Paragrafen >= TerugkeerSegment2) 
     then 
     OuderSegment := Eigenaar; 

    {----- Meester-omgeving markeren -----} 
     if DitSegment + 1 = Meester then Oorsprong := 'M'; 

    {----- Schakel-verloop -----} 
     Schakel := Schakel^.Vorige; 
    end {while Schakel <> nil}; 

    {----- Rapportage -----} 
    writeln ('Chain of Memory Control Blocks in DOS version ', 
      lo (dosversion), '.', ReleaseNummer, ':'); 
    writeln; 
    writeln ('[email protected] #Par Signat [email protected] [email protected] Type !! Name  File'); 
    writeln ('---- ---- ------ ---- ---- ---- -- -------- ', 
      '-----------------------------------'); 
    Schakel := EersteSchakel; 
    while Schakel <> nil do with Schakel^ do begin 

    {----- Ouder-omgeving vaststellen -----} 
     if Eigenaar = OuderSegment then begin 
     if not Dos3punt2 then begin 
      if (Functie = 'Env ') then begin 
       Ouder := DitSegment + 1; 
       Pijl := 'Û'; 
      end 
      else 
       Pijl := '<'; 
     end {if not Dos3punt2} 
     else begin 
      if ((Functie = 'Env' + chr (39)) or (Functie = 'Data')) and 
       (Ouder = $0000) 
      then begin 
       Ouder := DitSegment + 1; 
       Pijl := 'Û'; 
      end 
      else 
       Pijl := '<'; 
     end {else: Dos3punt2}; 
     end {with Schakel^}; 

    {----- Keten-weergave -----} 
     writeln (WordHex (DitSegment)  , ' ', 
       WordHex (Paragrafen)  , ' ', 
       Signatuur     , ' ', 
       WordHex (Eigenaar)   , ' ', 
       WordHex (Omgeving)   , ' ', 
       Functie      , ' ', 
       Oorsprong, Pijl    , ' ', 
       KorteNaam     , ' ', 
       LangeNaam      ); 

    {----- Schakel-verloop -----} 
     Schakel := Schakel^.Volgende; 
    end {while Schakel <> nil}; 

    {----- Afsluiting rapportage -----} 
    writeln; 

    write ('* = First command interpreter at '); 
    if ProgGevonden 
     then writeln (WordHex (EersteProg), ':0000') 
     else writeln ('?'); 

    write ('M = Master environment  at '); 
    if Meester > $0000 
     then writeln (WordHex (Meester), ':0000') 
     else writeln ('?'); 

    write ('< = Parent proces    at '); 
    writeln (WordHex (OuderSegment), ':0000'); 

    write ('Û = Parent environment  at '); 
    if Ouder > $0000 
     then writeln (WordHex (Ouder), ':0000') 
     else writeln ('?'); 

    writeln ('> = Current proces   at ', 
      WordHex (prefixseg), ':0000'); 

    writeln (' returns     to ', 
      WordHex (TerugkeerSegment), ':', WordHex (TerugkeerOffset)); 
END. 

(以上ASCII 127,有可能在一些ASCII/ANSI翻譯問題。此演示文稿)

1

這Python的腳本[*]試圖修改註冊表中的GLOBAL ENV-瓦爾,如果沒有權限下降,回到用戶的註冊表,並通知有關更改的所有窗口:

""" 
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 show_all(tree, path, key): 
    i = 0 
    while True: 
     try: 
      n,v,t = winreg.EnumValue(key, i) 
      print(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))) 

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: 
         show_all(tree_name, path, key) 
        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)) 
     except FileNotFoundError as ex: 
      print("!!!Cannot find %s due to: %s" % 
        (reg_key(tree_name, path, varname), ex)) 

if __name__=='__main__': 
    args = sys.argv 
    argc = len(args) 
    if argc > 3: 
     print(__doc__.format(prog=args[0])) 
     sys.exit() 

    manage_registry_env_vars(*args[1:]) 

下面是一些使用示例,假設它已被保存n當前路徑中的某個文件名爲setenv.py。 注意,在這些例子我沒有管理員權限,這樣的變化隻影響到我的本地用戶的註冊表樹:

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