Chuyu-Team / Dism-Multi-language

Dism++ Multi-language Support & BUG Report
MIT License
14.7k stars 1.01k forks source link

增加功能:释放镜像后可以更改系统占用盘符 #254

Closed powerxing04 closed 6 years ago

powerxing04 commented 6 years ago

这个功能提取自NT6快速安装器里的osletter7.cmd脚本,此脚本可用于部署一个WIM映像后,在重新启动前更改其系统盘占位盘符,尤其是用了vhdx安装或者Windows To Go的用户,不想导致系统盘默认是C导致本地硬盘盘符全部变化很有必要。 命令格式: OsLetter.CMD /TargetLetter:将要占位的盘符 /CurrentOS:当前所在分区盘符 参数说明: /TargetLetter:盘符 指定刚部署的系统盘启动后将要占位的盘符 /CurrentOS:盘符 指定要个更改盘符的系统当前所在分区盘符(比如WinPE下) 举例说明: osletter /targetletter:x /currentos:t 执行脚本,将当前T盘下的系统占用盘符更改为X盘。 osletter /targetletter:x /currentos:t > t:\dl.log 执行脚本,将当前T盘下的系统占用盘符更改为X盘,并将执行结果输出到日志文件T:\dl.log中。 源代码: @echo off REM =============================================================================== REM REM Script arguments REM /currentos: REM Specify the current drive letter (under WinPE) of the OS partition REQUIRED REM REM NOTE: The log is printed to console by default. To write log to file, please REM redirect the output to a log file. For example: REM osletter7.bat /targetletter:s /currentos:t > t:\osletter7.log REM REM -------------------------------------------------------------------------------

setlocal set BadUsage= set CurrentOsDriveLetter= set TargetSystemDriveLetter= set NewOSDriveLetter= set TempOutFile=%TEMP%\osletter7.bat.temp1.out set ValidDriveLetters=C D E F G H I J K L M N O P Q R S T U V W X Y Z

if /I "%1" == "" ( Call :PrintUsage exit /b 1 )

if /I "%1" == "/?" ( Call :PrintUsage exit /b 1 )

REM ----- Print log file header ------ echo. echo Script processing started for command: "%0 %*". echo Parsing arguments...

REM ----- parse command line arguments ------ :ParseArgumentLoop if /I "%1" == "" ( goto :ParseArgumentLoopEnd )

if /I "%1" == "/?" (
    Call :PrintUsage
    exit /b 1
)

Call :ParseArgument  %1
if "%BadUsage%" == "1" (
    goto :HandleBadUsage
)

shift /1
goto :ParseArgumentLoop

:ParseArgumentLoopEnd

REM ----- argument checks ------ Call :ValidateArgument if "%BadUsage%" == "1" ( goto :HandleBadUsage )

if not exist %CurrentOsDriveLetter%:\Windows\System32\Config\SYSTEM ( echo ERROR - Drive "%CurrentOsDriveLetter%" is not a valid OS drive - OS image not found. goto :HandleBadUsage )

REM Output command arguments to log file echo ----------------------------------------------------------------------- echo ---------------Executing with the following arguments------------------ echo ----------------------------------------------------------------------- echo Current OS partition: %CurrentOsDriveLetter% echo Target system partition letter: %TargetSystemDriveLetter% echo -----------------------------------------------------------------------

REM ----- Main script processing ---- Call :FixRegistry if "%BadUsage%" == "1" ( goto :HandleBadUsage ) if ERRORLEVEL 1 ( goto :Failure )

REM -------------------------------------------------------------------------------------- REM End of the main function (in case of success) REM -------------------------------------------------------------------------------------- if exist %TempOutFile% del /q %TempOutFile% echo Script completed successfully. exit /b 0

REM -------------------------------------------------------------------------------------- REM Exit the script in case of failure. REM -------------------------------------------------------------------------------------- :Failure if exist %TempOutFile% del /q %TempOutFile% echo Script failed! exit/b 1

REM -------------------------------------------------------------------------------------- REM Function - Parse an argument REM Output: set BadUsage=1 if parsing failed REM -------------------------------------------------------------------------------------- :ParseArgument set ArgumentName= set ArgumentValue= for /F "delims=: tokens=1" %%i in ("%1") do set ArgumentName=%%i for /F "delims=: tokens=2" %%i in ("%1") do set ArgumentValue=%%i for /F "delims=: tokens=3" %%i in ("%1") do ( if not "%%1" == "" ( REM This is the error case that there are more than two tokens in the REM argument string (e.g. "currentsystem:s:abc") echo Error - Invalid syntax: %1 set BadUsage=1 exit /b 1 ) )

    if /I "%ArgumentName%" == "/Targetletter" (
        set TargetSystemDriveLetter=%ArgumentValue%
    ) else (
        if /I "%ArgumentName%" == "/CurrentOS" (
            set CurrentOsDriveLetter=%ArgumentValue%
        ) else (
        echo Error - Invalid syntax: %1
        set BadUsage=1
            exit /b 1
        )
    )    

exit /b 0

REM -------------------------------------------------------------------------------------- REM Function - Check arguments for requiered options. REM Input: REM Output: set BadUsage=1 if validation failed REM -------------------------------------------------------------------------------------- :ValidateArgument if "%TargetSystemDriveLetter%" == "" ( echo ERROR - No /targetLetter option specified on the command line. set BadUsage=1 ) else ( Call :IsValidDriveLetter TargetLetter %TargetSystemDriveLetter% TargetSystemDriveLetter )

if "%CurrentOsDriveLetter%"     == ""  (
    echo ERROR - No /currentos option specified on the command line.
    set BadUsage=1
) else (
  Call :IsValidDriveLetter  CurrentOS  %CurrentOsDriveLetter%  CurrentOsDriveLetter
)

exit /b 0

REM -------------------------------------------------------------------------------------- REM Function - Display usage for help. REM Input: REM Output: REM -------------------------------------------------------------------------------------- :PrintUsage echo This script can be used to change the OS drive letters when echo deploying a WIM image before reboot. echo. echo osletter7[.cmd] /TargetLetter:^<DriveLetter^> /CurrentOS:^<DriveLetter^> echo. echo /TargetLetter:^<DriveLetter^> echo Specify the OS drive letter under the system echo. echo /CurrentOS:^<DriveLetter^> echo Specify the current drive letter (under WinPE) of the OS partition echo. echo Examples: echo osletter7 /targetletter:s /currentos:t echo Execute the script. echo. echo osletter7 /targetletter:s /currentos:t ^> t:\dl.log echo Execute the script and redirect output to a log file. echo. exit /b 0

REM -------------------------------------------------------------------------------------- REM Function - Print help message in case of bad usage REM Input: REM Output: REM -------------------------------------------------------------------------------------- :HandleBadUsage echo. echo Type "DriveLetter /?" for help. exit /b 1

REM -------------------------------------------------------------------------------------- REM Function - Check whether a drive letter from a command line argument is valid or not. REM Input: %1 - Name of the command line argument (e.g. CurrentSystem) REM %2 - the drive letter (e.g. C) REM %3 - Name of the global variable to set (e.g. CurrentSystemDriveLetter) REM Output: set BadUsage=1 and errorlevel=1 if the input drive letter is invalid REM -------------------------------------------------------------------------------------- :IsValidDriveLetter for %%i in (%ValidDriveLetters%) do ( if /I "%%i" == "%2" ( set %3=%%i exit /b 0 ) )

echo ERROR - Invalid drive letter "%2" entered for the command line argument "%1"
set BadUsage=1
exit /b 1

REM -------------------------------------------------------------------------------------- REM Function - Check whether a drive letter is valid or not. REM Input: %1 - the drive letter REM Output: set errorlevel=1 if the drive letter is invalid REM -------------------------------------------------------------------------------------- :IsValidDriveLetter2 for %%i in (%ValidDriveLetters%) do ( if /I "%%i" == "%1" ( exit /b 0 ) ) exit /b 1

REM -------------------------------------------------------------------------------------- REM Function - Fix drive letters in registry REM Input: arguments in global variables REM Output: REM Return: set errorlevel to 1 in case of failure REM -------------------------------------------------------------------------------------- :FixRegistry set SystemHiveLoaded= set FixRegistryErrorLevel=

echo Fixing drive letters in registry...

Call :GetNewOsDriveLetter
if errorlevel 1 (
    goto :FixRegistryExitWithFailure
)

echo Preparing to fix registry entries...

Call :FindVolumeEntryByDriveLetter  %CurrentOsDriveLetter%      OSVolumeValue
if errorlevel 1 (
    goto :FixRegistryExitWithFailure
)

REM -- At this point, OSVolumeValue is something like 000000080014E70400000000.

reg.exe load HKU\TEMP %CurrentOsDriveLetter%:\Windows\System32\Config\SYSTEM  > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg.exe load HKU\TEMP %CurrentOsDriveLetter%:\Windows\System32\Config\SYSTEM
    goto :FixRegistryExitWithFailure
) else (
    set SystemHiveLoaded=1
)

REM -- create the key first so that we can successfully 
REM -- delete, in case it did not exist.
reg add HKU\TEMP\MountedDevices /f > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg add HKU\TEMP\MountedDevices /f
    goto :FixRegistryExitWithFailure
)

reg delete HKU\TEMP\MountedDevices /f > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg delete HKU\TEMP\MountedDevices /f
    goto :FixRegistryExitWithFailure
)

reg add HKU\TEMP\MountedDevices /f > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg add HKU\TEMP\MountedDevices /f
    goto :FixRegistryExitWithFailure
)

reg add HKU\TEMP\MountedDevices /v \DosDevices\%NewOSDriveLetter%: /t REG_BINARY /d %OSVolumeValue% /f > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg add HKU\TEMP\MountedDevices /v \DosDevices\%NewOSDriveLetter%: /t REG_BINARY /d %OSVolumeValue% /f
    echo ERROR - Failed to write to System registry hive
    goto :FixRegistryExitWithFailure
) else (
    echo Successfully wrote OS volume device with the new drive letter.
)

reg.exe unload HKU\TEMP > %TempOutFile%
if ERRORLEVEL 1 (
    echo ERROR - Failed to save the System registry hive: %CurrentOsDriveLetter%:\Windows\System32\Config\SYSTEM.
    goto :FixRegistryExitWithFailure
) else (
    echo Successfully saved registry hive.
    set SystemHiveLoaded=
)

goto :FixRegistryEnd

:FixRegistryExitWithFailure set FixRegistryErrorLevel=1 :FixRegistryEnd if "%SystemHiveLoaded%" == "1" ( reg.exe unload HKU\TEMP > %TempOutFile% if ERRORLEVEL 1 ( echo Failed unload the SYSTEM hive, error ignored. ) )

exit /b %FixRegistryErrorLevel%

REM -------------------------------------------------------------------------------------- REM Function - Read offline register SOFTWARE\Microsoft\Windows NT\CurrentVersion RegValue REM "PathName", and parse the new OS driveletter from it. REM REM Input: REM Output: set NewOSDriveLetter to the new OS driveletter REM Return: set errorlevel to 1 in case of failure REM -------------------------------------------------------------------------------------- :GetNewOsDriveLetter set NewOSDriveLetter=%TargetSystemDriveLetter%

Call :IsValidDriveLetter2 %NewOSDriveLetter%
if ERRORLEVEL 1 (
    echo Failed to parse the new OS drive letter.
    exit /b 1
) else (
    echo Valid OS drive letter.
)

exit /b 0

REM -------------------------------------------------------------------------------------- REM Function - Search HKLM\SYSTEM\MountedDevices, find the volume device name and value by driveletter. REM REM Input: %1 - The drive letter REM %2 - Name of the variable to be set to the volume device value REM Output: set variable %3 REM Return: set errorlevel to 1 in case of failure REM -------------------------------------------------------------------------------------- :FindVolumeEntryByDriveLetter set %2= set VolumeDeviceValue= set DeviceDriveName=\DosDevices\%1:

reg query HKLM\SYSTEM\MountedDevices /v %DeviceDriveName% > %TempOutFile%
if ERRORLEVEL 1 (
    echo Command failed: reg query HKLM\SYSTEM\MountedDevices /v %DeviceDriveName%
    goto :FindVolumeEntryByDriveLetterEnd
)

for /F "skip=2 tokens=3" %%i in (%TempOutFile%) do (
    REM -- set VolumeDeviceValue to the REG_BINARY value (something like
    REM -- 000000080014E70400000000) of the volume device.
    set VolumeDeviceValue=%%i
    goto :FindVolumeEntryByDriveLetterEnd
)

:FindVolumeEntryByDriveLetterEnd if "%VolumeDeviceValue%" == "" ( echo Error - Failed to get registry drive mapping for drive: %1 exit /b 1 )

set %2=%VolumeDeviceValue%
exit /b 0
mingkuang-Chuyu commented 6 years ago

不添加此功能,因为如果用户在OOBE后更改盘符至非原有盘符,直接导致系统黑屏无法启动(Windows 8以上平台),而Windows 7则导致大量文件路径错误,尤其是Program File目录。

但是Dism++会提供类似的功能,针对释放映像保留原有盘符,来避免Win8以上系统跨盘符还原黑屏问题。

powerxing04 commented 6 years ago

主要就是希望添加在镜像释放的环节,部署重启配置系统后再更改系统盘符必然会导致系统混乱,我实测过