145 - Install Windows directly from an ISO file using iPXE wimboot with grub2 or grub4dos

This method allows you to directly boot from a number of different unmodified Windows Install 7/8/10 etc. ISOs on a bootable USB drive AND run Setup to install Windows to a system.

  • It only works for MBR\Legacy booting (wimboot for UEFI does not work unless you boot to iPXE via UEFI).
  • The ISO is automatically mounted as a virtual drive so Setup can find and use the Install.wim\esd file.
  • 2GB or more RAM is required to be in the system (it may fail to work if not enough RAM is available).
  • The Windows Install ISO file does not need to be modified in any way.

I will describe here only the outline process so that you can see how it is done. Easy2Boot uses a similar (but not identical) process.

Process in outline:

  1. Add Windows Install ISO to a grub4dos or grub2 bootable USB drive
  2. Add a menu for grub4dos\grub2
  3. The menu uses wimboot to boot to files inside the ISO
  4. The menu also injects a special .tag file (e.g. Windowsx64.iso.tag) - we can use any file for this because the contents are not important - only the file name is used (I just use the BCD)
  5. The menu also injects a startnet.bat file and winpeshl.ini file
  6. We swap BIOS device hd0 with hd1 so that Windows does not think the boot drive is the USB drive (it may refuse to install Windows to a Removable USB drive or Setup may install the Windows boot code to a USB hard disk if we don't do this).
  7. When the grub2\grub4dos menu is picked, here is what happens...
  8. The ISO is mounted (by grub4dos as a CD device using map or by grub2 as a loop device)
  9. wimboot will load the boot.wim, boot.SDI and BCD from the mounted ISO
  10. We inject into the boot.wim\X: RAM drive a .tag file which has the same name as the ISO file
  11. We inject into the boot.wim\X: RAM drive a winpeshl.ini and startup.bat file
  12. The boot.wim file is booted to by wimboot using bootmgr.exe and startup.bat runs
  13. startup.bat finds the USB drive and installs ImDisk (which is a also located on the USB drive somewhere)
  14. startup.bat finds the .tag file(s) in X:\Windows\System32 and from this we can determine the name of the ISO that we need to load
  15. startup.bat uses ImDisk to load the ISO from the USB drive as drive Y:
  16. startup.bat runs X:\Setup.exe which will now be able to find the \sources\install.wim file on the Y: virtual DVD drive mounted by ImDisk
If required, we can also inject an XML file into the X:\Windows\System32 folder and specify this as the unattend file when we run setup.exe.

It is necessary to switch the BIOS drives 0 (USB drive) and 1 around so that Windows will think the 'boot' drive is the internal hard disk and not the USB drive - otherwise Windows will refuse to install to the first internal hard disk.

You can use VBox+VMUB to test (see Tutorial 4).

Example grub2 menu:

menuentry "WIN10 Install" --unrestricted --class Windows {
set isoname=win10.iso
loopback loop /$isoname
linux16 /wimboot
initrd16 newc:bcd:(loop)/boot/bcd \
newc:boot.sdi:(loop)/boot/boot.sdi \
newc:boot.wim:(loop)/sources/boot.wim \
newc:Win10.iso.tag:(loop)/boot/bcd \
newc:winpeshl.ini:/winpeshl.ini \
newc:startup.bat.sdi:/startup.bat
drivemap -s hd0 hd1
boot
)

Note: filenames defined after newc: must not be bigger than 31 characters or wimboot will fail.

Example grub4dos menu:

title Install Windows10x64UK_Oct_2018 using wimboot method
map /Windows10x64UK_Oct_2018.iso (0xff)
map --hook
root (0xff)
# the root path now points to the files inside the ISO file
# hd0,0 is the USB drive that we booted from
kernel (hd0,0)/wimboot
initrd @startup.bat=(hd0,0)/startup.bat @winpeshl.ini=(hd0,0)/winpeshl.ini @bcd=/boot/bcd @boot.sdi=/boot/boot.sdi @boot.wim=/sources/boot.wim @Windows10x64UK_Oct_2018.iso.tag=/boot/bcd
map (hd0) (hd1)
map (hd1) (hd0)
map --hook
boot


On our USB drive we have:
\winpeshl.ini
\startup.bat
\(the windows install iso)


Example winpeshl.ini
[LaunchApps]
startup.bat


Example startup.bat
@echo off
TITLE %~dpnx0 (E2B-WIMBOOT startup.bat)
wpeinit.exe
REM prevent wpeinit from running again
ren X:\windows\system32\wpeinit.exe wpeinit.exe.old

for %%I in (C D E F G H I J K L M N O P Q R S T U V W X Y Z) do if exist %%I:\_ISO\e2b\grub\e2b.cfg set E2BDRIVE=%%I:
IF "%E2BDRIVE%"=="" (
echo ERROR - COULD NOT FIND E2B DRIVE!
pause
goto :EOF
)

cd %E2BDRIVE%\
%E2BDRIVE%
REM load ISO using Imdisk - we must find a X:\windows\system32\*.iso.tag file to determine the ISO filename we need to load
call \_ISO\e2b\firadisk\loadiso.cmd

TITLE %~dpnx0 (E2B-WIMBOOT startup.bat)
REM Run Setup.exe and default unattend.xml file in root of E2B drive
%DVDDRIVE%
cd \
set pp=\x86
if /i "%PROCESSOR_ARCHITECTURE%"=="AMD64" set pp=\x64
if not exist %DVDDRIVE%%pp%\setup.exe set pp=

MODE CON COLS=30 LINES=2
echo DO NOT CLOSE THIS WINDOW
%DVDDRIVE%%pp%\setup.exe /Unattend:%E2BDRIVE%\AutoUnattend.xml



Adding a menu to the E2B grub2 menu system (MBR only)

Set up your E2B drive with a second partition and the E2B grub2 menu files.

The following windows_install.grub2 menu text file can be added to the \_ISO\MAINMENU folder on the 2nd partition.
  1. Download the grub2_wimboot files - extract it onto the root of the SECOND partition so you have a new \wimboot folder

  2. Move the \windows_install.grub2 file to \_ISO\MAINMENU\grub2 folder on the SECOND E2B partition. Rename it as custom_menu.grub2 if using grub2 Beta 10 or later.

  3. Create a new \_ISO\MAINMENU\WINDOWS folder (must be in capital letters) and place all your Windows ISOs in that folder.
The Windows ISOs will be automatically added into the main grub2 menu (but only if you MBR boot).

The Windows ISO MUST NOT CONTAIN SPACES IN THE FILENAME and the ISO filename must be less than 28 characters (because the xxxx.iso.tag file must be less than 32 characters in total).
Dual-architecture Install ISOs are supported, x64 will be used if the CPU is a 64-bit processor.


\_ISO\MAINMENU\grub2\windows_install.grub2

function ListWimBoot {
echo "Adding ISO files from \"$ip\WINDOWS\"..."
set root=$root2
for file in $ifp/WINDOWS/*.iso $ifp/WINDOWS/*.ISO; do
if ! test -f "$file"; then continue; fi
regexp -s filename "$ip/WINDOWS/(.*)" "$file"
regexp -s filenamex "$ip/WINDOWS/(.*)(.[iI][Ss][oO])" "$file"
menuentry "${filenamex}" {
set isoname="${filename}" ; CHECK_MNU_FOLDER
loopback loop ${ifp}/WINDOWS/${filename}
set pp=
if test -f (loop)/x64/sources/boot.wim; then set pp=/x64; fi
if $MBR32; then
if test -f (loop)/x86/sources/boot.wim; then set pp=/x86; fi
fi
echo Using ${pp}/sources/boot.wim...
linux16 /wimboot/wimboot
initrd16 newc:bcd:(loop)${pp}/boot/bcd \
newc:$filename.tag:(loop)${pp}/boot/bcd \
newc:boot.sdi:(loop)${pp}/boot/boot.sdi \
newc:winpeshl.ini:/wimboot/winpeshl.ini \
newc:startup.bat://wimboot/startup.bat \
newc:boot.wim:(loop)${pp}/sources/boot.wim
drivemap -s hd0 hd1
boot
}
done
}

if ! $EFI ; then ListWimBoot; fi




Example startup.bat file:

@echo off
TITLE %~dpnx0 (WIMBOOT startup.bat)
wpeinit.exe
REM prevent wpeinit from running again
ren X:\windows\system32\wpeinit.exe wpeinit.exe.old

for %%I in (C D E F G H I J K L M N O P Q R S T U V W X Y Z) do if exist %%I:\wimboot\startup.bat set USBDRIVE=%%I:
IF "%USBDRIVE%"=="" (
echo ERROR - COULD NOT FIND E2B DRIVE!
pause
goto :EOF
)

cd %USBDRIVE%\
%USBDRIVE%
color 1f
@echo off
cls
SET BIT=32
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" SET BIT=64

echo LOADISO
FOR /L %%A IN (0,1,5000) DO ECHO NOTHING > nul
cls
@echo FOUND USB DRIVE AT DRIVE %USBDRIVE%
cd /d %USBDRIVE%\

:: get path of the ISO into ISONAME
:: SET "MYISO=\_ISO\MAINMENU\WINDOWS\Windows10Prox64.iso"
for /f %%a in ( 'dir /b X:\Windows\System32\*.iso.tag' ) do set MYISO=%%a
set MYISO=%MYISO:~,-4%

:: find the ISO in \_ISO\MAINMENU\WINDOWS
set UPATH=\_ISO\MAINMENU\WINDOWS\%MYISO%
if exist %USBDRIVE%%UPATH% set MYISO=%UPATH%
echo Loading %USBDRIVE%%MYISO%

REM Load ISO using ImDisk
TITLE LOAD WINDOWS ISO USING IMDISK
call \wimboot\imdisk\IMDISK_install.cmd
call \wimboot\imdisk\IMDISK_instiso.cmd

REM Find mounted DVD drive
set DVDDRIVE=
FOR %%D IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
DIR %%D:\SOURCES\install.* > nul 2>&1 && (call set DVDDRIVE=%%D:) && echo FOUND %%D:\SOURCES\install.*
)
FOR %%D IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
DIR %%D:\SOURCES\x86\install.* > nul 2>&1 && (call set DVDDRIVE=%%D:) && echo FOUND %%D:\SOURCES\x86\install.*
)
FOR %%D IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
DIR %%D:\SOURCES\x64\install.* > nul 2>&1 && (call set DVDDRIVE=%%D:) && echo FOUND %%D:\SOURCES\x64\install.*
)
FOR %%D IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
DIR %%D:\x86\SOURCES\install.* > nul 2>&1 && (call set DVDDRIVE=%%D:) && echo FOUND %%D:\x86\SOURCES\install.*
)
FOR %%D IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO (
DIR %%D:\x64\SOURCES\install.* > nul 2>&1 && (call set DVDDRIVE=%%D:) && echo FOUND %%D:\x64\SOURCES\install.*
)

:ENDSEARCH
IF "%DVDDRIVE%"=="" echo WARNING: VIRTUAL DRIVE DRIVE NOT FOUND!
IF "%DVDDRIVE%"=="" echo WARNING: install.* not found on any mounted volume.
IF "%DVDDRIVE%"=="" pause
echo.
IF NOT "%DVDDRIVE%"=="" echo ISO FILE MOUNTED AS %DVDDRIVE%

REM startnet.cmd normally only contains wpeinit.exe, custom ISOs may contain other commands, so try to run them
if exist X:\WINDOWS\SYSTEM32\startnet.cmd call cmd /c X:\WINDOWS\SYSTEM32\startnet.cmd
if not exist X:\WINDOWS\SYSTEM32\startup.bat exit
IF "%DVDDRIVE%"=="" cmd

%DVDDRIVE%
cd \
set pp=\x86
if /i "%PROCESSOR_ARCHITECTURE%"=="AMD64" set pp=\x64
if not exist %DVDDRIVE%%pp%\setup.exe set pp=

MODE CON COLS=30 LINES=2
echo DO NOT CLOSE THIS WINDOW
REM %DVDDRIVE%%pp%\setup.exe /Unattend:%E2BDRIVE%\AutoUnattend.xml
%DVDDRIVE%%pp%\setup.exe



ċ
grub2_wimboot.zip
(289k)
Steve Si,
21 Jan 2019, 06:16
Comments