We're setting up some systems to PXEboot via iPXE and, depending on a master server state, either boot normally or reimage via wimboot and MDT. The systems are configured to boot from the network first. iPXE and wimboot are both running under UEFI.
It works great, except at the end of the windows installation, the BIOS has been modified to point to the new Windows Boot Manager as the primary boot device. So it can't be imaged again without entering the bios and changing settings.
I understand why the boot order gets changed as the wimboot/MDT process involves multiple restarts. But I really would like to either keep PXE as the primary boot throughout or manipulate the boot order back to have network first when done. (My PXE server will pass on the network boot opportunity to allow the install to work or leave the system alone when no imaging is needed.)
Update - I see two possibilities:
- Figure out how the windows installer tells UEFI to boot from the destination install disk, and do the same thing when the windows install is done to set back to PXE boot.
- Play with the Windows Boot Manager and BCDEdit after installation of windows to place the PXE booting option above booting from local disk (question found at superuser is basically the same question as here. The end result discussed there isn't quite what I really want (PXE first in UEFI settings) but might yield the same behavior (PXE boot always getting a chance to act before windows starts).
Learned the following:
Once I understood the UEFI spec for boot order and the windows API, the code (C++, built for 64-bit as that is all we are using) wasn't too bad. This needs to be built into an exe that requires administrative privileges and statically links the windows runtime, and then I run it in MDT after the OS is installed before restart.
First, you have to claim a privilege to call the API. Use a little helper:
then call
Next, get the list of boot options (a concatenation of uint16_t values):
You then can iterate over each boot option, form the Boot#### variable name for it, and then use that to get a struct with info about the option. You'll want to see if the first active option has "Description" equal to "Windows Boot Manager". Description is a null-terminated wide character string at offset 6 in the struct.
Now if you found active WBM and non-WBM boot options and the first WBM option is at wbmOffset, and the first non-WBM option is at nonWBMOffset, with wbmOffset < nonWBMOffset, swap the entries in the BootOrder variable with the following:
I came up with this powershell script that works for me. It's not perfect because it just "stupidly" moves the first non-Windows boot entry to the top. That works for my purposes and there may be a way to make it smarter that I just didn't find.
It looks long, but it's mostly comments and formatted for comprehension. It could be re-written to 5 or 6 lines.
https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order