3

I need to be able to access the identifier GUID of the current running installation of Windows from the Boot Configuration Data Store using c#. It can be returned from the command line running:

bcdedit /enum {current} /v

The problem I have is that in c# if I try to directly run this command (even though the program is running as Administrator) I'm told that bcdedit does not exist. I'm using:

ProcessStartInfo procStartInfo = new ProcessStartInfo("bcdedit.exe", "/enum {current} /v");

The other thing that I have researched is using WMI but the only reference I have to doing so is http://msdn.microsoft.com/en-us/library/windows/desktop/aa362673(v=vs.85).aspx which isn't very helpful.

The best solution would be if I don't have to use bcdedit but instead could use native WMI classes. How would I find the current Windows Boot Loader identifier using C#?

L-Williams
  • 146
  • 1
  • 9
  • `ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c \"bcdedit /enum {current} /v\"");`. – M.Babcock Feb 18 '12 at 00:38
  • I tried that as well but cmd runs as a normal user instead of Administrator so it can't find bcdedit. I was able to make it run as Administrator by putting the username and password in the code but that's not what we wanted. Also, this will be used accross machines where the username and password may be different. – L-Williams Feb 18 '12 at 00:40
  • Did you try `procStartInfo.UseShellExecute = true;` with the code from your question? – M.Babcock Feb 18 '12 at 00:44
  • Yeah, I tried it with `procStartInfo.UseShellExecute = true;` and I also tried it with `procStartInfo.UseShellExecute = false;`. I've also tried it using `runas` as my process and `cmd` opening `bcdedit` as parameters. For some reason the processes are being created without Administrative priviledges though my c# code is running as Administrator. – L-Williams Feb 18 '12 at 00:48
  • Sign your application and set the `requestedExecutionLevel`, and it'll work. ([Source](http://msdn.microsoft.com/en-us/library/bb756929.aspx)) – M.Babcock Feb 18 '12 at 00:51
  • The application is signed and in the app.mainifest file the code was in place: `` but it still does not run correctly. The title of the command prompt that opens is "Administrator: c:\Windows\System32\cmd.exe" but it says `'bcdedit' is not recognized as an internal or external command, operable program or batch file.` When I run in a non-administrator command prompt normally it says `The boot configuration data store could not be opened.` so that's a little confusing as well. – L-Williams Feb 18 '12 at 01:04

2 Answers2

8

There seem to be many problems accessing bcdedit.exe directly but I was able to figure out how to use WMI in C# to access the BcdStore:

ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
connectionOptions.EnablePrivileges = true;

// The ManagementScope is used to access the WMI info as Administrator
ManagementScope managementScope = new ManagementScope(@"root\WMI", connectionOptions);

// {9dea862c-5cdd-4e70-acc1-f32b344d4795} is the GUID of the System BcdStore
ManagementObject privateLateBoundObject = new ManagementObject(managementScope, new ManagementPath("root\\WMI:BcdObject.Id=\"{9dea862c-5cdd-4e70-acc1-f32b344d4795}\",StoreFilePath=\"\""), null);

ManagementBaseObject inParams = null;
inParams = privateLateBoundObject.GetMethodParameters("GetElement");

// 0x24000001 is a BCD constant: BcdBootMgrObjectList_DisplayOrder
inParams["Type"] = ((UInt32)0x24000001);
ManagementBaseObject outParams = privateLateBoundObject.InvokeMethod("GetElement", inParams, null);
ManagementBaseObject mboOut = ((ManagementBaseObject)(outParams.Properties["Element"].Value));

string[] osIdList = (string[]) mboOut.GetPropertyValue("Ids");

// Each osGuid is the GUID of one Boot Manager in the BcdStore
foreach (string osGuid in osIdList)
{
    ManagementObject currentManObj = new ManagementObject(managementScope, new ManagementPath("root\\WMI:BcdObject.Id=\"" + osGuid + "\",StoreFilePath=\"\""), null);
            MessageBox.Show("" + currentManObj.GetPropertyValue("Id"));
}

This gets the GUID of every Windows Boot Manager in the BcdStore and shows them in a MessageBox. It should be noted that you must have the right ConnectionOptions and that this program must be run as Administrator.

Thanks to Ross Johnston for his project at: http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=18233 to find the BCD constants and to Tran Dinh Hop for his project at: http://www.codeproject.com/script/Articles/ViewDownloads.aspx?aid=19208 which has all of the C# code to work with the BcdStore (except for the aforementioned constants).

Update:

Using:

ManagementObject privateLateBoundObject = new ManagementObject(managementScope, new ManagementPath("root\\WMI:BcdObject.Id=\"{fa926493-6f1c-4193-a414-58f0b2456d1e}\",StoreFilePath=\"\""), null);

will obtain the BcdObject for the current, running Windows Boot Manager. If you then call:

currentManObj.GetPropertyValue("Id")

you will get the GUID of the current, running Windows Boot Manager which is different from "{fa926493-6f1c-4193-a414-58f0b2456d1e}" which is a link to the current Boot Manager.

Thanks to The Microsoft Scripting Guys and their project at: http://technet.microsoft.com/en-us/magazine/2008.07.heyscriptingguy.aspx?pr=blog for having that GUID constant that links to the current Boot Manager.

L-Williams
  • 146
  • 1
  • 9
  • 1
    Wow, I am surprised how little information on the "interweb" there is regarding this. I am trying to piece everything together. I am trying to use this to toggle back and forth from Safe to Normal mode. Any suggestions would be greatly appreciated. I do not want to use the command-line bcdedit, just purely C#. – Vippy Aug 13 '14 at 19:45
  • Using the BCD WMI Provider and with the help of L-Williams, was able get the exact code need to set BCD to safe mode: http://stackoverflow.com/questions/25295117/use-c-sharp-bcd-wmi-provider-to-safeboot-windows – Vippy Aug 15 '14 at 20:16
  • I get errors if I use PrintDocument with simple printing code AFTER calling your method: "Default printer is not set." And "No printers are installed." How to solve this? – user2241289 Aug 03 '17 at 11:12
  • I found the solution: set EnablePrivileges = False. – user2241289 Aug 03 '17 at 14:52
  • Note: this Id changed after windows 10 updated! but NOT after every update. – user2241289 Mar 29 '18 at 19:00
5

Note that there is only a 64-bit bcdedit.exe in %systemroot%\system32. If your app is 32-bit, it will not be able to launch the 64-bit bcdedit because the WOW64 layer remaps the system32\ directory to syswow64. It's definitely best to use the WMI interface.