How do I stop Windows 10 Install from modifying BIOS boot settings? The Next CEO of Stack OverflowChanging uEFI boot order from WindowsHow to PXE boot if BIOS does not suppport itCan't boot Windows Server 2012 from iSCSICreating a local partition with iPXEpxe boot uefi ends with pxe-e16: No offer received - ip helper address in placePXE boot windows PE from LinuxChanging uEFI boot order from WindowsUEFI iPXE boot into debian results in grub shellMDT v. 8443 + ADK v. 1703 = boot-order changed after Post Install using UEFIWDS + MDT How to avoid pxe boot loopHow to boot a UEFI based Windows OS via a Linux PXE server

Is there an analogue of projective spaces for proper schemes?

Why does standard notation not preserve intervals (visually)

MessageLevel in QGIS3

Complex fractions

In excess I'm lethal

What does convergence in distribution "in the Gromov–Hausdorff" sense mean?

How to start emacs in "nothing" mode (`fundamental-mode`)

Indicator light circuit

Workaholic Formal/Informal

How to transpose the 1st and -1th levels of arbitrarily nested array?

How do scammers retract money, while you can’t?

What exact does MIB represent in SNMP? How is it different from OID?

Novel about a guy who is possessed by the divine essence and the world ends?

Inappropriate reference requests from Journal reviewers

Bold, vivid family

Why do remote companies require working in the US?

Is there a way to save my career from absolute disaster?

How do I go from 300 unfinished/half written blog posts, to published posts?

How fast would a person need to move to trick the eye?

How did the Bene Gesserit know how to make a Kwisatz Haderach?

Rotate a column

multiple labels for a single equation

Help understanding this unsettling image of Titan, Epimetheus, and Saturn's rings?

FBX seems to be empty when imported into Blender



How do I stop Windows 10 Install from modifying BIOS boot settings?



The Next CEO of Stack OverflowChanging uEFI boot order from WindowsHow to PXE boot if BIOS does not suppport itCan't boot Windows Server 2012 from iSCSICreating a local partition with iPXEpxe boot uefi ends with pxe-e16: No offer received - ip helper address in placePXE boot windows PE from LinuxChanging uEFI boot order from WindowsUEFI iPXE boot into debian results in grub shellMDT v. 8443 + ADK v. 1703 = boot-order changed after Post Install using UEFIWDS + MDT How to avoid pxe boot loopHow to boot a UEFI based Windows OS via a Linux PXE server










3















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:



  1. 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.

  2. 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).









share|improve this question
























  • Are you using only BIOS or is it EFI?

    – Spooler
    Nov 7 '16 at 23:50











  • I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

    – Michael Hampton
    Nov 8 '16 at 0:07











  • Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

    – Spooler
    Nov 8 '16 at 0:48











  • @SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

    – aggieNick02
    Nov 8 '16 at 16:58






  • 1





    I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

    – Michael Hampton
    Nov 8 '16 at 17:06
















3















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:



  1. 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.

  2. 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).









share|improve this question
























  • Are you using only BIOS or is it EFI?

    – Spooler
    Nov 7 '16 at 23:50











  • I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

    – Michael Hampton
    Nov 8 '16 at 0:07











  • Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

    – Spooler
    Nov 8 '16 at 0:48











  • @SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

    – aggieNick02
    Nov 8 '16 at 16:58






  • 1





    I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

    – Michael Hampton
    Nov 8 '16 at 17:06














3












3








3








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:



  1. 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.

  2. 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).









share|improve this question
















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:



  1. 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.

  2. 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).






deployment pxe-boot mdt wim bcdedit






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 20 '17 at 10:16









Community

1




1










asked Nov 7 '16 at 23:47









aggieNick02aggieNick02

14119




14119












  • Are you using only BIOS or is it EFI?

    – Spooler
    Nov 7 '16 at 23:50











  • I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

    – Michael Hampton
    Nov 8 '16 at 0:07











  • Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

    – Spooler
    Nov 8 '16 at 0:48











  • @SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

    – aggieNick02
    Nov 8 '16 at 16:58






  • 1





    I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

    – Michael Hampton
    Nov 8 '16 at 17:06


















  • Are you using only BIOS or is it EFI?

    – Spooler
    Nov 7 '16 at 23:50











  • I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

    – Michael Hampton
    Nov 8 '16 at 0:07











  • Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

    – Spooler
    Nov 8 '16 at 0:48











  • @SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

    – aggieNick02
    Nov 8 '16 at 16:58






  • 1





    I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

    – Michael Hampton
    Nov 8 '16 at 17:06

















Are you using only BIOS or is it EFI?

– Spooler
Nov 7 '16 at 23:50





Are you using only BIOS or is it EFI?

– Spooler
Nov 7 '16 at 23:50













I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

– Michael Hampton
Nov 8 '16 at 0:07





I'm not sure you can. And it did this in Windows 7 when installed via UEFI too...

– Michael Hampton
Nov 8 '16 at 0:07













Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

– Spooler
Nov 8 '16 at 0:48





Some EFI allow you to prevent operating systems from updating the NVRAM, and this is controlled via a setting within "setup". That may be a simple solution to this, if you have that option.

– Spooler
Nov 8 '16 at 0:48













@SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

– aggieNick02
Nov 8 '16 at 16:58





@SmallLoanOf1M - that was an interesting idea - by this I'm guessing you mean setting a password to lock down being able to enter UEFI configuration at boot? On the Asrock and Gigabyte boards I tried, this unfortunately didn't work.

– aggieNick02
Nov 8 '16 at 16:58




1




1





I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

– Michael Hampton
Nov 8 '16 at 17:06






I was able to find some third party software (EasyUEFI) that can alter the UEFI boot order, but nothing for Windows that can do it in an automated fashion, which is what you would want. As for OS installation, every OS adds a boot entry to the UEFI boot order, but Windows is the only one I know of which moves it to the first position.

– Michael Hampton
Nov 8 '16 at 17:06











2 Answers
2






active

oldest

votes


















3














Learned the following:



  1. On Linux, this would be fairly straightforward, via efibootmgr

  2. EasyUEFI would let me do what I want too - command line support requires a fairly cheap license; but I don't feel great depending on a niche tool like it, especially if there are other options.


  3. bcdedit on a UEFI machine modifies UEFI settings. I think it would work.


  4. The UEFI spec for boot order isn't too complicated. The API is really just GetVariable/SetVariable with variables named BootOrder (to get/set the list of boot options in the order they'll be tried) and Boot#### (to get/set info about each boot option).

  5. I have no idea how I'd write a windows app against the UEFI API on windows (anyone?)


  6. Windows provides an API that, among other things, wraps UEFI's GetVariable/SetVariable.

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:



struct CloseHandleHelper

void operator()(void *p) const

CloseHandle(p);

;

BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)

HANDLE token;
if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
return FALSE;
std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
return FALSE;
tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);



then call



SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));


Next, get the list of boot options (a concatenation of uint16_t values):



const int BUFFER_SIZE = 4096;
BYTE bootOrderBuffer[BUFFER_SIZE];
DWORD bootOrderLength = 0;
const TCHAR bootOrderName[] = TEXT("BootOrder");
const TCHAR globalGuid[] = TEXT("8BE4DF61-93CA-11D2-AA0D-00E098032B8C");
DWORD bootOrderAttributes;
bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
if (bootOrderLength == 0)

std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
return 1;



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.



for (DWORD i = 0; i < bootOrderLength; i += 2)

std::wstringstream bootOptionNameBuilder;
bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
std::wstring bootOptionName(bootOptionNameBuilder.str());
BYTE bootOptionInfoBuffer[BUFFER_SIZE];
DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
if (bootOptionInfoLength == 0)

std::cout << "Failed getting option info for option at offset " << i << std::endl;
return 1;

uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
//First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
if (((*bootOptionInfoAttributes) & 0x1) != 0)

std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
// details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them




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:



 uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))

std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;

else

std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
return 1;






share|improve this answer
































    1














    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



    # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
    # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
    # by mmseng
    # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order

    # Notes:
    # - 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.
    # - 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.
    # - 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.
    # - 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.
    # - AFAICT bcdedit is really only designed to edit Windows' own "bootmgr" entry which represents one of the "boot devices" in the overall UEFI list.
    # - Here are some sources:
    # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
    # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
    # - https://www.boyans.net/DownloadVisualBCD.html
    # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
    # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows


    # Read current boot order
    echo "Reading current boot order..."
    $bcdOutput = cmd /c bcdedit /enum "fwbootmgr"
    echo $bcdOutput

    # Kill as many of the stupid characters as possible
    echo "Removing extraneous characters from boot order output..."
    $bcdOutput = $bcdOutput -replace 's+',''
    $bcdOutput = $bcdOutput -replace '`t',''
    $bcdOutput = $bcdOutput -replace '`n',''
    $bcdOutput = $bcdOutput -replace '`r',''
    $bcdOutput = $bcdOutput.trim()
    $bcdOutput = $bcdOutput.trimEnd()
    $bcdOutput = $bcdOutput.trimStart()
    $bcdOutput = $bcdOutput -replace ' ',''
    echo $bcdOutput

    # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
    # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
    # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
    # 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
    # However this seems to work, even though I can't replicate the results in any regex testers
    $regex = [regex]'^([-a-z0-9]+)+'
    echo "Defined regex as: $regex"

    # Save matches
    echo "Save strings matching regex..."
    $foundMatches = $bcdOutput -match $regex

    # Grab first match
    # If Windows Boot Manager (a.k.a. "bootmgr" was the first in the list, this should be the second
    # Which means it was probably the first before Windows hijacked the first spot
    # Which means it was probably my "EFI Network" boot device
    $secondBootEntry = $foundMatches[0]
    echo "First match: $secondBootEntry"

    # Move it to the first spot
    echo "Running this command:"
    echo "cmd /c bcdedit $bcdParams /set `"fwbootmgr`" displayorder $secondBootEntry /addfirst"
    cmd /c bcdedit $bcdParams /set "fwbootmgr" displayorder $secondBootEntry /addfirst





    share|improve this answer








    New contributor




    mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.




















      Your Answer








      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "2"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fserverfault.com%2fquestions%2f813695%2fhow-do-i-stop-windows-10-install-from-modifying-bios-boot-settings%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      Learned the following:



      1. On Linux, this would be fairly straightforward, via efibootmgr

      2. EasyUEFI would let me do what I want too - command line support requires a fairly cheap license; but I don't feel great depending on a niche tool like it, especially if there are other options.


      3. bcdedit on a UEFI machine modifies UEFI settings. I think it would work.


      4. The UEFI spec for boot order isn't too complicated. The API is really just GetVariable/SetVariable with variables named BootOrder (to get/set the list of boot options in the order they'll be tried) and Boot#### (to get/set info about each boot option).

      5. I have no idea how I'd write a windows app against the UEFI API on windows (anyone?)


      6. Windows provides an API that, among other things, wraps UEFI's GetVariable/SetVariable.

      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:



      struct CloseHandleHelper

      void operator()(void *p) const

      CloseHandle(p);

      ;

      BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)

      HANDLE token;
      if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
      return FALSE;
      std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
      TOKEN_PRIVILEGES tp;
      tp.PrivilegeCount = 1;
      if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
      return FALSE;
      tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
      return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);



      then call



      SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));


      Next, get the list of boot options (a concatenation of uint16_t values):



      const int BUFFER_SIZE = 4096;
      BYTE bootOrderBuffer[BUFFER_SIZE];
      DWORD bootOrderLength = 0;
      const TCHAR bootOrderName[] = TEXT("BootOrder");
      const TCHAR globalGuid[] = TEXT("8BE4DF61-93CA-11D2-AA0D-00E098032B8C");
      DWORD bootOrderAttributes;
      bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
      if (bootOrderLength == 0)

      std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
      return 1;



      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.



      for (DWORD i = 0; i < bootOrderLength; i += 2)

      std::wstringstream bootOptionNameBuilder;
      bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
      std::wstring bootOptionName(bootOptionNameBuilder.str());
      BYTE bootOptionInfoBuffer[BUFFER_SIZE];
      DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
      if (bootOptionInfoLength == 0)

      std::cout << "Failed getting option info for option at offset " << i << std::endl;
      return 1;

      uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
      //First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
      if (((*bootOptionInfoAttributes) & 0x1) != 0)

      std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
      bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
      // details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them




      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:



       uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
      uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
      std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
      if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))

      std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;

      else

      std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
      return 1;






      share|improve this answer





























        3














        Learned the following:



        1. On Linux, this would be fairly straightforward, via efibootmgr

        2. EasyUEFI would let me do what I want too - command line support requires a fairly cheap license; but I don't feel great depending on a niche tool like it, especially if there are other options.


        3. bcdedit on a UEFI machine modifies UEFI settings. I think it would work.


        4. The UEFI spec for boot order isn't too complicated. The API is really just GetVariable/SetVariable with variables named BootOrder (to get/set the list of boot options in the order they'll be tried) and Boot#### (to get/set info about each boot option).

        5. I have no idea how I'd write a windows app against the UEFI API on windows (anyone?)


        6. Windows provides an API that, among other things, wraps UEFI's GetVariable/SetVariable.

        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:



        struct CloseHandleHelper

        void operator()(void *p) const

        CloseHandle(p);

        ;

        BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)

        HANDLE token;
        if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
        return FALSE;
        std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
        return FALSE;
        tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
        return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);



        then call



        SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));


        Next, get the list of boot options (a concatenation of uint16_t values):



        const int BUFFER_SIZE = 4096;
        BYTE bootOrderBuffer[BUFFER_SIZE];
        DWORD bootOrderLength = 0;
        const TCHAR bootOrderName[] = TEXT("BootOrder");
        const TCHAR globalGuid[] = TEXT("8BE4DF61-93CA-11D2-AA0D-00E098032B8C");
        DWORD bootOrderAttributes;
        bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
        if (bootOrderLength == 0)

        std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
        return 1;



        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.



        for (DWORD i = 0; i < bootOrderLength; i += 2)

        std::wstringstream bootOptionNameBuilder;
        bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
        std::wstring bootOptionName(bootOptionNameBuilder.str());
        BYTE bootOptionInfoBuffer[BUFFER_SIZE];
        DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
        if (bootOptionInfoLength == 0)

        std::cout << "Failed getting option info for option at offset " << i << std::endl;
        return 1;

        uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
        //First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
        if (((*bootOptionInfoAttributes) & 0x1) != 0)

        std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
        bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
        // details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them




        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:



         uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
        uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
        std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
        if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))

        std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;

        else

        std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
        return 1;






        share|improve this answer



























          3












          3








          3







          Learned the following:



          1. On Linux, this would be fairly straightforward, via efibootmgr

          2. EasyUEFI would let me do what I want too - command line support requires a fairly cheap license; but I don't feel great depending on a niche tool like it, especially if there are other options.


          3. bcdedit on a UEFI machine modifies UEFI settings. I think it would work.


          4. The UEFI spec for boot order isn't too complicated. The API is really just GetVariable/SetVariable with variables named BootOrder (to get/set the list of boot options in the order they'll be tried) and Boot#### (to get/set info about each boot option).

          5. I have no idea how I'd write a windows app against the UEFI API on windows (anyone?)


          6. Windows provides an API that, among other things, wraps UEFI's GetVariable/SetVariable.

          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:



          struct CloseHandleHelper

          void operator()(void *p) const

          CloseHandle(p);

          ;

          BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)

          HANDLE token;
          if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
          return FALSE;
          std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
          TOKEN_PRIVILEGES tp;
          tp.PrivilegeCount = 1;
          if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
          return FALSE;
          tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
          return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);



          then call



          SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));


          Next, get the list of boot options (a concatenation of uint16_t values):



          const int BUFFER_SIZE = 4096;
          BYTE bootOrderBuffer[BUFFER_SIZE];
          DWORD bootOrderLength = 0;
          const TCHAR bootOrderName[] = TEXT("BootOrder");
          const TCHAR globalGuid[] = TEXT("8BE4DF61-93CA-11D2-AA0D-00E098032B8C");
          DWORD bootOrderAttributes;
          bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
          if (bootOrderLength == 0)

          std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
          return 1;



          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.



          for (DWORD i = 0; i < bootOrderLength; i += 2)

          std::wstringstream bootOptionNameBuilder;
          bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
          std::wstring bootOptionName(bootOptionNameBuilder.str());
          BYTE bootOptionInfoBuffer[BUFFER_SIZE];
          DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
          if (bootOptionInfoLength == 0)

          std::cout << "Failed getting option info for option at offset " << i << std::endl;
          return 1;

          uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
          //First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
          if (((*bootOptionInfoAttributes) & 0x1) != 0)

          std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
          bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
          // details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them




          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:



           uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
          uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
          std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
          if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))

          std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;

          else

          std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
          return 1;






          share|improve this answer















          Learned the following:



          1. On Linux, this would be fairly straightforward, via efibootmgr

          2. EasyUEFI would let me do what I want too - command line support requires a fairly cheap license; but I don't feel great depending on a niche tool like it, especially if there are other options.


          3. bcdedit on a UEFI machine modifies UEFI settings. I think it would work.


          4. The UEFI spec for boot order isn't too complicated. The API is really just GetVariable/SetVariable with variables named BootOrder (to get/set the list of boot options in the order they'll be tried) and Boot#### (to get/set info about each boot option).

          5. I have no idea how I'd write a windows app against the UEFI API on windows (anyone?)


          6. Windows provides an API that, among other things, wraps UEFI's GetVariable/SetVariable.

          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:



          struct CloseHandleHelper

          void operator()(void *p) const

          CloseHandle(p);

          ;

          BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)

          HANDLE token;
          if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
          return FALSE;
          std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
          TOKEN_PRIVILEGES tp;
          tp.PrivilegeCount = 1;
          if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
          return FALSE;
          tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
          return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);



          then call



          SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));


          Next, get the list of boot options (a concatenation of uint16_t values):



          const int BUFFER_SIZE = 4096;
          BYTE bootOrderBuffer[BUFFER_SIZE];
          DWORD bootOrderLength = 0;
          const TCHAR bootOrderName[] = TEXT("BootOrder");
          const TCHAR globalGuid[] = TEXT("8BE4DF61-93CA-11D2-AA0D-00E098032B8C");
          DWORD bootOrderAttributes;
          bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
          if (bootOrderLength == 0)

          std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
          return 1;



          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.



          for (DWORD i = 0; i < bootOrderLength; i += 2)

          std::wstringstream bootOptionNameBuilder;
          bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
          std::wstring bootOptionName(bootOptionNameBuilder.str());
          BYTE bootOptionInfoBuffer[BUFFER_SIZE];
          DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
          if (bootOptionInfoLength == 0)

          std::cout << "Failed getting option info for option at offset " << i << std::endl;
          return 1;

          uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
          //First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
          if (((*bootOptionInfoAttributes) & 0x1) != 0)

          std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
          bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
          // details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them




          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:



           uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
          uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
          std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
          if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))

          std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;

          else

          std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
          return 1;







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 9 '16 at 22:38

























          answered Nov 9 '16 at 22:23









          aggieNick02aggieNick02

          14119




          14119























              1














              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



              # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
              # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
              # by mmseng
              # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order

              # Notes:
              # - 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.
              # - 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.
              # - 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.
              # - 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.
              # - AFAICT bcdedit is really only designed to edit Windows' own "bootmgr" entry which represents one of the "boot devices" in the overall UEFI list.
              # - Here are some sources:
              # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
              # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
              # - https://www.boyans.net/DownloadVisualBCD.html
              # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
              # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows


              # Read current boot order
              echo "Reading current boot order..."
              $bcdOutput = cmd /c bcdedit /enum "fwbootmgr"
              echo $bcdOutput

              # Kill as many of the stupid characters as possible
              echo "Removing extraneous characters from boot order output..."
              $bcdOutput = $bcdOutput -replace 's+',''
              $bcdOutput = $bcdOutput -replace '`t',''
              $bcdOutput = $bcdOutput -replace '`n',''
              $bcdOutput = $bcdOutput -replace '`r',''
              $bcdOutput = $bcdOutput.trim()
              $bcdOutput = $bcdOutput.trimEnd()
              $bcdOutput = $bcdOutput.trimStart()
              $bcdOutput = $bcdOutput -replace ' ',''
              echo $bcdOutput

              # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
              # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
              # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
              # 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
              # However this seems to work, even though I can't replicate the results in any regex testers
              $regex = [regex]'^([-a-z0-9]+)+'
              echo "Defined regex as: $regex"

              # Save matches
              echo "Save strings matching regex..."
              $foundMatches = $bcdOutput -match $regex

              # Grab first match
              # If Windows Boot Manager (a.k.a. "bootmgr" was the first in the list, this should be the second
              # Which means it was probably the first before Windows hijacked the first spot
              # Which means it was probably my "EFI Network" boot device
              $secondBootEntry = $foundMatches[0]
              echo "First match: $secondBootEntry"

              # Move it to the first spot
              echo "Running this command:"
              echo "cmd /c bcdedit $bcdParams /set `"fwbootmgr`" displayorder $secondBootEntry /addfirst"
              cmd /c bcdedit $bcdParams /set "fwbootmgr" displayorder $secondBootEntry /addfirst





              share|improve this answer








              New contributor




              mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
              Check out our Code of Conduct.
























                1














                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



                # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
                # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
                # by mmseng
                # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order

                # Notes:
                # - 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.
                # - 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.
                # - 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.
                # - 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.
                # - AFAICT bcdedit is really only designed to edit Windows' own "bootmgr" entry which represents one of the "boot devices" in the overall UEFI list.
                # - Here are some sources:
                # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
                # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
                # - https://www.boyans.net/DownloadVisualBCD.html
                # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
                # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows


                # Read current boot order
                echo "Reading current boot order..."
                $bcdOutput = cmd /c bcdedit /enum "fwbootmgr"
                echo $bcdOutput

                # Kill as many of the stupid characters as possible
                echo "Removing extraneous characters from boot order output..."
                $bcdOutput = $bcdOutput -replace 's+',''
                $bcdOutput = $bcdOutput -replace '`t',''
                $bcdOutput = $bcdOutput -replace '`n',''
                $bcdOutput = $bcdOutput -replace '`r',''
                $bcdOutput = $bcdOutput.trim()
                $bcdOutput = $bcdOutput.trimEnd()
                $bcdOutput = $bcdOutput.trimStart()
                $bcdOutput = $bcdOutput -replace ' ',''
                echo $bcdOutput

                # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
                # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
                # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
                # 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
                # However this seems to work, even though I can't replicate the results in any regex testers
                $regex = [regex]'^([-a-z0-9]+)+'
                echo "Defined regex as: $regex"

                # Save matches
                echo "Save strings matching regex..."
                $foundMatches = $bcdOutput -match $regex

                # Grab first match
                # If Windows Boot Manager (a.k.a. "bootmgr" was the first in the list, this should be the second
                # Which means it was probably the first before Windows hijacked the first spot
                # Which means it was probably my "EFI Network" boot device
                $secondBootEntry = $foundMatches[0]
                echo "First match: $secondBootEntry"

                # Move it to the first spot
                echo "Running this command:"
                echo "cmd /c bcdedit $bcdParams /set `"fwbootmgr`" displayorder $secondBootEntry /addfirst"
                cmd /c bcdedit $bcdParams /set "fwbootmgr" displayorder $secondBootEntry /addfirst





                share|improve this answer








                New contributor




                mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                Check out our Code of Conduct.






















                  1












                  1








                  1







                  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



                  # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
                  # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
                  # by mmseng
                  # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order

                  # Notes:
                  # - 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.
                  # - 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.
                  # - 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.
                  # - 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.
                  # - AFAICT bcdedit is really only designed to edit Windows' own "bootmgr" entry which represents one of the "boot devices" in the overall UEFI list.
                  # - Here are some sources:
                  # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
                  # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
                  # - https://www.boyans.net/DownloadVisualBCD.html
                  # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
                  # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows


                  # Read current boot order
                  echo "Reading current boot order..."
                  $bcdOutput = cmd /c bcdedit /enum "fwbootmgr"
                  echo $bcdOutput

                  # Kill as many of the stupid characters as possible
                  echo "Removing extraneous characters from boot order output..."
                  $bcdOutput = $bcdOutput -replace 's+',''
                  $bcdOutput = $bcdOutput -replace '`t',''
                  $bcdOutput = $bcdOutput -replace '`n',''
                  $bcdOutput = $bcdOutput -replace '`r',''
                  $bcdOutput = $bcdOutput.trim()
                  $bcdOutput = $bcdOutput.trimEnd()
                  $bcdOutput = $bcdOutput.trimStart()
                  $bcdOutput = $bcdOutput -replace ' ',''
                  echo $bcdOutput

                  # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
                  # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
                  # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
                  # 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
                  # However this seems to work, even though I can't replicate the results in any regex testers
                  $regex = [regex]'^([-a-z0-9]+)+'
                  echo "Defined regex as: $regex"

                  # Save matches
                  echo "Save strings matching regex..."
                  $foundMatches = $bcdOutput -match $regex

                  # Grab first match
                  # If Windows Boot Manager (a.k.a. "bootmgr" was the first in the list, this should be the second
                  # Which means it was probably the first before Windows hijacked the first spot
                  # Which means it was probably my "EFI Network" boot device
                  $secondBootEntry = $foundMatches[0]
                  echo "First match: $secondBootEntry"

                  # Move it to the first spot
                  echo "Running this command:"
                  echo "cmd /c bcdedit $bcdParams /set `"fwbootmgr`" displayorder $secondBootEntry /addfirst"
                  cmd /c bcdedit $bcdParams /set "fwbootmgr" displayorder $secondBootEntry /addfirst





                  share|improve this answer








                  New contributor




                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.










                  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



                  # This script looks for the first non-Windows Boot Manager entry in the UEFI/GPT boot order and moves it to the top
                  # For preventing newly installed Windows from hijacking the top boot order spot on my UEFI/GPT image testing VMs
                  # by mmseng
                  # https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order

                  # Notes:
                  # - 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.
                  # - 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.
                  # - 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.
                  # - 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.
                  # - AFAICT bcdedit is really only designed to edit Windows' own "bootmgr" entry which represents one of the "boot devices" in the overall UEFI list.
                  # - Here are some sources:
                  # - https://www.cnet.com/forums/discussions/bugged-bcdedit-349276/
                  # - https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi
                  # - https://www.boyans.net/DownloadVisualBCD.html
                  # - https://serverfault.com/questions/813695/how-do-i-stop-windows-10-install-from-modifying-bios-boot-settings
                  # - https://serverfault.com/questions/714337/changing-uefi-boot-order-from-windows


                  # Read current boot order
                  echo "Reading current boot order..."
                  $bcdOutput = cmd /c bcdedit /enum "fwbootmgr"
                  echo $bcdOutput

                  # Kill as many of the stupid characters as possible
                  echo "Removing extraneous characters from boot order output..."
                  $bcdOutput = $bcdOutput -replace 's+',''
                  $bcdOutput = $bcdOutput -replace '`t',''
                  $bcdOutput = $bcdOutput -replace '`n',''
                  $bcdOutput = $bcdOutput -replace '`r',''
                  $bcdOutput = $bcdOutput.trim()
                  $bcdOutput = $bcdOutput.trimEnd()
                  $bcdOutput = $bcdOutput.trimStart()
                  $bcdOutput = $bcdOutput -replace ' ',''
                  echo $bcdOutput

                  # Define a reliable regex to capture the UUIDs of non-Windows Boot Manager devices in the boot order list
                  # This is difficult because apparently Powershell interprets regex is a fairly non-standard way (.NET regex flavor)
                  # https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions
                  # 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
                  # However this seems to work, even though I can't replicate the results in any regex testers
                  $regex = [regex]'^([-a-z0-9]+)+'
                  echo "Defined regex as: $regex"

                  # Save matches
                  echo "Save strings matching regex..."
                  $foundMatches = $bcdOutput -match $regex

                  # Grab first match
                  # If Windows Boot Manager (a.k.a. "bootmgr" was the first in the list, this should be the second
                  # Which means it was probably the first before Windows hijacked the first spot
                  # Which means it was probably my "EFI Network" boot device
                  $secondBootEntry = $foundMatches[0]
                  echo "First match: $secondBootEntry"

                  # Move it to the first spot
                  echo "Running this command:"
                  echo "cmd /c bcdedit $bcdParams /set `"fwbootmgr`" displayorder $secondBootEntry /addfirst"
                  cmd /c bcdedit $bcdParams /set "fwbootmgr" displayorder $secondBootEntry /addfirst






                  share|improve this answer








                  New contributor




                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.









                  share|improve this answer



                  share|improve this answer






                  New contributor




                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.









                  answered yesterday









                  mmsengmmseng

                  112




                  112




                  New contributor




                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.





                  New contributor





                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.






                  mmseng is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Server Fault!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fserverfault.com%2fquestions%2f813695%2fhow-do-i-stop-windows-10-install-from-modifying-bios-boot-settings%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      How to write a 12-bar blues melodyI-IV-V blues progressionHow to play the bridges in a standard blues progressionHow does Gdim7 fit in C# minor?question on a certain chord progressionMusicology of Melody12 bar blues, spread rhythm: alternative to 6th chord to avoid finger stretchChord progressions/ Root key/ MelodiesHow to put chords (POP-EDM) under a given lead vocal melody (starting from a good knowledge in music theory)Are there “rules” for improvising with the minor pentatonic scale over 12-bar shuffle?Confusion about blues scale and chords

                      What if the end-user didn't have the required library?What is setup.py?What is a clean, pythonic way to have multiple constructors in Python?What does Ruby have that Python doesn't, and vice versa?What is the reason for having '//' in Python?How do I create a namespace package in Python?How to package shared objects that python modules depend on?setuptools vs. distutils: why is distutils still a thing?Navigation in Windows 10 vs code not going to virtualenv library when the same library is installed at user levelPython create package for local usePackaging a project that uses multiple python versionsWhy is permission denied on pip install except for when “--user” is included at end of command?

                      Esgonzo ibérico Índice Descrición Distribución Hábitat Ameazas Notas Véxase tamén "Acerca dos nomes dos anfibios e réptiles galegos""Chalcides bedriagai"Chalcides bedriagai en Carrascal, L. M. Salvador, A. (Eds). Enciclopedia virtual de los vertebrados españoles. Museo Nacional de Ciencias Naturales, Madrid. España.Fotos