PSUBST - Persistent SUBST Command

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

samintz

Scott Mintz
May 20, 2008
1,228
11
Solon, OH, USA
#1
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
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
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
 

samintz

Scott Mintz
May 20, 2008
1,228
11
Solon, OH, USA
#6
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?
 

samintz

Scott Mintz
May 20, 2008
1,228
11
Solon, OH, USA
#8
This looks promising:
Code:
do d in /c ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 (echo %d:  %@winapi[kernel32.dll,QueryDosDeviceW,"%d:",BUFFER,16384])|ffind /vkm /t"\??\"
 

samintz

Scott Mintz
May 20, 2008
1,228
11
Solon, OH, USA
#9
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
 

Attachments

#10
This looks promising:
Code:
do d in /c ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 (echo %d:  %@winapi[kernel32.dll,QueryDosDeviceW,"%d:",BUFFER,16384])|ffind /vkm /t"\??\"
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.