├── README.md └── fix-uefi-boot-order.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | This powershell script modifies the local system's UEFI/GPT boot order by finding the first non-Windows entry and moving it to the top of the order. 3 | 4 | # Context 5 | When using UEFI+GPT, the Windows installation (since Windows 7?) creates its own boot device entry (`Windows Boot Manager`, a.k.a. `{bootmgr}`) in the UEFI/GPT boot order list and, obnoxiously, takes the liberty of moving said entry to the top of the list. Under most circumstances, this is fine, and probably desirable. However for systems used for repeated deployment testing, or systems which you want a different bootloader to take priority (such as dual-boot systems, or computer lab systems that can be remotely re-imaged), this is a show stopper. So I needed a way to do this programmatically. 6 | 7 | # Behavior 8 | This script makes use of the arcane and undocumented `{fwbootmgr}` (not to be confused with `{bootmgr}` noted above) identifier implemented by bcdedit to find the first non-Windows boot device entry in the UEFI/GPT boot order list and move it to the top of the list. 9 | 10 | As far as I can tell, bcdedit provides no way to pull the friendly names of the devices in the overall UEFI boot order list. Therefore, this script simply identifies the first entry in the list which is NOT `{bootmgr}` (a.k.a. "Windows Boot Manager"), and moves it to the top of the list. 11 | 12 | It's up to the user to make sure the boot order exists in a state before the script is run, such that the desired result is achieved. 13 | 14 | In my case: 15 | - My test UEFI VMs initially have the boot order of: 16 | - 1 - `EFI Network` 17 | - 2 - whatever else 18 | - When Windows is installed with GPT partitioning, it changes the boot order to: 19 | - 1 - `Windows Boot Manager` 20 | - 2 - `EFI Network` 21 | - 3 - whatever else 22 | - In that state, this script can be used to change the boot order to: 23 | - 1 - `EFI Network` 24 | - 2 - `Windows Boot Manager` 25 | - 3 - whatever else 26 | 27 | # Sources 28 | Here are some sources I used in my research: 29 | - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/ 30 | - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi 31 | - https://www.boyans.net/DownloadVisualBCD.html 32 | - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings 33 | - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows 34 | 35 | # Notes 36 | - Only tested on Windows Powershell 5.1. 37 | - This functionality relies on the completely undocumented feature of bcdedit to modify the `{fwbootmgr}` GPT entry, which contains the overall list of UEFI boot devices. As far as I can tell, bcdedit is really only designed to edit Windows' own `{bootmgr}` entry which represents one of the "boot devices" in the overall UEFI list. 38 | - There's very little point in using this on regular production machines being deployed. Its main use is for machines being repeatedly imaged, or might be useful for computer lab machines. 39 | - By mseng3. See my other projects here: https://github.com/mmseng/code-compendium. 40 | -------------------------------------------------------------------------------- /fix-uefi-boot-order.ps1: -------------------------------------------------------------------------------- 1 | # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top 2 | # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs 3 | # by mmseng 4 | # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order 5 | 6 | # Notes: 7 | # - There's very little point in using this on regular production machines being deployed. Its main use is for machines being repeatedly imaged, or might be useful for lab machines. 8 | # - AFAICT bcdedit provideds no way to pull the friendly names of the devices in the overall UEFI boot order list. Therefore, this script only moves the first entry it identifies in the list which is NOT "{bootmgr}" (a.k.a. "Windows Boot Manager"). It's up to the user to make sure the boot order will exist in a state where the desired result is achieved. 9 | # - In my case, my test UEFI VMs initially have the boot order of 1) "EFI Network", 2) whatever else. When Windows is installed with GPT partitioning, it changes the boot order to 1) "Windows Boot Manager", 2) "EFI Network", 3) whatever else. In that state, this script can be used to change the boot order to 1) "EFI Network", 2) "Windows Boot Manager", 3) whatever else. 10 | # - This functionality relies on the completely undocumented feature of bcdedit to modify the "{fwbootmgr}" GPT entry, which contains the overall list of UEFI boot devices. 11 | # - AFAICT bcdedit is really only designed to edit Windows' own "{bootmgr}" entry which represents one of the "boot devices" in the overall UEFI list. 12 | # - Here are some sources: 13 | # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/ 14 | # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi 15 | # - https://www.boyans.net/DownloadVisualBCD.html 16 | # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings 17 | # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows 18 | 19 | 20 | # Read current boot order 21 | echo "Reading current boot order..." 22 | $bcdOutput = cmd /c bcdedit /enum "{fwbootmgr}" 23 | echo $bcdOutput 24 | 25 | # Kill as many of the stupid characters as possible 26 | echo "Removing extraneous characters from boot order output..." 27 | $bcdOutput = $bcdOutput -replace '\s+','' 28 | $bcdOutput = $bcdOutput -replace '`t','' 29 | $bcdOutput = $bcdOutput -replace '`n','' 30 | $bcdOutput = $bcdOutput -replace '`r','' 31 | $bcdOutput = $bcdOutput.trim() 32 | $bcdOutput = $bcdOutput.trimEnd() 33 | $bcdOutput = $bcdOutput.trimStart() 34 | $bcdOutput = $bcdOutput -replace ' ','' 35 | echo $bcdOutput 36 | 37 | # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list 38 | # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor) 39 | # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions 40 | # Even then, .NET regex testers I used didn't match the behavior of what I got out of various Powershell commands that accept regex strings 41 | # However this seems to work, even though I can't replicate the results in any regex testers 42 | $regex = [regex]'^{([\-a-z0-9]+)+}' 43 | echo "Defined regex as: $regex" 44 | 45 | # Save matches 46 | echo "Save strings matching regex..." 47 | $foundMatches = $bcdOutput -match $regex 48 | 49 | # Grab first match 50 | # If Windows Boot Manager (a.k.a. "{bootmgr}" was the first in the list, this should be the second 51 | # Which means it was probably the first before Windows hijacked the first spot 52 | # Which means it was probably my "EFI Network" boot device 53 | $secondBootEntry = $foundMatches[0] 54 | echo "First match: $secondBootEntry" 55 | 56 | # Move it to the first spot 57 | echo "Running this command:" 58 | echo "cmd /c bcdedit $bcdParams /set `"{fwbootmgr}`" displayorder $secondBootEntry /addfirst" 59 | cmd /c bcdedit $bcdParams /set "{fwbootmgr}" displayorder $secondBootEntry /addfirst 60 | --------------------------------------------------------------------------------