Copy ipxe.efi to uefi partition?
-
Re: Windows 10 change BIOS boot order after deploy
@JJ-Fullmer, In the above topic you stated that you were able to copy the ipxe.efi to the machine’s uefi partition. How do you go about doing this automated? could elaborate on the process for me? I have VERY little experience with uefi.
Thanks!
-
@greg-plamondon The concept of creating a uefi boot image that will boot into iPXE is covered here: https://forums.fogproject.org/topic/6350/usb-boot-uefi-client-into-fog-menu-easy-way Understand this tutorial is for creating a usb boot disk, but the concepts are exactly the same. In your case you want to modify the uefi boot partition (typically disk0 partition0).
-
@george1421 Thanks!
-
@george1421 I followed the post you linked.
In my case, it was partition 2.
I then assigned partition 2 drive letter b in disakpart. killed explorer and restarted explorer.
select disk 0 select part 2 assign letter=b exit taskkill /im explorer.exe /f explorer.exe
I then copied and replaced the bootx64.efi with the renamed ipxe.efi from the fogserver.
Once the file was copied over I removed the drive letter and rebooted.
I don’t see the menu while it’s booting. what am I supposed to see? -
@greg-plamondon Well you “should” see iPXE booting. I have not tried to do what you are attempting, but in theory it should work.
let me see if I can setup a test VM and reproduce the issue. Its strange that its the second partition, but whatever it should work if windows booted.
-
@greg-plamondon said in Copy ipxe.efi to uefi partition?:
I then copied and replaced the bootx64.efi with the renamed ipxe.efi from the fogserver.
Does Windows actually use the filename
bootx64.efi
I wonder?Wikipedia tells me it’s not:
The UEFI invokes bootmgfw.efi from an EFI system partition at startup
The German version of the wikipedia article says that bootx64.efi is just a fallback copy of bootmgfw.efi. Not sure if that’s correct bit it would explain why iPXE is not loaded in your case.
So, rename
bootmgfw.efi
and put in the iPXE EFI binary instead of that. Seems like the UEFI loader entry will address that file. -
@greg-plamondon Sorry I’ve been rather busy and hadn’t checked the forums in a bit.
Firstly a sidenote on what @Sebastian-Roth posted last. My understanding (from lots of trial and error, testing, and reading of microsoft docs) bootmgfw.efi is the bootmgr at the firmware level for windows. It uses the bcd entries (that you can modify with
bcdedit
to then load the specified efi file to boot the OS, which I think is something like bootx64.efi.So, I have a lot of information in my brain on this so let’s see if I can simplify.
TL;DR
Perhaps the quick answer to your question is
- make a symlink on the fog server to be able to download the ipxe.efi file
ln -s /tftpboot/ipxe.efi /var/www/html/ipxe.efi
- Mount the efi partition to drive letter A in windows
mountvol A: /S
- Download the ipxe file using powershell
Invoke-WebRequest -Uri "http://fogserver/ipxe.efi" -OutFile "A:\EFI\ipxe-latest.efi";
- (untested bit, but would probably work) Set the bcd to use ipxe as a bootmanager
bcdedit /set "{bootmgr}" path "\EFI\ipxe-latest.efi"
- You can revert this back to default with
bcdedit /set "{bootmgr}" path "\efi\Microsoft\Boot\bootmgfw.efi"
- You can revert this back to default with
- Dismount the efi partition
Mountvol A: /D
Brain dump of detailed info
I used to use rEFInd as my bootloader for my machines, but it has compatibility issues on some hardware so I found a different solution. I now use grub2win. But I still utilize Refind sometimes manually because it has a uefi shell, so when it is compatible it’s useful.
So first let me explain a wee bit on uefi shells from my understanding.
Basically, uefi has a shell, but not all computers have one built in. If you can boot to refind from a usb then you can access the shell.
The syntax for changing directories in the shell isfs#:
where # is the disk/partition number seen by uefi 0-(number of partitions -1).
You can then usels
andcd
to navigate and you can execute.efi
boot files and load efi drivers i.e.load driverName.efi
.
Playing with the uefi shells is how I figured out that if you pop ipxe.efi on to a usb or somewhere on the local disk, you can run it from the efi shell and it boots to fog (provided your network is already configured for pxe booting to fog). Some Bios/uefi firmwares also have options for ‘booting to file’ or other custom boot options where you can achive the same idea of navigating to an efi file and booting to it.So here’s a rundown of how I automate that process.
- I use chocolatey package manager and have a package made for installing grub2win
- I have a custom powershell module provisioning system that’s started via firstlogoncommands of my unattend.xml
- Within some of the first steps of provisioning I have it install my custom grub2win package (I have also tried to embed it in the image, but I believe sysprep/windows install changes the boot order on you, so I just make sure it runs, you could also do this with a setupcomplete.cmd system or whatever you use the run scripts after an image is completed)
So here’s what my custom package does, it looks like a lot here but it’s basically just installing a boot manager, copying some files, and editing the bcd.
Install grub2win
You can get a grub2win installer here https://sourceforge.net/projects/grub2win/
You download and extract the zip file. The setup.exe from the zip will then download the latest install files to%LocalAppData%\temp\grub2win.setup.exe.{buildNumber}\install
It will auto start a gui setup, but I leave that be and go copy the install folder from the temp folder to be a part of my package. Once I have the install folder out of the local appdata temp directory, I close the install wizard that popped up.Configure grub
In that install folder, you’ll need to edit the file at
winsource\basic.cfg
You can also use the built in gui tools to edit this after installing, but I find it easier to just make the config changes beforehand.Here’s what my custom menu entries look like, you’ll at least need the windows and fog menu entries.
# # Menu Entry 0 Windows 10 # # ** Grub will boot this entry by default ** # menuentry 'Windows 10 Hotkey=w' --hotkey=w --class windows --class icon-arrowwin { set gfxpayload=auto set efibootmgr=/efi/Microsoft/Boot/bootmgfw.efi getpartition file $efibootmgr root if [ ! -z $reviewpause ] ; then echo GNU Grub will load the Windows EFI Boot Manager at disk address $root g2wsleep echo fi chainloader $efibootmgr savelast 0 'Windows 10' echo GNU Grub is now loading Windows 10 } # # Menu Entry 1 FOG # menuentry 'FOG Hotkey=f' --hotkey=f --class chainfile --class icon-fog { set gfxpayload=auto set chainbootmgr=/efi/ipxe-latest.efi getpartition file $chainbootmgr root chainloader $chainbootmgr savelast 1 'FOG' echo GNU Grub is now loading FOG via ipxe } # # Menu Entry 2 Boot to your EFI firmware setup # menuentry 'Boot to your EFI firmware setup Hotkey=b' --hotkey=b --class bootfirmware --class icon-bootfirmware { g2wutil fwsetup } # # Menu Entry 3 Boot Information and Utilities # menuentry 'Boot Information and Utilities Hotkey=i' --hotkey=i --class bootinfo --class icon-bootinfo { clear set pager=0 set grub2win_chosen='0 - Windows Boot Manager' set grub2win_lastbooted=no export gfxmode export grub2part export grub2win_chosen export grub2win_lastbooted export grub2win_version export grub2win_procbits export grub2win_bootmode export grub2win_efiboot export grub2win_efilevel configfile $prefix/g2bootmgr/gnugrub.bootinfo.cfg } # # Menu Entry 65 Shutdown the system # menuentry 'Shutdown the system Hotkey=s' --hotkey=s --class shutdown --class icon-shutdown { clear set pager=1 echo echo Grub is shutting down your machine echo sleep -i -v 2 halt # If halt fails, display an error message echo Grub Shutdown is not supported by your firmware }
I put all that at the bottom, that’s my entire menuentries section.
Then at the top of the basic.cfg file (as in the very first uncommented line) I have
Set default=0
to default to the windows bootloader.Packaging and silent install
Then I make a chocolatey package (if you don’t have chocolatey you could probably achieve the same idea with a fog snapin pack). Basically you need all the files from the install folder, for a quick example we’ll pretend I copied the install files to
C:\install
To install grub2win silently I would runC:\install\winsource\grub2win.exe Autoinstall Quiet EFIAccess Shortcut=no Drive=C: RunFromEFI=yes SetAsDefault
This will extract some files to
C:\grub2win
and copy neccesarry files to the EFI partition.I also do some theme customization and add the refind efi shell tools, but I’m not going to get into that here right now.
Mount The EFI drive and copy down the ipxe.efi file
I have a powershell function called Mount-Efi that does this with some other functions that help it too with some error checking and making sure it’s not already mounted. But the most important bit is this bit
$mountLtr='A:' $mountVol = "C:\Windows\System32\mountvol.exe"; Start-Process -FilePath $mountVol -Wait -NoNewWindow -ArgumentList @($mountLtr, '/S');
That’s all to make it pretty in powershell, you can also just run the command natively
mountvol A: /S
where the/S
is telling it to mount your efi partion, and theA:
is saying to use A: as your path. This isn’t exposed to the gui file explorer, but you can thencd A:\
and you’re in the efi partion in powershell/cmd and can do whatever you want.Getting ipxe.efi
To simplify this process and always have the latest version. I have a symlink on my fogserver to be able to grab the ipxe.efi file with a quick download.
On the fogserver I create this withln -s /tftpboot/ipxe.efi /var/www/html/ipxe.efi
I can then download from http://fogserver/ipxe.efi. So after I’ve installed grub2win and then mounted the efi partition. I run this powershell command to download the ipxe file to efi and have it be namedipxe-latest.efi
Invoke-WebRequest -Uri "http://fogserver/ipxe.efi" -OutFile "A:\EFI\ipxe-latest.efi";
Now it is where my grub config will look for it if I choose to boot to fog.
Test that grub2win installed correct
I do a check in the efi partition that the kernel and binary files for grub2win are in the right place.
You should ssee all the files that were in the folderg2bootmgr
from the grub2win install folder at (assuming you mounted efi to A)A:\EFI\Grub2Win\g2bootmgr
particularly you want to see thegnugrub.kernel*.efi
boot file.Edit the windows bcd
This is the series of steps I run through to edit the bcd. (I have powershell functions for each to keep it simple to run internally, but I’ll just share the basic commands to make it less confusing to read through). Essentially I have an end result of pointing the default windows bootmgr bcd entry to the grub efi boot file.
Remove boot entry added by grub2win
Grub2win adds its own entry to bcd and it does often work. But I have a handful of devices that it doesn’t work as expected on, so I remove it and edit the default windows one, which helps with devices that don’t let you change the boot order within windows.
First you need to get the bcd entry for grub2win
$searchString = "Grub2Win EFI - 64 Bit"; $grubEntry = ($bcdEntry.ToString().split([Environment]::NewLine) | Where-Object { $_ -match 'id' }).Replace("identifier","").trim();
Then you need the guid of that entry
$guid = ($grubEntry.ToString().split([Environment]::NewLine) | Where-Object { $_ -match 'id' }).Replace("identifier","").trim();
Now you can remove the entry
bcdedit /set "{fwbootmgr}" displayorder $guid /remove
# you can also view/confirm its removal before and after with bcdedit /enum "{fwbootmgr}"
Edit where the bootmgr points
This is where we change the default bcd entry to use grub instead of the windows bootloader. Theoretically you could also use this to always boot to pxe, but I wouldn’t recommend that.
$path = "\EFI\Grub2Win\g2bootmgr\gnugrub.kernel64.efi" bcdedit /set "{bootmgr}" path $path
The code above is just using string manipulation to get the guid out of the output of the above enum command. If doing it manually you could highlight, copy, paste.
Make sure the altered boot manager is the first boot option
I’m pretty sure this is the command windows uses during sysprep to reset the boot order to boot to windows first instead of whatever you had set in the bios for install (i.e. pxeboot)
bcdedit /set "{fwbootmgr}" displayorder "{bootmgr}" /addfirst
Remove runOnce boot options
Sometimes grub2win or windows bcd or something else during this process adds a runOnce option. Theoretically you could use the runOnce option to force the computer to boot to the network on next reboot but it’ll go back to normal after that.
However, since I’m creating a default here and want to see it work as it always will, I remove any entries if the exist.bcdedit /deletevalue "{fwbootmgr}" bootsequence
Dismount efi partition and you’re done
Lastly you can dismount the efi partition with this command. Next time you restart you’ll have grub as a bootmgr with options for booting to fog or windows.
mountvol A: /D
Putting it all together.
Here’s what my chocolatey package looks like
- parent folder named custom-grub
- custom-grub.nuspec
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> <metadata> <id>custom-grub</id> <version>2004.2.207.5</version> <title>custom-grub</title> <authors>jfullmer</authors> <copyright>2019</copyright> <tags>custom-grub admin</tags> <description> Installs the customized arrowhead grub bootloader for easy booting to fog bios setup or a uefi shell when needed To update the config that gets installed, edit the sources\winsource\basic.cfg file The basic theme is overridden with the customized theme complete with company logo background the boot options are to boot to windows 10, fog via ipxe, firmware/bios setup, or the refind boot manager for when a uefi shell is needed. In the future options for windows 10 safe mode and other boot modes should be added as a submenu. </description> </metadata> <files> <file src="tools\**" target="tools" /> </files> </package>
-
- tools folder
- chocolateyinstall.ps1
- tools folder
$packageName = 'custom-grub' $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" $sources = "$toolsDir\sources"; $fileLocation = "$sources\winsource\grub2win.exe" $packageArgs = @{ packageName = $packageName softwareName = 'custom-grub*' file = $fileLocation fileType = 'exe' silentArgs = "Autoinstall Quiet EFIAccess Shortcut=no Drive=C: RunFromEFI=yes SetAsDefault " validExitCodes= @(0) url = "" destination = $toolsDir } Import-Module "$toolsDir\Functions.psm1" -force; Set-Location "C:\" Mount-EFI; $EfiMnt = Get-EfiMountLetter; Remove-OldGrubFiles -EfiMnt $EfiMnt; Add-EfiTools -sources $sources -EfiMnt $EfiMnt Dismount-EFI; Install-ChocolateyInstallPackage @packageArgs Mount-EFI; $EfiMnt = Get-EfiMountLetter; Test-BootMgrBinary -sources $sources -EfiMnt $EfiMnt Add-AdlGrubTheme -sources $sources -EfiMnt $EfiMnt; Write-Verbose "adding grub boot manager to bios boot order and fixing built-in bootmgr to use grub boot manager" Remove-FwBootEntry; Set-BcdBootMgrPath; Set-FirstFwBootOption; Remove-RunOnceBootOptions; Dismount-EFI; Remove-Item -Force -Recurse $sources; return;
-
-
- functions.psm1
-
function Remove-OldGrubFiles { [CmdletBinding()] param ( $EfiMnt ) process { Write-Verbose "removing any current grub files for fresh install" if ((Test-Path "C:\grub2")) { #grub2 path already exists remove it "Removing C:\grub2" | OUt-HOst; Remove-Item -Force -Recurse C:\grub2; } if ((Test-Path "$EfiMnt\EFI\grub2win")) { "Removing old grub2 EFI Files" | Out-host; Remove-Item -Force -Recurse "$EfiMnt\EFI\grub2win"; } } } function Add-AdlGrubTheme { [CmdletBinding()] param ( $sources, $EfiMnt ) process { Copy-Item "$sources\themes\*" "C:\grub2\themes\" -force -recurse; Copy-Item "$sources\themes\*" "$EfiMnt\EFI\Grub2win\themes\" -force -recurse; } } function Add-EFITools { [CmdletBinding()] param ( $Sources, $EfiMnt ) process { Write-Verbose "Adding efi binary tools and drivers" New-Dir "$EfiMnt\EFI\Tools\"; New-Dir "$EfiMnt\EFI\boot\"; Copy-Item "$sources\refind\tools\*" "$EfiMnt\EFI\Tools\" -Force; Copy-Item "$sources\refind\boot\*" "$EfiMnt\EFI\boot\" -Force -Recurse; Write-Verbose "downloading latest fog ipxe file" Invoke-WebRequest -Uri "http://arrowfog/ipxe.efi" -OutFile "$EfiMnt\EFI\ipxe-latest.efi"; } } function Test-BootMgrBinary { [CmdletBinding()] param ( $Sources, $EfiMnt ) process { if (!(Test-Path "$EfiMnt\EFI\Grub2Win\g2bootmgr\gnugrub.kernel*.efi")) { Write-Verbose "boot manager binary is missing, re-copying the grub boot binary files"; Copy-Item "$sources\g2bootmgr\*" "$EfiMnt\EFI\Grub2Win\g2bootmgr\" -force; } } } function Get-BCDEntry { [CmdletBinding()] param ( $searchString = "Grub2Win EFI - 64 Bit" ) process { return (bcdedit /enum all | select-string $searchString -Context 5,1); #get the grub bootmgr entry from all bcd options } } function Get-BcdGUID { [CmdletBinding()] param ( $bcdEntry = (Get-BCDEntry) ) process { return ($bcdEntry.ToString().split([Environment]::NewLine) | ? { $_ -match 'id' }).Replace("identifier","").trim(); #get the guid of the grub bootmgr entry } } function Remove-FwBootEntry { [CmdletBinding()] param ( $bcdEntry = (Get-BCDEntry) ) process { $guid = Get-BcdGUID -bcdEntry $bcdEntry; $fwboot = bcdedit /enum "{fwbootmgr}" if ($null -ne $guid) { if ($fwboot -match $guid) { return (bcdedit /set "{fwbootmgr}" displayorder $grubID /remove); #remove the grub boot manager created by the installer from boot order as it isn't universally compatible } else { "guid was not in {fwbootmgr}" | OUt-Host; } } else { "guid not found" | OUt-Host; return $null; } } } function Set-BcdBootMgrPath { [CmdletBinding()] param ( $path = "\EFI\Grub2Win\g2bootmgr\gnugrub.kernel64.efi" ) process { return (bcdedit /set "{bootmgr}" path $path) #set the default bootmanager to the grub efi file path } } function Set-FirstFwBootOption { [CmdletBinding()] param ( $bootOptionName = "{bootmgr}" ) process { return (bcdedit /set "{fwbootmgr}" displayorder $bootOptionName /addfirst); #set the edited bootmanager to the first boot option } } function Remove-RunOnceBootOptions { [CmdletBinding()] param ( ) process { $fwboot = bcdedit /enum "{fwbootmgr}" if ($fwboot -match "bootsequence") { $result = (bcdedit /deletevalue "{fwbootmgr}" bootsequence); #remove any run once boot options } else { $result = "bootsequence value not present"; } return $result; } } function Dismount-Efi { <# .SYNOPSIS Dismounts the EFI system partition if it is currently mounted .DESCRIPTION Gets the efi partition mount letter and dismounts it with the mountvol tool #> [CmdletBinding()] param () process { $mountLtr=(Get-EfiMountLetter) if ($null -eq $mountLtr) { Write-Debug "EFI Partition is not mounted"; return $null } else { $mountVol = "C:\Windows\System32\mountvol.exe"; return Start-Process -FilePath $mountVol -Wait -NoNewWindow -ArgumentList @($mountLtr, '/D'); } } } function Get-EfiMountLetter { <# .SYNOPSIS If the EFI partition is mounted this returns the current drive letter .DESCRIPTION Runs the mountvol.exe tool and parses out the string at the end of the output that states if and where the EFI system partition is mounted #> [CmdletBinding()] [Alias('Get-EfiMountLtr','Get-EfiMountPath')] param ( ) process { $mountVol = "C:\Windows\System32\mountvol.exe"; #test if mountvol already has mounted a EFI partition somewhere and dismount it $mountVolStr = (& $mountVol) $currentEfiMountStr = ($mountVolStr | Select-String "EFI System Partition is mounted at"); if ($null -ne $currentEfiMountStr) { #get the substring starting at the index of the character before ':' in the drive name $currentEfiMountLtr = $currentEfiMountStr.ToString().Substring(($currentEfiMountStr.ToString().indexOf(':'))-1,2); if ($null -ne $currentEfiMountLtr) { return $currentEfiMountLtr; } } Write-Debug "EFI partition is not currently mounted"; return $null } }
-
-
- sources folder
- Contents of install folder with altered basic.cfg file from the install grub2win step. I also have customizations to the theme (like a fog icon) and have some other customizations, but the ones I described here are all you need to make it function.
- sources folder
-
Hopefully that is helpful information. Probably more information than you ever wanted.
- make a symlink on the fog server to be able to download the ipxe.efi file
-
@sebastian-roth said in Copy ipxe.efi to uefi partition?:
Does Windows actually use the filename bootx64.efi I wonder?
Understand I’m speaking out of ignorance here, but how would the UEFI firmware know we wanted to boot windows over some other operating system (the uefi boot menu may be the answer to that). I would think the uefi firmware would look for the bootx64.efi image and that would tell the uefi firmware to chain to bootmgfw.efi. At least that is how I would think it should work.
-
@george1421 I’m pretty sure bootmgfw.efi is a bootmanager like refind and grub, it just doesn’t have a gui. And it chains bootx64.efi to boot to windows. From what I remember, trying to manually boot to bootx64.efi to get into windows doesn’t work, or doesn’t always work. So you want to use bootmgfw.efi to get into windows.
There’s probably a way to enable a gui on the windows 10 bootloader like you could in windows 7 and 8 and add additional boot options to it, but I haven’t found anything that works reliably or that would be easy to maintain. So I just started using different bootloaders which eradicated any issues I ever had with the windows bootloader randomly breaking and with added bonuses of not needing to try to get keystrokes in fast enough during initial boot to get to bios settings or fog. -
@george1421 said in Copy ipxe.efi to uefi partition?:
how would the UEFI firmware know we wanted to boot windows
Because the setup will set a UEFI entry pointing to that file…
-
@sebastian-roth Thanks!
That worked for me. I would also note that this is Windows 10 1607 Enterprise LTSB.
that could be why the partition is not partition 1? -
@jj-fullmer I will have to try this when I have more time because simply copying the ipxe.efi from fog over to the uefi partition works great for when the machine is on the network, but if its not connected to the LAN it wont boot to windows its caught in an IPXE boot loop.
-
@greg-plamondon That is one of the reasons I set this up, we have some wifi only devices, setting them to default boot to lan just doesn’t work. Also users get confused and or complain about the time it takes for the lan boot. So I set up a custom boot manager and got the best of all worlds.
I did recently accidentally (so sadly not sure how to recreate it) find that the windows boot manager does still have a gui mode. So you could theoretically create this functionality without the use of third party tools. I discovered it when I imaged a computer that had 2 drives. I imaged the nvme in a desktop that had a old spinning drive that still had a windows install on it and windows saw the old spinning drive’s install first and kept booting to that. At some point I had a windows boot menu that showed both windows options. So there is still a way to add custom boot entries to the windows boot manager. Probably a mix of enabling the timeout in bcd bootmgr settings and then adding a custom boot option. So you could theoretically make it so you see an option for straight windows boot and straight fog ipxe.efi file boot. Personally I like using grub, but just wanted to let people know it’s an option someone could try to figure out.