How do I get the same result as I get with bcdedit

2019-08-27 18:45发布

问题:

I'm trying to get the same information as I get with the bcdedit command "bcdedit /enum ALL" but using wmi and C#. I know how to get the bootmgr entries (see code) but I can't get all entries, especially the device options is the information I'm looking for. Does anyone have an idea how to achieve that?

This is the code I'm using to get the standard and legacy os boot entries.

    public class BCDWMI
{
    public static readonly UInt32 BCDE_STANDARD_OS_ENTRY = 0x10200003;
    public static readonly UInt32 BCDE_LEGACY_OS_ENTRY = 0x10300006;
    public static readonly UInt32 BcdLibraryElementTypeString_Description = 0x12000004;

    public static Dictionary<string, string> EnumerateObjectsByType(uint bcdType, string storePath)
    {

        Dictionary<string, string> dictEntries = null;

        ConnectionOptions options = new ConnectionOptions();
        options.Impersonation = ImpersonationLevel.Impersonate;
        options.EnablePrivileges = true;
        ManagementScope MgmtScope = new ManagementScope("root\\WMI", options);
        ManagementPath MgmtPath = new ManagementPath("root\\WMI:BcdStore.FilePath='" + storePath + "'");
        ManagementObject bcdStore = new System.Management.ManagementObject(MgmtScope, MgmtPath, null);
        ManagementBaseObject[] mboArray;

        bool success = EnumerateObjects(bcdStore, bcdType, out mboArray);
        if (success)
        {
            dictEntries = new Dictionary<string, string>();

            foreach (ManagementBaseObject mbo in mboArray)
            {
                ManagementPath BcdObjectPath = new ManagementPath("root\\WMI:BcdObject.Id=\"" + mbo.GetPropertyValue("Id") + "\",StoreFilePath='" + storePath + "'");

                ManagementObject BcdObject = new ManagementObject(MgmtScope, BcdObjectPath, null);
                ManagementBaseObject Element;
                String Description = String.Empty;
                try
                {
                    bool getDescripStatus = GetElement(BcdObject, BcdLibraryElementTypeString_Description, out Element);
                    if (getDescripStatus)
                        Description = Element.GetPropertyValue("String").ToString();
                }
                catch (Exception)
                {
                }
                dictEntries.Add((string)mbo.GetPropertyValue("Id"), String.Format("Type: {0:X8} {1}", mbo.GetPropertyValue("Type"), Description));
            }
        }
        return dictEntries;
    }

    public static bool EnumerateObjects(ManagementObject bcdStore, uint Type, out System.Management.ManagementBaseObject[] Objects)
    {
        System.Management.ManagementBaseObject inParams = null;
        inParams = bcdStore.GetMethodParameters("EnumerateObjects");
        inParams["Type"] = ((uint)(Type));
        System.Management.ManagementBaseObject outParams = bcdStore.InvokeMethod("EnumerateObjects", inParams, null);
        Objects = ((System.Management.ManagementBaseObject[])(outParams.Properties["Objects"].Value));
        return System.Convert.ToBoolean(outParams.Properties["ReturnValue"].Value);
    }

    public static bool GetElement(ManagementObject bdcObject, uint Type, out System.Management.ManagementBaseObject Element)
    {
        System.Management.ManagementBaseObject inParams = null;
        inParams = bdcObject.GetMethodParameters("GetElement");
        inParams["Type"] = ((uint)(Type));
        System.Management.ManagementBaseObject outParams = bdcObject.InvokeMethod("GetElement", inParams, null);
        Element = ((System.Management.ManagementBaseObject)(outParams.Properties["Element"].Value));
        return System.Convert.ToBoolean(outParams.Properties["ReturnValue"].Value);
    }
}

To query the system store, I call the function like this.

            Dictionary<string, string> StdOSEntries = BCDWMI.EnumerateObjectsByType(BCDWMI.BCDE_STANDARD_OS_ENTRY, String.Empty);
        foreach (String guid in StdOSEntries.Keys)
            Debug.WriteLine(String.Format("Id={0} {1}", guid,  StdOSEntries[guid]));

回答1:

If you need to learn the type value of a boot entry you are interested in, you can use bcdedit.exe to look up the GUID of that entry, and then load that entry in your program putting the GUID in ManagementPath like you do in:

ManagementPath BcdObjectPath = new ManagementPath("root\\WMI:BcdObject.Id=\"" + "{Guid goes here}" + "\",StoreFilePath='" + storePath + "'");

then get the value of a Type property like this:

uint Type = (uint)BcdObject["Type"];
Console.WriteLine("{0:X8}", Type);

In case if bcdedit.exe shows "well known" identifier like {current} or {bootmgr}, use this document to map the identifier to a GUID.

You can also enumerate types programmatically like this:

for (uint a = 1; a <= 10; a++) {
    uint FirmwareType = 0x10100000 | a;
    uint BootType = 0x10200000 | a;
    uint LegacyType = 0x10300000 | a;
    uint RealModeType = 0x10400000 | a;
}

which will give identifiers like you have here

public static readonly UInt32 BCDE_STANDARD_OS_ENTRY = 0x10200003;
public static readonly UInt32 BCDE_LEGACY_OS_ENTRY = 0x10300006;

See WMI documentation on BcdObject class for description of how those identifiers are formed.



回答2:

I found the solution. As almost always, it's quite obvious and simple. I just passed 0x0 as Type to the call.

Dictionary<string, string> StdOSEntries = BCDWMI.EnumerateObjectsByType(0, String.Empty);

And this is what I get.

    Id: {0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9} Type: 20100000 
Id: {4636856e-540f-4170-a130-a84776f4c654} Type: 20100000 
Id: {6efb52bf-1766-41db-a6b3-0ee5eff72bd7} Type: 20200003 
Id: {7619dcc8-fafe-11d9-b411-000476eba25f} Type: 30000000 
Id: {7619dcc9-fafe-11d9-b411-000476eba25f} Type: 10200003 Windows Setup 
Id: {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e} Type: 20100000 
Id: {7ff607e0-4395-11db-b0de-0800200c9a66} Type: 20200003 Hypervisor Settings
Id: {9dea862c-5cdd-4e70-acc1-f32b344d4795} Type: 10100002 Windows Boot Manager
Id: {a19f4228-8f0e-11e7-ac85-005056c00008} Type: 30000000 
Id: {a1c5dee9-8f0e-11e7-ac85-005056c00008} Type: 10200003 WinPE x86
Id: {a20de869-8f0e-11e7-ac85-005056c00008} Type: 10200003 WinPE amd64
Id: {b2721d73-1db4-4c62-bf78-c548a880142d} Type: 10200005 Windows Memory Diagnostic

My device options now are listed with the type 0x30000000. So if I pass 0x30000000 the function will return the two devices.



标签: c# wmi bcd