Windows Environment Path

This is a little script that allows you to edit the Microsoft Windows environment path.

I HATE the built-in Windows method of editing the path, so I whipped up this script to make it easy.

I have ONLY tested this under Microsoft Windows XP.

PSW

(escargo - It would be useful to know which version of XP; it could Home or Pro, and it could be the original or service packs 1 or 2.)

PSW Work for me on both Home and Pro - Service Pack 2. In both cases I have full admin rights.


 #
 #
 #   Simple editor for fixing paths on Windows
 #
 package require Tk
 package require tile
 package require registry 

 ##############################################################################

 namespace eval ::pathedit {
    variable list
    variable pathlist
 }

 proc ::pathedit::updateList { } {
    variable list
    variable pathlist

    $list delete 0 end
    foreach path $pathlist {
       $list insert end $path
    }
 }

 proc ::pathedit::read { } {
    variable list
    variable pathlist

    puts "pathedit::read"
    set regPath {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment}
    set curPath [registry get $regPath "Path"]
    set pathlist [ split $curPath ";" ]
    ::pathedit::updateList
 }

 proc ::pathedit::save {  } {
    variable pathlist
  
    puts "::pathedit::save"
    set newPath ""
    foreach path $pathlist {
      append newPath "$path;"
   }
   puts $newPath
   set regPath {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment}
   registry set $regPath "Path" "$newPath"
   registry broadcast "Environment"
 }

 proc ::pathedit::moveup { } {
    variable list
    variable pathlist

    set selIndex [ $list curselection ]
    if { ( [ string length $selIndex ] > 0 ) &&
         ( $selIndex > 0 ) } {
       set swapIndex [ expr { $selIndex - 1 } ]
       set select  [ lindex $pathlist $selIndex ]
       set swap [ lindex $pathlist $swapIndex ]
       lset pathlist $swapIndex $select
       lset pathlist $selIndex $swap
       ::pathedit::updateList
       $list selection set $swapIndex
       $list see $swapIndex
    }
 }

 proc ::pathedit::movedown { } {
    variable list
    variable pathlist
    set selIndex [ $list curselection ]
    set lastIndex [ $list index end ]
    if { ( [ string length $selIndex ] > 0 ) &&
         ( $selIndex < ( $lastIndex -  1)  ) } {
       set swapIndex [ expr { $selIndex + 1 } ]
       set select  [ lindex $pathlist $selIndex ]
       set swap [ lindex $pathlist $swapIndex ]
       lset pathlist $swapIndex $select
       lset pathlist $selIndex $swap
       ::pathedit::updateList
       $list selection set $swapIndex
       $list see $swapIndex
    } 
 }

 proc ::pathedit::add { }  {
    variable pathlist
    variable list
   
    set file [ tk_chooseDirectory -mustexist true  ]
    if { $file ne "" } {
       set selIndex [ $list curselection ]
       if { $selIndex eq "" } {
          set selIndex 0
       }
       set pathlist [ linsert $pathlist $selIndex [ file native $file ] ]
       ::pathedit::updateList
    }
 }

 proc ::pathedit::remove { } {
    variable pathlist
    variable list
    set selIndex [ $list curselection ]
    if { $selIndex ne "" } {
       set pathlist [ lreplace $pathlist $selIndex $selIndex ]
       ::pathedit::updateList
    }
 }

 proc ::pathedit::makeGui { } {
    variable list
    frame .f
    frame .b
    frame .r
    ttk::button .b.exit -text "Exit" -command exit
    ttk::button .b.read -text "Re-read" -command ::pathedit::read
    ttk::button .b.save -text "Save"    -command ::pathedit::save
    ttk::button .r.up -text "Move Up"      -command ::pathedit::moveup
    ttk::button .r.down -text "Move Down"  -command ::pathedit::movedown
    ttk::button .r.add -text "Add path"    -command ::pathedit::add
    ttk::button .r.remove -text "Remove Path" -command ::pathedit::remove
    set list [ listbox .f.list -yscrollcommand { .f.scroll set } ]
    ttk::scrollbar .f.scroll -command { .f.list yview }
    pack .r -side right -fill y
    pack .b -side bottom -fill x
    pack .f -side left -fill both -expand true
    pack .f.list -side left -fill both -expand true
    pack .f.scroll -side right -fill y
    pack .b.save .b.read .b.exit -side left
    pack .r.up .r.down  .r.add .r.remove -side top
 }

 # For Debugging 
 bind . <Alt-c> { console show }
 
 ######################################################3
 pathedit::makeGui
 pathedit::read

MEd 2006/03/01: A nice script, but unfortunately I get an error dialog when I try to save: "unable to open key: access is denied" (Win XP, Service Pack 1). I guess this is because you try change the system variable "path" and I do not have administrator rights. Actually there are two path variables on the system, one user variable and one system variable, as normal user I'm only allowed to change the user variable. The real path (when you type "echo %PATH%" on cmd.exe) consists of user variable + system variable. By the way: the "user variable" can also be found in the registry:

 HKEY_CURRENT_USER\Environment\path

MG adds, on a side note, that the "built-in" way to edit the path (and other environment variables) on his Win XP SP2 machine seems to be to right-click on "My Computer" -> Properties -> Advanced -> Environment Variables. Strangely, running

  parray env

from the wish console lists many vars for me which don't appear in that Windows list...

MEd I guess thats the point I mentioned above (that there are two path variables, one in the system and one in the user "variable space"


AEC The values seen by

 parray env

are also visible by executing

 set

at the prompt in the window's command shell.


PSW The whole point for me is to be able to MOVE things so I can force the programs I want higher in the path. I just played around with the script and changed the path's to point to the "user" path, the script still seems to work the same. But perhaps that will fix other peoples permission issues.


Here is a little utility to clean up the Windows PATH: remove non-existing directories, trailing backslashes, duplicates. It only returns the cleaned string, and it is up to the caller to actually set it. RS 2012-08-17

 proc clean_path {} {
   set res {}
   foreach part [split $::env(PATH) ";"] {
      set part [string trimright $part \\]
      if ![file exists $part] continue
      if {[lsearch -exact $res $part] >= 0} continue
      lappend res $part
   }
   join $res ";"
 }