Skip to content

Commit

Permalink
rework script; enable privileges elevation
Browse files Browse the repository at this point in the history
  • Loading branch information
ildar-shaimordanov committed Mar 4, 2020
1 parent 7426d9b commit 277f04c
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 96 deletions.
5 changes: 4 additions & 1 deletion History.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### History ###

2020/03/04 - Version 3.0.0 Beta
Enable privileges elevation with the `/PF` option

2015/12/05 - Version 2.6.2 Stable.
Fixed [Issue 11]: Version inofrmation of psubst.bat

Expand Down Expand Up @@ -30,4 +33,4 @@ The problem of quoted arguments in the `IF "%*" == ""` construction was fixed.
2008/08/31 - Version 1.1.
Minor changes (the more accurate init of vars, unified names of vars).

2008/08/30 - The first release.
2008/08/30 - The first release.
35 changes: 20 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Since oldest times in Windows there is admirable feature to map some path with n
subst Z: "C:\Documents and Settings\All Users\Shared Documents"
```

So to reach targets in this folder it does not need to type the full path or go over a tree of folders in the Explorer window. To select the `Z:` drive is enough.
So to reach targets in this folder it does not need to type the full path or go over a tree of folders in the Explorer window. To select the `Z:` drive is enough.

## Do we need it? ##

Expand Down Expand Up @@ -135,43 +135,48 @@ psubst

### Extended ###

Typing the `/P` argument you run the script with the extended features to work with persistent virtual disks.
Typing the `/P` or `/PF` argument you run the tool with the extended features to work with persistent virtual disks:

Create a persistent virtual drive with saving in the registry:
* `/P` stands for creating, deleting or displaying persistent drives;
* `/PF` stands for creating and deleting persistent drives using elevated privileges; it can be useful for managing persistent drives by non-administrative users.

Print all virtual persistent drives (read from the registry)

```
psubst drive1: drive2:path /P
psubst /P
```

Create a virtual drive reading about it from the registry:
Restore a virtual drive from the persistent drive, if any:

```
psubst drive1: /P
psubst drive1: /P
```

Delete a drive and wipe out a record from the registry:
In the following commands the option `/P` can be replaced with the option `/PF` to elevate privileges.

Create the persistent virtual drive with saving its persistency in the registry:

```
psubst drive1: /D /P
psubst drive1: drive2:path /P
```

Print all virtual persistent drives (read from the registry)
Delete the persistent drive from the registry:

```
psubst /P
psubst drive1: /D /P
```

### Additional features ###

Great advantage of the script is independency of existence or lack of the trailing backslashes. It means that incorrect examples described earlier in this article will work always – incorrect input arguments will be transformed to the required format and the command will execute substitution successfully. Nevertheless the standard command works with the slashes in a path correctly, the script transforms these to backslashes usual in Windows.
Great advantage of the tool is independency of existence or lack of the trailing backslashes. It means that incorrect examples described earlier in this article will work always – incorrect input arguments will be transformed to the required format and the command will execute substitution successfully. Nevertheless the standard command works with the slashes in a path correctly, the script transforms these to backslashes usual in Windows.

### New shortcomings ###

Are there owned shortcomings? Exactly! There are:
Are there own shortcomings? Yes, a bit of them! There are:

* this is batch script and it works slower than binary analog;
* there is probability to run script twice with different arguments and disturb results of both;
* there is probability to break a script execution when disk have been created but the registry is not updated. But there are so little things.
* this is batch script and it works a bit slower than binary analog;
* there is quite weak probability to run the script twice with different arguments and disturb results of both;
* there is weak probability to break the script execution when disk is already created but the registry is not updated yet. To be honest, it's not lack of this script because managing the drives and updating the registry are two separate independednt actions.

## How to install? ##

Expand Down
223 changes: 143 additions & 80 deletions psubst.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@
::Associates a path with a drive letter.
::Manages persistently substituted (virtual) drives.
::
::PSUBST [drive1: [drive2:]path] [/P]
::PSUBST drive1: /D [/P]
::PSUBST [drive1: [drive2:]path] [/P | /PF]
::PSUBST drive1: /D [/P | /PF]
::PSUBST drive1: /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.
:: /D Deletes substituted (virtual) drive.
:: /P Manages persistent drives (create, delete, display).
:: /D Deletes a substituted (virtual) drive.
:: /P Add, delete or display persistent drives.
:: /PF Add or delete persistent drives with elevated privileges.
::
::Type PSUBST with no parameters to display a list of current virtual drives.
::Type PSUBST /P to display a list of persistent virtual drives.
::Type PSUBST drive1: /P to restore a virtual drive from persistency.
@echo off


if /i "%~1" == "/?" goto :print_usage
if "%~1" == "/?" goto :print_usage


if "%~1" == "" (
Expand All @@ -30,128 +34,187 @@ if "%~1" == "" (
)


if /i "%~1" == "/p" (
if /i "%~1" == "/P" (
rem
rem SUBST /P
rem

setlocal enabledelayedexpansion
setlocal enableextensions

call :init
setlocal

call :print_persist
call :psubst_init

call :cleanup
call :psubst_print

endlocal
goto :EOF
)


setlocal enabledelayedexpansion
setlocal enableextensions
setlocal

call :init
call :psubst_init

call :init_disk "%~1"
call :init_path "%~2"
call :psubst_check_disk "%~1" || exit /b %ERRORLEVEL%

subst !psubst_disk! !psubst_path!
if /i "%~2" == "/P" (
rem
rem PSUBST X: /P
rem

if /i "%~3" == "/p" (
if /i "%~2" == "/d" (
call :reg delete !psubst_disk! >nul
) else (
if errorlevel 1 goto stop_reg
call :reg add !psubst_disk! !psubst_path! >nul
call :psubst_lookup "%psubst_disk%"
if not defined psubst_persist_path (
echo:%~n0: Drive not persistent
exit /b 1
)

setlocal enabledelayedexpansion

subst "!psubst_persist_disk!" "!psubst_persist_path!"

endlocal
goto :EOF
)

:stop_reg
call :cleanup
if /i "%~2" == "/D" (
rem
rem PSUBST X: /D ...
rem

set "psubst_reg_op=delete"
set "psubst_path="
) else (
rem
rem PSUBST X: "..." ...
rem

call :psubst_check_path "%~2" || exit /b %ERRORLEVEL%
)

if /i "%~3" == "/P" (
rem
rem PSUBST ... /P
rem

call :psubst_persist "%~3"
) else if /i "%~3" == "/PF" (
rem
rem PSUBST ... /PF
rem

call :psubst_persist "%~3"
) else if defined psubst_path (
rem
rem SUBST X: "..."
rem

subst "%psubst_disk%" "%psubst_path%"
) else (
rem
rem SUBST X: /D
rem

subst "%psubst_disk%" /D
)

endlocal
goto :EOF


:init
set psubst_disk=
set psubst_path=
set psubst_line=
set psubst_query="HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices"
:psubst_init
set "psubst_disk="
set "psubst_path="
set "psubst_value="
set "psubst_persist_disk="
set "psubst_persist_path="
set "psubst_reg_op="
set "psubst_regkey=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices"
goto :EOF


:init_disk
if "%~1" == "" goto :EOF
set psubst_disk=%~d1
if "!psubst_disk:~-1!" == "\" set psubst_disk=!psubst_disk:~0,-1!
goto :EOF
:psubst_check_disk
if not "%~1" == "" for %%d in ( "%~1" ) do if /i "%%~d" == "%%~dd" (
set "psubst_disk=%%~d"
exit /b 0
)

echo:%~n0: Invalid parameter: %~1
exit /b 1

:init_path
if "%~1" == "" goto :EOF
if /i "%~1" == "/d" (
set "psubst_path=%~1"
goto :EOF

:psubst_check_path
if /i "%~1" == "/D" (
set "psubst_reg_op=delete"
set "psubst_path="
exit /b 0
)

if /i "%~1" == "/p" (
set psubst_path=
for /f "tokens=1,2,*" %%a in ( 'reg query !psubst_query! ^| findstr ??' ) do (
if "!psubst_disk!" == "%%~a" (
set psubst_path="%%~c"
set psubst_path=!psubst_path:\??\=!
goto :EOF
)
)
goto :EOF
if not "%~1" == "" for %%f in ( "%~1\." ) do if exist %%~sf\nul (
set "psubst_reg_op=add"
set "psubst_path=%%~ff"
exit /b 0
)

set "psubst_path=%~1"
set psubst_path=!psubst_path:/=\!
if "!psubst_path:~-1!" == ":" set psubst_path=!psubst_path!\
if "!psubst_path:~-1!" == "\" (
if not "!psubst_path:~-2,1!" == ":" set psubst_path=!psubst_path:~0,-1!
echo:%~n0: Path not found: %~1
exit /b 1


:psubst_persist
call :psubst_lookup "%psubst_disk%"

if /i "%psubst_reg_op%" == "add" if defined psubst_persist_disk (
echo:%~n0: Drive already SUBSTed persistently
exit /b 1
)

set psubst_path="!psubst_path!"
goto :EOF
if /i "%psubst_reg_op%" == "delete" if not defined psubst_persist_disk (
echo:%~n0: Drive not SUBSTed persistently
exit /b 1
)

set "psubst_value="

:reg
set psubst_line=
if not "%~3" == "" (
set "psubst_line=\??\%~3"
if not "!psubst_line:~-1!" == "\" set psubst_line="!psubst_line!"
set psubst_line=/t REG_SZ /d !psubst_line!
if /i "%~1" == "/PF" (
call :psubst_persist_reg_sudo
) else (
call :psubst_persist_reg
)
if not "%~2" == "" set psubst_line=/v %~2 !psubst_line!
if /i not "%~1" == "query" set psubst_line=!psubst_line! /f
goto :EOF

reg %~1 !psubst_query! !psubst_line!
:psubst_persist_reg
if defined psubst_path set "psubst_value=/t REG_SZ /d "\??\%psubst_path%""
reg %psubst_reg_op% "%psubst_regkey%" /v %psubst_disk% %psubst_value% /f >nul
goto :EOF

rem Based on the solution suggested in this thread:
rem https://www.dostips.com/forum/viewtopic.php?f=3&t=9212
:psubst_persist_reg_sudo
if defined psubst_path set "psubst_value=/t REG_SZ /d \"\??\%psubst_path%\""
reg add "HKCU\Software\Classes\.elevate\shell\runas\command" /ve /d "cmd.exe /c start reg %psubst_reg_op% \"%psubst_regkey%\" /v %psubst_disk% %psubst_value% /f >nul" /f >nul

:print_persist
for /f "tokens=1,2,*" %%a in ( 'reg query !psubst_query! ^| findstr ??' ) do (
set psubst_disk=%%~a
set psubst_path=%%~c
set psubst_path=!psubst_path:\??\=!
type nul > "%TEMP%\%~n0.elevate"
"%TEMP%\%~n0.elevate"
del /q "%TEMP%\%~n0.elevate"

reg delete "HKCU\Software\Classes\.elevate" /f >nul

echo:!psubst_disk!\: =^> !psubst_path!
)
goto :EOF


:cleanup
set psubst_query=
set psubst_disk=
set psubst_path=
set psubst_file=
set psubst_line=
:psubst_print
call :psubst_lookup
goto :EOF


:psubst_lookup
for /f "tokens=1,2,*" %%a in ( 'reg query "%psubst_regkey%"' ) do ^
for /f "tokens=1,* delims=\\" %%k in ( "%%~c" ) do ^
if "%%k" == "??" if "%~1" == "" (
echo:%%~a\: =^> %%~l
) else if "%~1" == "%%~a" (
set "psubst_persist_disk=%%~a"
set "psubst_persist_path=%%~l"
goto :EOF
)
goto :EOF


Expand Down

0 comments on commit 277f04c

Please sign in to comment.