The 30 second delay in booting Windows PE’s via pxelinux

The Windows Preinstallation Environment (Windows PE) is used to install newer Microsoft operating systems such as Windows 7 and Windows Server 2008 — Windows PE is what boots, when the appropriate install DVD is inserted.

Now when pursuing network installations, one sooner or later hits the .iso generated by the Windows Automated Installation Kit (WAIK) or the Windows OEM Preinstallation Kit (OPK). Windows PE can be PXE-booted in two ways from PXELinux, either by loading this .iso via memdisk or by booting the PXE Bootloader contained within, There are some (not that easy) steps necessary to get the latter going, but this post is not about that.

Rather this is about the approximate 30 second delay observable when your TFTP server is running with increased verbosity:

  1. First, is loaded.
  2. loads bootmgr.exe (yes, a relative path specification.)
  3. Now the ~30 second delay occurs before the BCD file is loaded.

This does not happen with Windows’ Deployment Services, of course… so what’s going on?

Matijn Tigchelaar found out: bootmgr.exe does not necessarily load BCD from a fixed location but looks at DHCP options for a path specification first, then tries to contact a WDS server at UDP port 4011 and at last resorts to the default path \Boot\BCD, but only after a timeout of, guess what, 30 seconds.

So if we want to get rid of that delay, we need to feed bootmgr.exe the DHCP option 252, even if we stay with the default path \Boot\BCD. Now we can’t just set that option on the DHCP server since we might not have access to it. Also DHCP option 252 actually has a special meaning, feeding Microsoft clients the path to Web Proxy Automatic Discovery (WPAD) information. Matijn thus asked for a possibility to have PXELinux spoof the DHCP option to be set just for

The solution suggested on the syslinux mailing list involves the use of gPXE/iPXE and a special embedded script:

dhcp net0
set 252:string \Boot\BCD
chain tftp:///Boot/pxeboot.0

However, this requires compilation of a custom iPXE binary. I therefore opted to go a different way. Just use a generic iPXE binary compiled as a Linux kernel (make bin/ipxe.lkrn), save the script into a file which is then fed as an initrd:

label winpe
menu label Windows PE
kernel ipxe.lkrn
initrd winpe_fake_dhcp252.ipxe

You can also pass the script via PXELinux’s append parameter, as also described in the iPXE “embed” dcoumentation.

Note that this still fires off a second DHCP request once iPXE is loaded. The way around that would be to use iPXE’s bin/undionly.kkpxe target, but then PXELinux’s append and initrd wouldn’t work. keeppxe is also no option, since it a.) didn’t work for me and b.) only triggers error messages from iPXE which, by contrast to the Linux kernel, doesn’t know about that option.

1 comment

Leave a comment