2009-07-06 8 views
16

Jak mogę trwale modyfikować zmienne środowiskowe systemu Windows ze skryptu Python? (to skrypt setup.py)Interfejs do modyfikowania zmiennych środowiskowych systemu Windows z Python

Szukam standardowej funkcji lub modułu do użycia w tym celu. Jestem już zaznajomiony z registry way of doing it, ale wszelkie uwagi dotyczące tego są również mile widziane.

+0

Czy oznacza trwałe środowisko zmienne (jak komenda 'setx') lub zmiana jednego dla bieżącego procesu (jak polecenie 'set')? Fakt, że * istnieje * przepis na ActiveState sugeruje, że nie ma dla niego standardowego modułu, chyba że jest to całkiem nowy, jak sądzę. –

+0

Tak, uporczywie, zaktualizowałem pytanie: – sharkin

+0

Duplikat: http://stackoverflow.com/questions/263005/is-it-possible-to-change-the-environment-of-a-parent-process-in- python –

Odpowiedz

20

Używanie setx ma kilka wad, szczególnie jeśli próbujesz dołączyć do zmiennych środowiskowych (np. Setx PATH% Path%; C: \ mypath) To będzie wielokrotnie dołączane do ścieżki przy każdym uruchomieniu, co może być problemem. Co gorsza, nie rozróżnia ścieżki maszyny (przechowywanej w HKEY_LOCAL_MACHINE) i ścieżki użytkownika (przechowywanej w HKEY_CURRENT_USER). Zmienna środowiskowa widoczna w wierszu polecenia składa się z połączenia tych dwóch wartości. Dlatego też, przed wywołaniem 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 

Ścieżka system jest nieunikniony powielane w zmiennej środowiskowej% PATH% przy każdym wywołaniu setx do dołączania do PATH. Zmiany te są trwałe, nigdy nie są resetowane przez ponowne uruchomienie komputera, a więc akumulują się przez cały okres eksploatacji urządzenia.

Próba skompensowania tego w DOS jest poza moimi możliwościami. Więc zwróciłem się do Pythona. Rozwiązanie Mam wymyślić dzisiaj, aby ustawić zmienne środowiskowe przez modyfikację rejestru, w tym dodanie do PATH bez wprowadzania duplikatów, jest następująca:

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']) 

To nie ma wpływu na bieżący proces lub powłoki nadrzędnej, ale wpłynie to na wszystkie okna cmd otwarte po uruchomieniu, bez konieczności ponownego uruchamiania i może być bezpiecznie edytowane i ponownie uruchamiane wiele razy bez wprowadzania żadnych duplikatów.

+2

'setx' domyślnie ustawia HKCU, ale możesz' setx/M' ustawić HKLM. – cod3monk3y

+3

właśnie odkrył ... setx ma [ograniczenie 1024 znaków] (http://superuser.com/questions/387619/overcoming-the-1024-character-limit-with-setx) – cod3monk3y

1

Sposób rejestrowania polega na tym, że chcesz go trwale zmodyfikować na wszystko, co, jak sądzę, jest tutaj, ponieważ jest w setup.py.

Tymczasowo dla twojego procesu, to os.environ jest lewą.

1

W module os występują funkcje getenv i putenv. Wydaje się jednak, że putenv nie działa prawidłowo i że trzeba użyć rejestru systemu Windows zamiast

Spójrz na this discussion

4

To może być tak proste w użyciu zewnętrznego systemu Windows setx polecenie:

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 

teraz otworzyć nowe polecenie:

C:\>set NEWVAR 
NEWVAR=newvalue 

Jak widać, setx ani zestawów zmienna dla bieżącej sesji, ani dla procesu nadrzędnego (pierwszy wiersz polecenia). Ale ustawia stałą w rejestrze dla przyszłych procesów.

Nie sądzę, że istnieje sposób na zmianę środowiska procesu nadrzędnego (a jeśli tak, to chciałbym to usłyszeć!).

+1

Kiedyś stworzyłem upiorny hack, aby zmodyfikować środowisko procesu wywołującego w systemie Windows, ale wymaga to współdziałania z procesem wywoływania: wywoływany skrypt napisał plik .bat na dysk, a proces wywołujący następnie 'exec's it lub somesuch . http://tartley.com/?p=966 –

+0

Yuk! Czy mogę zgodzić się z moim własnym komentarzem? –

3

To musiało być tysiąc lat temu, że próbowałem zmienić środowisko obecnej sesji DOS za pomocą programu. Problem polega na tym, że program działa w ramach własnej powłoki DOS, więc musi działać w środowisku macierzystym. Trwa spacer, zaczynając od bloku informacyjnego DOS, w całym łańcuchu bloków sterowania pamięcią, aby znaleźć lokalizację tego środowiska macierzystego.Kiedy już dowiedziałem się, jak to zrobić, zniknęła moja potrzeba manipulowania zmiennymi środowiskowymi. Dam ci kod Turbo Pascal poniżej, ale myślę, że istnieją co najmniej trzy sposoby, aby lepiej zrobić lewy:

  1. utworzyć plik wsadowy: (a) wywołuje skrypt Pythona (lub cokolwiek), który generuje tymczasowy plik wsadowy zawierający odpowiednie polecenia SET; (b) wywołuje tymczasowy plik wsadowy (polecenia SET wykonywane są w bieżącej powłoce); i (c) usuwa tymczasowy plik wsadowy.

  2. Utwórz skrypt w języku Python, który zapisuje coś w stylu "VAR1 = val1 \ nVAR2 = val2 \ nVAR3 = val3 \ n" do STDOUT. Używaj go w ten sposób w pliku wsadowym:

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

    et voilà: zmienne VAR1, VAR2 i VAR3 nadano wartość.

  3. Zmodyfikuj rejestr systemu Windows i nadaj zmianę ustawień zgodnie z opisem here Alexander Prokofyev.

I tutaj jest kod Pascala (może być potrzebny słownik holenderski i książka programowania Pascala) programu, który po prostu raportuje lokalizacje pamięci. Nadal wydaje się działać pod Windows XP, czy to raportowanie, czy pracujemy na DOSie 5.00. To dopiero początek, istnieje wiele programów o niskim poziomie działania, aby manipulować wybranym środowiskiem. I jako struktura wskaźnik może wydawać się poprawne, nie jestem pewien, czy model Środowisko 1994 nadal posiada te dni ...

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. 

(Above ASCII 127, mogą być pewne problemy ASCII/ANSI tłumaczenie w . ta prezentacja)

1

Ten Pythona skrypt [*] próbuje modyfikować globalnej eNV-vars w rejestrze, jeśli nie-uprawnienia spada-back do rejestru użytkownika, a następnie powiadamia wszystkie okna o zmianie:

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

Poniżej kilka przykładów użycia, zakładając, że został zapisany n plik o nazwie setenv.py gdzieś w aktualnej ścieżce. Należy zauważyć, że w tych przykładach i nie miał admin-prawa, więc zmiany dotknęły tylko drzewa rejestru mojego lokalnego użytkownika:

> 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 

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