1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

PSUBST - Persistent SUBST Command

Discussion in 'T&T - Scripting' started by samintz, Jan 21, 2015.

  1. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    Code:
    @echo off
    setlocal
    set regkey=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices
    set fPersist=0
    set fDel=0
    set drive1=
    set drive2=
    
    do i=1 to %#
        switch "%[%i]"
        case "/p"
         set fPersist=1
        case "/d"
         set fDel=1
        case "/?" .or. "/h"
         goto :usage
        default
         iff "%drive1" == "" then
           set drive1=%[%i]
         elseiff "%drive2" == "" then
           set drive2=%[%i]
         else
           goto :usage
        endswitch
    enddo
    
    iff %fPersist == 1 .and. %fDel == 1 then
        goto :usage
    endiff
    iff "%drive2" != "" .and. %fDel == 1 then
        goto :usage
    endiff
    iff    "%drive1" == "" .and. (%fDel==1 .or. %fPersist==1) then
        goto :usage
    endiff
    
    rem Make an existing virtual drive persistent
    iff "%drive1" != "" .and. "%drive2" == "" .and. %fPersist==1 then
        do d in /p subst
          setdos /x-6
         set drv=%@left[2,%d]
         set vpath=\??\%@trim[%@word[">",1,%d]]
         setdos /x+6
         iff %drv == %drive1 then
           echo Making %drv persistent
            set r=%@regset["%regkey\%drv",REG_SZ,%vpath]
            goto :display
         endiff
        enddo
        echo Error %drive1 is not a SUBST'ed drive.
        quit
    endiff
    
    rem Remove an existing drive
    iff "%drive1" != "" .and. "%drive2" == "" .and. %fDel==1 then
        do d in /p subst
          setdos /x-6
         set drv=%@left[2,%d]
         setdos /x+6
         iff %drv == %drive1 then
           echo Removing %drv
            set r=%@regset["%regkey\%drv",REG_SZ,]
            subst %drv /d
            goto :display
         endiff
        enddo
        echo Error %drive1 is not a SUBST'ed drive.
        quit
    endiff
    
    rem Create a substituted drive
    iff "%drive2" != "" then
        rem first try to run SUBST
        subst %drive1 %drive2
        iff %? != 0 then
         quit
        endiff
        iff %fPersist==1 then
            set r=%@regset["%regkey\%drive1",REG_SZ,\??\%@unquote[%drive2]]
        endiff
    endiff
    
    rem Default to display mappings
    :display
        do d in /p subst
          setdos /x-6
         iff %@regquery["%regkey\%@left[2,%d]"] != -1 then
            echos [*] ``
         else
           echos [ ] ``
         endiff
         echo %d
          setdos /x+6
        enddo
        echo ^nItems marked with [*] are persistent
        quit
           
    :usage
    text
    PSUBST v1.0 Associates a path with a drive letter.
    Manages persistent substituted (virtual) drives.
       
    PSUBST [drive1: [drive2:]path] [/P]
    PSUBST drive1: /D | /P
       
        drive1:        Specifies a virtual drive to which you want to assign a path.
        [drive2:]path  Specifies a physical drive and path you want to assign to
                       a virtual drive (no trailing backslash).
        /D             Deletes a substituted (virtual) drive.
        /P             Make a substituted drive persistent
       
    Type PSUBST with no parameters to display a list of current virtual drives.
    endtext
    quit
    
     
  2. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,970
    Likes Received:
    30
    Scott, the first example I found with Google (didn't try it) looks like this
    Code:
    "Z:"="\\??\\C:\\Documents and Settings\\All Users\\Shared Documents"
    Your code uses only single backslashes. So, what's correct here?
     
  3. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,970
    Likes Received:
    30
    You had it right, Scott. I was looking at a .REG script and when a .REG is imported, "\\" is changed to "\".

    Did you know 0-9 can be used as drive names? They don't show up in the SUBST command, but they work.
    Code:
    v:\> subst 4: g:\tc17
    
    v:\> subst
    P:\: => L:\projects
    S:\: => C:\Windows\system32
    T:\: => H:\temp
    U:\: => G:\uty
    V:\: => H:\workplace
    W:\: => C:\Windows
    
    v:\> echo %@truename[4:]
    G:\tc17\
    
    v:\> 4:\
    
    4:\> dir /k /m tcc*
    2015-01-19  10:39  175,512  tcc.exe
    2013-01-09  12:05  1,002  tccbatch.btm
    2013-04-03  08:10  1,170  tcchere.btm
    2014-11-26  17:02  1,281  TCCHereEx.btm
    2014-10-25  22:09  2,353  tcconly.ini
    2013-01-09  12:07  1,273  tcctabhere.btm
     
  4. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    That's kind of nifty. Any idea what API SUBST uses? It's too bad it doesn't display those mappings.
     
  5. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,970
    Likes Received:
    30
    DefineDosDevice() would be my first guess.
     
  6. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    It looks like SUBST uses QueryDosDeviceW() and DefineDosDeviceW().

    I tried to experiment with @WINAPI to call QueryDosDeviceW but it only echos a single drive letter.
    Code:
    echo %@winapi[kernel32.dll,QueryDosDeviceW,0,BUFFER,16384]
    P:
    
    How do you get the full contents of the buffer?
     
  7. Charles Dye

    Charles Dye Super Moderator
    Staff Member

    Joined:
    May 20, 2008
    Messages:
    3,311
    Likes Received:
    39
    I guess you write a plugin.... It might be handy if @WINAPI and @CAPI could interface with binary buffers allocated by @BALLOC, but I suspect that would be a major-update type feature to add.
     
  8. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    This looks promising:
    Code:
    do d in /c ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 (echo %d:  %@winapi[kernel32.dll,QueryDosDeviceW,"%d:",BUFFER,16384])|ffind /vkm /t"\??\"
    
     
  9. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    Here is a SUBST-less version that uses the native Win32 API's to define, query, and remove DOS drive mappings.
    Code:
    @echo off
    setlocal
    set regkey=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices
    set fPersist=0
    set fDel=0
    set drive1=
    set drive2=
    function DefineDosDevice=`%@winapi[kernel32.dll,DefineDosDeviceW,1,"%1","%2"]`
    function RemoveDosDevice=`%@winapi[kernel32.dll,DefineDosDeviceW,2,"%1",0]`
    function QueryDosDevice=`%@winapi[kernel32.dll,QueryDosDeviceW,"%1",BUFFER,1024]`
    
    do i=1 to %#
        switch "%[%i]"
        case "/p"
         set fPersist=1
        case "/d"
         set fDel=1
        case "/?" .or. "/h"
         goto :usage
        default
         iff "%drive1" == "" then
           set drive1=%[%i]
         elseiff "%drive2" == "" then
           set drive2=%[%i]
         else
           echo Invalid parameter - %[%i]^n
           goto :usage
        endswitch
    enddo
    
    iff %fPersist == 1 .and. %fDel == 1 then
        echo Invalid parameter - cannot specify both /P and /D^n
        goto :usage
    elseiff "%drive2" != "" .and. %fDel == 1 then
        echo Invalid parameter - /D^n
        goto :usage
    elseiff    "%drive1" == "" .and. (%fDel == 1 .or. %fPersist == 1) then
        echo Syntax error - missing drive1:^n
        goto :usage
    elseiff    "%drive1" != "" .and. "%drive2" == "" .and. %fDel == 0 .and. %fPersist == 0 then
        echo Syntax error - missing option or [drive2:]path^n
        goto :usage
    endiff
    
    rem Make an existing virtual drive persistent
    iff "%drive2" == "" .and. %fPersist==1 then
        set d=%@QueryDosDevice[%drive1]
        iff %@index["%d",\??\] != -1 then
            set drv=%drive1
            set vpath=%d
            echo Making %drv persistent
            set r=%@regset["%regkey\%drv",REG_SZ,%vpath]
            goto :display
        endiff
        echo Error %drive1 is not a PSUBST'ed drive.
        quit
    endiff
    
    rem Remove an existing drive
    iff %fDel==1 then
        set d=%@QueryDosDevice[%drive1]
        iff %@index["%d",\??\] != -1 then
            echo Removing %drive1
            set r=%@regset["%regkey\%drive1",REG_SZ,]
            set r=%@RemoveDosDevice[%drive1]
            goto :display
        endiff
        echo Error %drive1 is not a PSUBST'ed drive.
        quit
    endiff
    
    rem Create a substituted drive
    iff "%drive2" != "" then
        rem make sure it is not already mapped
        set d=%@QueryDosDevice[%drive1]
        iff %@index["%d",\??\] != -1 then
         echo Drive %drive1 is already PSUBSTed
         quit
        endiff
        iff %@DefineDosDevice[%drive1,\??\%@unquote[%drive2]] != 1 then
         echo.
         goto :usage
        endiff
        iff %fPersist==1 then
            set r=%@regset["%regkey\%drive1",REG_SZ,\??\%@unquote[%drive2]]
        endiff
    endiff
    
    rem Default to display mappings
    :display
        do l in /c ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 
         set d=%@QueryDosDevice[%l:]
         if %@index["%d",\??\] == -1 ITERATE
         iff %@regquery["%regkey\%l:"] != -1 then
            echos [*] ``
         else
           echos [ ] ``
         endiff
         echo %l:  %@right[-4,%d]
        enddo
        echo ^nItems marked with [*] are persistent
        quit
           
    :usage
    text
    PSUBST v1.0 Associates a path with a drive letter.
    Manages persistent substituted (virtual) drives.
       
    PSUBST [drive1: [drive2:]path [/P]]
    PSUBST drive1: /D | /P
       
        drive1:        Specifies a virtual drive to which you want to assign a path.
        [drive2:]path  Specifies a physical drive and path you want to assign to
                       a virtual drive (no trailing backslash).
        /D             Deletes a substituted (virtual) drive.
        /P             Make a substituted drive persistent
       
    Type PSUBST with no parameters to display a list of current virtual drives.
    endtext
    quit
    
     

    Attached Files:

  10. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,970
    Likes Received:
    30
    I imagine that's exactly what SUBST.EXE does, but, since 0-9 are not documented as allowable, it omits them. I wonder if any other single characters work. ... Yes indeed, I just tried "-:" as a drive letter with SUBST.EXE and it worked! "~:" works too ... could be a good one for one's profile directory.
     
  11. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,191
    Likes Received:
    11
    The downside to the non-letter mappings is Explorer doesn't know what to do with them.
     

Share This Page