Click here to Skip to main content
14,176,928 members
Click here to Skip to main content
Add your own
alternative version

Stats

25.7K views
11 bookmarked
Posted 1 Nov 2014
Licenced CPOL

Modify Windows BCD using Powershell

, 19 Feb 2018
Rate this:
Please Sign up or sign in to vote.
Working with Windows BCD store in Powershell

Introduction

This article will cover using the BCD (Boot Configuration Data) WMI provider to manipulate BCD stores from Powershell. Complete code for interacting with BCD stores, objects, and elements is provided. This article was taged as intermediate, not because of the difficulty of the code, but the subject matter.

Background

Because of the complexity of BCD, this article will not cover BCD in dept. The purpose of this article is to demonstrate tested techniques for managing BCD stores. For this article all BCD operations are conducted locally. Additionally, the WMI provider for BCD requires elevated privileges.

Warning:

Improper modification of a system BCD store can result in an unbootable operating system. Although the bcd.mof file was completely translated into Powershell functions for the code in this article, not all methods will be covered, nor have those methods not covered by this article been extensively tested. Before using a method not described in this article, consult the Microsoft documentation. Neither Microsoft, nor the author are responsible for how this code is used.

Accessing the BCD store

For this article, the WbemScripting.SWbemLocator object will be used to access the BCD provider. In a side by side comparison, a C# application using the System.Management namespace and a Powershell script using WbemScripting both use the same resources: wmiprvse, wmiutils, wbemsvc, wbemcomn2, wbemprox, bcdprov, and bcdsrv (among others). For Powershell, it is much easier to use WMI scripting API. By using only COM objects, a few (simple) functions are all that will be required to access the BCD WMI provider.

Getting an instance of the static class BcdStore:

function Get-StaticBcdStore {
    $SWbemLocator = New-Object -ComObject WbemScripting.SWbemLocator
    $wmi = $SWbemLocator.ConnectServer(".","root\wmi")
    $wmi.Get("BcdStore")
}

Four COM helper functions

Access to method parameters

function New-InParameter {
Param([Parameter(Position=0)]$Method, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Methods_.Item($Method).InParameters.SpawnInstance_()
}

Access to properties

function Get-PropertyValue {
Param([Parameter(Position=0)]$Property, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Properties_.Item($Property).Value
}
function Set-PropertyValue {
Param([Parameter(Position=0)]$Property, [Parameter(Position=1)]$Value, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Properties_.Item($Property).Value=$Value
}

Method execution and parameter returns

function Invoke-Method {
Param([Parameter(Position=0)]$Method, [Parameter(Position=1)]$ParameterNames, [Parameter(Position=2)]$ParameterValues,
    [Parameter(ValueFromPipeLine=$true)]$Object)
    if($ParameterNames -eq $null -or $ParameterValues -eq $null) {
        $Object.ExecMethod_($Method)
    }
    else {
        $in = New-InParameter $Method -Object $Object
        if($ParameterNames.GetType() -eq [System.String]) {
            $in | Set-PropertyValue $ParameterNames $ParameterValues
        }
        else {
            for($i = 0; $i -lt $ParameterNames.LongLength; $i++) {
                if($ParameterValues[$i] -ne $null) {
                    $in | Set-PropertyValue $ParameterNames[$i] $ParameterValues[$i]
                }
            }
        }
        $Object.ExecMethod_($Method, $in)
    }
}

Implementing BCD WMI Methods

All methods exposed by the BCD provider are available in the bcd.mof (Managed Object Format) file. For this article, and Powershell code provided, these are broken down into 3 main categories according to object relation: functions and properties relating only to BcdStore, functions and properties relating only to BcdObject, and functions and properties that relate to BcdElements along with properties which are shared. In implementing these methods, any out parameters are used as the function's return value, otherwise, the return is a boolean indicating the success or failure of an operation.

Working with the BCD store

To access a store and retrieve items, the following methods are used:

function Open-Store {
    Param(
        [Parameter(Position=0)][string]$File="",
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "OpenStore" "File" $File | Get-PropertyValue "Store"
}
function Open-Object {
    Param(
        [Parameter(Position=0)][string]$Id,
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "OpenObject" "Id" $Id | Get-PropertyValue "Object"
}
function Enumerate-Objects {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "EnumerateObjects" "Type" $Type | Get-PropertyValue "Objects"
}

To open a BCD store, the BCD file name must be specified. An empty string denotes the system store. Obtaining BCD objects requires the GUID Id of the object. Enumerating BCD objects requires an object type.

 

$bootmanager = Get-StaticBcdStore | Open-Store -file "" | Open-Object "{9dea862c-5cdd-4e70-acc1-f32b344d4795}"
$bootmanager.Properties_

In this example, the well-known GUID for the Windows Boot Manager is used to get the boot manager from the system store and the COM properties are out put. The result is just the BcdObject properties: Id which is the well-known GUID, StoreFilePath which is blank because it's in the system store, and Type which is 0x10100002.

In the previous example, the boot manager was retrieved explicitly by using the well-known GUID. However; it is also possible to retrieve this element using its type.

$bootmanagers = Get-StaticBcdStore | Open-Store "" | Enumerate-Objects ([uint32]"0x10100002")
$bootmanagers[0].Properties_

or

$bootmanagers = Get-StaticBcdStore | Open-Store "" | Enumerate-Objects ([uint32]"0x10000002")
$bootmanagers[0].Properties_

These examples point out the ability to enumerate objects by their type definitions. In the second example the object type was generalized to indicate any application type object with an application code of Windows boot manager.

To create a BCD store and BCD objects, the following two methods are used:

function Create-Store {
    Param(
        [Parameter(Position=0)][string]$File,
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CreateStore" "File" $File | Get-PropertyValue "Store"
}
function Create-Object {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][string]$Id,  
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CreateObject" "Id","Type" $Id,$Type | Get-PropertyValue "Object"
}

Like the OpenStore method, the CreateStore method of the BcdStore requires a file name. Creating objects in the BCD store requires a type and an optional GUID or well-known GUID.

Get-StaticBcdStore | Create-Store "$env:TEMP\BCD-Demo" `
    | Create-Object ([uint32]"0x10100001") "{a5a30fa2-3d06-4e9f-b5f4-a01df9d1fcba}"

In this example, the well-known GUID for Firmware Boot Manager and the object type for firmware boot manager are used to create: Firmware Boot Manager. The Id parameter is optional. To create new objects, pass only the object type, the objects Id will be populated with a GUID created by the provider. However, many objects, like this Firmware Boot Manager, can only be created with the well-known GUID and type combination.

Working with BCD objects

Setting elements requires methods provided by the BcdObject. What these methods have in common is the use of Type to define the object's element to be manipulated. Microsoft's MSDN has a fairly complete (although not always accurate) list of enumerations. By this, I mean that a few enumeration values may be defined as a specific type though they are not of that type, and other enumeration values that are missing--though they can be substituted with existing values.

The following methods are used to retrieve element data from BcdObjects:

function Enumerate-Elements {
    Param([Parameter(Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Invoke-Method "EnumerateElements" | Get-PropertyValue "Elements"
}
function Get-Element {
        Param([Parameter(Position=0)][uint32]$Type,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "GetElement" "Type" $Type | Get-PropertyValue "Element"
}
function Enumerate-ElementTypes {
    Param([Parameter(Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Invoke-Method "EnumerateElementTypes" | Get-PropertyValue "Types"
}

To get a list of elements, element types, and values all that needs to be done is this:

$bootmanager = Get-StaticBcdStore | Open-Store -file "" | Open-Object "{9dea862c-5cdd-4e70-acc1-f32b344d4795}"
$bootmanager | Enumerate-ElementTypes | % {
    (Get-Element -Type $_ -BcdObject $bootmanager).Properties_
}

As for setting element data, the following methods will be demonstrated later, but with names like SetBooleanElement and SetStringElement, they are self explanatory.

function Set-StringElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][string]$String,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetStringElement" "Type","String" $Type,$String | Get-PropertyValue "ReturnValue"
}
function Set-BooleanElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][bool]$Boolean,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetBooleanElement" "Type","Boolean" $Type,$Boolean | Get-PropertyValue "ReturnValue"
}
function Set-IntegerElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)]$Integer,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetIntegerElement" "Type","Integer" $Type,$Integer | Get-PropertyValue "ReturnValue"
}
function Set-ObjectElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][string]$Id,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetObjectElement" "Type","Id" $Type,$Id | Get-PropertyValue "ReturnValue"
}

A few methods will take an array of values, these should be passed using @().

function Set-ObjectListElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)]$Ids,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetObjectListElement" "Type","Ids" $Type,$Ids | Get-PropertyValue "ReturnValue"
}
function Set-IntegerListElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)]$Integers,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetIntegerListElement" "Type","Integers" $Type,$Integers | Get-PropertyValue "ReturnValue"
}

Setting device data is much more complex and will also be demonstrated later.

function Set-FileDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][int]$DeviceType,
        [Parameter(Position=2)][string]$AdditionalOptions,
        [Parameter(Position=3)][string]$Path,
        [Parameter(Position=4)][uint32]$ParentDeviceType,
        [Parameter(Position=5)][string]$ParentAdditionalOptions,
        [Parameter(Position=6)][string]$ParentPath,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions","Path","ParentDeviceType","ParentAdditionalOptions","ParentPath"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions,$Path,$ParentDeviceType,$ParentAdditionalOptions,$ParentPath
    $BcdObject | Invoke-Method "SetFileDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}
function Set-PartitionDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][int]$DeviceType,
        [Parameter(Position=2)][string]$AdditionalOptions,
        [Parameter(Position=3)][string]$Path,
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions","Path"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions,$Path
    $BcdObject | Invoke-Method "SetPartitionDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

More methods are provided by the BcdObject and included in the code later in this article, though not covered in this article.

Working with BCD elements

This last section covering BCD methods will deal with the actual elements of BCD objects. In the previous sections, we covered using the BcdStore object to open and create objects and briefly touched on using the BcdObject to set element data. To get specific information from an element, we have to access the element's properties. A string element has a property String, a boolean element has a property Boolean, and so on.

function Get-String {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStringElement)
    Get-PropertyValue "String" -Object $BcdStringElement
}
function Get-Integer {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdIntegerElement)
    Get-PropertyValue "Integer" -Object $BcdIntegerElement
}
function Get-Boolean {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdBooleanElement)
    Get-PropertyValue "Boolean" -Object $BcdBooleanElement
}

For object lists

function Get-Integers {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdIntegerListElement)
    Get-PropertyValue "Integers" -Object $BcdIntegerListElement
}
function Get-Ids {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObjectListElement)
    Get-PropertyValue "Ids" -Object $BcdObjectListElement
}

For device objects

function Get-Device {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceElement)
    $BcdDeviceElement | Get-PropertyValue "Device"
}

This will be the last demonstration for getting data from a BCD store. (Saving the best for last: getting device data.)

$mem = Get-StaticBcdStore | Open-Store "" | Open-Object "{b2721d73-1db4-4c62-bf78-c548a880142d}"
$dev = $mem | Get-Element -Type ([BcdLibraryElementTypes]::Device_ApplicationDevice) | Get-Device
$dev.Properties_

This example gets the Windows Memory Tester and retrieves the device data. This method is handy for evaluating properties for setting various device elements from code.

Finally, the good stuff

Now then...the ultimate goal of this article is to provide working examples for modifying a BCD store from Powershell.

Building a BCD store from scratch

For the first demonstration the output from bcdedit for a live system store is used to generate a new BCD store in code. The resulting BCD store is created on a drive that has been cleaned, reformated, and reimaged in a deployment senario. Much of bcdedit's output has been reorderd for object dependancy. Enumerators and well-known GUID variables are provided in the code at the end of this article.

 

. ("$PSScriptRoot\PowershellBcd.ps1")
Get-StaticBcdStore | Create-Store -File "$env:TEMP\BCD-TEMP" | Out-Null
$bcdFile = "S:\boot\BCD"
if(Test-Path $bcdFile) {
    Remove-Item -Path $bcdFile | Out-Null
}
$sDrive = Get-DosDevice "S:"
# Windows OS (will be C after reboot)
$cDrive = Get-DosDevice "W:"
$BcdStore = Get-StaticBcdStore | Create-Store -File $bcdFile
$BcdStore | Import-Store "$env:TEMP\BCD-TEMP" | Out-Null

*The BCD WMI provider does not seem to implement QueryDosDevice--unlike bcdedit, volume letters are not accepted when setting Device properties. Also, while building the BCD store from scratch results in a fully functional store, OS boots, hybernates, and resumes properly, booting to WinRE always results in a rebuild of the BCD store. To get the store just right, a "dummy" store has to be imported. This results in a properly functioning BCD store. (This solution was found at http://windowsitpro.com/systems-management/build-bootable-bcd-scratch-bcdedit)

EMS Settings
------------
identifier {0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}
bootems Yes
$BcdStore | Create-Object -Id $emssettings -Type ([uint32]"0x20100000") | `
    Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_EmsEnabled) 1 | Out-Null
Debugger Settings
-----------------
identifier {4636856e-540f-4170-a130-a84776f4c654}
debugtype Serial
debugport 1
baudrate 115200
$debugger = $BcdStore | Create-Object -Id $dbgsettings -Type ([uint32]"0x20100000")
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_DebuggerType) 0 | Out-Null
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_SerialDebuggerPort) 1 | Out-Null
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_SerialDebuggerBaudRate) 115200 | Out-Null
RAM Defects
-----------
identifier {5189b25c-5558-4bf2-bca4-289b11bd29e2}
$BcdStore | Create-Object -Id $badmemory -Type ([uint32]"0x20100000") | Out-Null
Global Settings
---------------
identifier {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
inherit {4636856e-540f-4170-a130-a84776f4c654}
  {0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}
  {5189b25c-5558-4bf2-bca4-289b11bd29e2}
$global = $BcdStore | Create-Object -Id $globalsettings -Type ([uint32]"0x20100000") | `
    Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) `
    @($dbgsettings,$emssettings,$badmemory) | Out-Null 
Resume Loader Settings
----------------------
identifier {1afa9c49-16ab-4a5c-901b-212802da9460}
inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
$BcdStore | Create-Object -Id $resumeloadersettings -Type ([uint32]"0x20200004") | `
        Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($globalsettings) | Out-Null
Hypervisor Settings
-------------------
identifier {7ff607e0-4395-11db-b0de-0800200c9a66}
hypervisordebugtype Serial
hypervisordebugport 1
hypervisorbaudrate 115200
$hypervisor = $BcdStore | Create-Object -Id $hypervisorsettings -Type ([uint32]"0x20200003")
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerType) 0 | Out-Null
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerPortNumber) 1 | Out-Null
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerBaudrate) 115200 | Out-Null
Boot Loader Settings
--------------------
identifier {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
  {7ff607e0-4395-11db-b0de-0800200c9a66}
$BcdStore | Create-Object -Id $bootloadersettings -Type ([uint32]"0x20200003") | `
    Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($globalsettings,$hypervisorsettings) | Out-Null
Windows Memory Tester
---------------------
identifier {b2721d73-1db4-4c62-bf78-c548a880142d}
device partition=S:
path \boot\memtest.exe
description Windows Memory Diagnostic
locale en-US
inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
badmemoryaccess Yes
$memorytester = $BcdStore | Create-Object -Id $memdiag -Type ([uint32]"0x10200005")
$memorytester | Set-PartitionDeviceElement ([BcdLibraryElementTypes]::Device_ApplicationDevice) 2 "" $sDrive | Out-Null
$memorytester | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) "\boot\memtest.exe" | Out-Null
$memorytester | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Windows Memory Diagnostic" | Out-Null
$memorytester | Set-StringElement ([BcdLibraryElementTypes]::String_PreferredLocale) "en-US" | Out-Null
$memorytester | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($globalsettings) | Out-Null
$memorytester | Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_AllowBadMemoryAccess) 1 | Out-Null
Resume from Hibernate
---------------------
identifier {ebe94447-1944-11e4-95c4-dd9a4e7158f6}
device partition=C:
path \windows\system32\winresume.exe
description Windows Resume Application
locale en-US
inherit {1afa9c49-16ab-4a5c-901b-212802da9460}
filedevice partition=C:
filepath \hiberfil.sys
debugoptionenabled No
$hibernate = $BcdStore | Create-Object ([uint32]"0x10200004")
# Get generated GUID
$resume = $hibernate | Get-Id
$hibernate | Set-PartitionDeviceElement ([BcdLibraryElementTypes]::Device_ApplicationDevice) 2 "" $cDrive | Out-Null
$hibernate | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) "\Windows\system32\winresume.exe" | Out-Null
$hibernate | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Windows Resume Application" | Out-Null
$hibernate | Set-StringElement ([BcdLibraryElementTypes]::String_PreferredLocale) "en-US" | Out-Null
$hibernate | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($resumeloadersettings) | Out-Null
$hibernate | Set-PartitionDeviceElement ([BcdOSLoaderElementTypes]::Device_OSDevice) 2 "" $cDrive | Out-Null
$hibernate | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\hiberfil.sys" | Out-Null
$hibernate | Set-BooleanElement ([BcdResumeElementTypes]::Boolean_DebugOptionEnabled) 0 | Out-Null
Device options
--------------
identifier {ebe9444a-1944-11e4-95c4-dd9a4e7158f6}
description Ramdisk Options
ramdisksdidevice partition=S:
ramdisksdipath \Recovery\WindowsRE\boot.sdi
$ramdisk = $BcdStore | Create-Object -Id $ramdiskopt -Type ([uint32]"0x30000000")
$ramdisk | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Ramdisk Options" | Out-Null
$ramdisk | Set-PartitionDeviceElement ([BcdDeviceObjectElementTypes]::Device_SdiDevice) 2 "" $sDrive | Out-Null
$ramdisk | Set-StringElement ([BcdDeviceObjectElementTypes]::String_SdiPath) "\Recovery\WindowsRE\boot.sdi" | Out-Null
Windows Boot Loader
-------------------
identifier {ebe94449-1944-11e4-95c4-dd9a4e7158f6}
device ramdisk=[S:]\Recovery\WindowsRE\Winre.wim,{ebe9444a-1944-11e4-95c4-dd9a4e7158f6}
path \windows\system32\winload.exe
description Windows Recovery Environment
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
osdevice ramdisk=[S:]\Recovery\WindowsRE\Winre.wim,{ebe9444a-1944-11e4-95c4-dd9a4e7158f6}
systemroot \windows
nx OptIn
winpe Yes
custom:46000010 Yes
$winre = $BcdStore | Create-Object ([uint32]"0x10200003")
# Get Generated GUID
$reLoader = $winre | Get-Id
$winre | Set-FileDeviceElement -Type ([BcdLibraryElementTypes]::Device_ApplicationDevice) -DeviceType 4 `
    -AdditionalOptions $ramdiskopt -Path "\Recovery\WindowsRE\Winre.wim" -ParentDeviceType 2 `
    -ParentAdditionalOptions "" -ParentPath $sDrive | Out-Null
$winre | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) "\Windows\system32\winload.exe" | Out-Null
$winre | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Windows Recovery Environment" | Out-Null
$winre | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($bootloadersettings) | Out-Null
$winre | Set-FileDeviceElement -Type ([BcdOSLoaderElementTypes]::Device_OSDevice) -DeviceType 4 `
    -AdditionalOptions $ramdiskopt -Path "\Recovery\WindowsRE\Winre.wim" -ParentDeviceType 2 `
    -ParentAdditionalOptions "" -ParentPath $sDrive | Out-Null
$winre | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\Windows" | Out-Null
$winre | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 0 | Out-Null
$winre | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null
$winre | Set-BooleanElement ([uint32]"0x46000010") 1 | Out-Null
Windows Boot Loader
-------------------
identifier {ebe94448-1944-11e4-95c4-dd9a4e7158f6}
device partition=C:
path \windows\system32\winload.exe
description Windows 7
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
recoverysequence {ebe94449-1944-11e4-95c4-dd9a4e7158f6}
recoveryenabled Yes
osdevice partition=C:
systemroot \windows
resumeobject {ebe94447-1944-11e4-95c4-dd9a4e7158f6}
nx OptIn
$loader = $BcdStore | Create-Object ([uint32]"0x10200003")
# Get generated GUID
$osLoader = $loader | Get-Id
$loader | Set-PartitionDeviceElement ([BcdLibraryElementTypes]::Device_ApplicationDevice) 2 "" $cDrive | Out-Null
$loader | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) "\Windows\system32\winload.exe" | Out-Null
$loader | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Windows 7" | Out-Null
$loader | Set-StringElement ([BcdLibraryElementTypes]::String_PreferredLocale) "en-US" | Out-Null
$loader | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($bootloadersettings) | Out-Null
$loader | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_RecoverySequence) @($reLoader) | Out-Null
$loader | Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_AutoRecoveryEnabled) 1 | Out-Null
$loader | Set-PartitionDeviceElement ([BcdOSLoaderElementTypes]::Device_OSDevice) 2 "" $cDrive | Out-Null
$loader | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\Windows" | Out-Null
$loader | Set-ObjectElement ([BcdOSLoaderElementTypes]::Object_AssociatedResumeObject) $resume | Out-Null
$loader | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 0 | Out-Null
Windows Boot Manager
--------------------
identifier {9dea862c-5cdd-4e70-acc1-f32b344d4795}
device partition=S:
description Windows Boot Manager
locale en-US
inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}
default {ebe94448-1944-11e4-95c4-dd9a4e7158f6}
resumeobject {ebe94447-1944-11e4-95c4-dd9a4e7158f6}
displayorder {ebe94448-1944-11e4-95c4-dd9a4e7158f6}
toolsdisplayorder {b2721d73-1db4-4c62-bf78-c548a880142d}
timeout 30
$bootManager = $BcdStore | Create-Object -Id $bootmgr -Type ([uint32]"0x10100002")
$bootManager | Set-PartitionDeviceElement ([BcdLibraryElementTypes]::Device_ApplicationDevice) 2 "" $sDrive | Out-Null
$bootManager | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "Windows Boot Manager" | Out-Null
$bootManager | Set-StringElement ([BcdLibraryElementTypes]::String_PreferredLocale) "en-US" | Out-Null
$bootManager | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($globalsettings) | Out-Null
$bootManager | Set-ObjectElement ([BcdBootMgrElementTypes]::Object_DefaultObject) $osLoader | Out-Null
$bootManager | Set-ObjectElement ([BcdOSLoaderElementTypes]::Object_AssociatedResumeObject) $resume | Out-Null
$bootManager | Set-ObjectListElement ([BcdBootMgrElementTypes]::ObjectList_DisplayOrder) @($osLoader) | Out-Null
$bootManager | Set-ObjectListElement ([BcdBootMgrElementTypes]::ObjectList_ToolsDisplayOrder) @($memdiag) | Out-Null
$bootManager | Set-IntegerElement ([BcdBootMgrElementTypes]::Integer_Timeout) 30 | Out-Null

Updating a USB BCD store

For the second demonstration, a WinPE file is added to an existing WinPE USB. Other than adding the Windows Boot Loader, it is necessary to update the ems (Emergency Management Services) setting to display the boot menu, if not already enabled. As the BCD store has an existing Ramdisk Option, a new one is not required; however, it is necessary to get the Id of the existing Device Option. Lastly, after the new boot loader is added, the Windows Boot Manager needs the display order updated to include the new boot loader.

$storeFile = "BCD file"
$wimFile = "\sources\boot2.wim"

$bcdStore = Get-StaticBcdStore | Open-Store $storeFile

# Ramdisk Options
$devices = $bcdStore | Enumerate-Objects ([uint32]"0x30000000")
if($devices.Count -gt 1) {
    Write-Host "Not prepared for this..."
    return
}
else {
    if(($devices | Get-Element ([BcdDeviceObjectElementTypes]::String_SdiPath)) -ne $null) {
        $id = $devices | Get-Id
    }
}

if([String]::IsNullOrEmpty($id)) {
    Write-Host "Missing Ramdisk Option"
    return
}

$winre = $BcdStore | Create-Object ([uint32]"0x10200003")

$winre | Set-FileDeviceElement -Type ([BcdLibraryElementTypes]::Device_ApplicationDevice) -DeviceType ([DeviceTypes]::RamdiskDevice) `
    -AdditionalOptions $id -Path $wimFile -ParentDeviceType 1 `
    -ParentAdditionalOptions "" -ParentPath "" | Out-Null
$winre | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) "\Windows\system32\winload.exe" | Out-Null
$winre | Set-StringElement ([BcdLibraryElementTypes]::String_Description) "An additional WinPE" | Out-Null
$winre | Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) @($bootloadersettings) | Out-Null
$winre | Set-FileDeviceElement -Type ([BcdOSLoaderElementTypes]::Device_OSDevice) -DeviceType 4 `
    -AdditionalOptions $id -Path $wimFile -ParentDeviceType 1 `
    -ParentAdditionalOptions "" -ParentPath "" | Out-Null
$winre | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\Windows" | Out-Null
$winre | Set-IntegerElement ([uint32]"0x250000C2") 1 | Out-Null
$winre | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_DetectKernelAndHal) 1 | Out-Null
$winre | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null

# Windows Boot Loader
$loader = $bcdStore | Enumerate-Objects ([uint32]"0x10200003")

$values = @()

$loader | % {
    $values += ($_ | Get-Id)
    # update ems
    $_ | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_EmsEnabled) 1 | Out-Null
}

# enable ems
$BcdStore | Open-Object $emssettings | Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_EmsEnabled) 1 | Out-Null

$bcdStore | Open-Object $bootmgr | Set-ObjectListElement -Type ([BcdBootMgrElementTypes]::ObjectList_DisplayOrder) -Ids $values

*The Boolean_EmsEnabled that appears for the boot loader and the boot manager are not the same.

Just for fun--Building the BCD-Template

The last demonstration will recreate the BCD-Template located in system32\config. This will show some of the BCD objects not normally defined in a standard BCD store.

A few of the repetative operations have been simplified--such as the use of a Set-InheritedObjects function to wrap Set-ObjectListElement ([BcdLibraryElementTypes]::ObjectList_InheritedObjects). Also, a mix of basic and verbose bcdedit output is used to provide a more accurate result of the demonstrative code.

 

EMS Settings
------------
identifier {emssettings}
bootems Yes
$BcdStore | Create-Object -Id $emssettings -Type ([uint32]"0x20100000") | `
    Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_EmsEnabled) 1 | Out-Null
Debugger Settings
-----------------
identifier {dbgsettings}
debugtype Serial
debugport 1
baudrate 115200
$debugger = $BcdStore | Create-Object -Id $dbgsettings -Type ([uint32]"0x20100000")
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_DebuggerType) 0 | Out-Null
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_SerialDebuggerPort) 1 | Out-Null
$debugger | Set-IntegerElement ([BcdLibraryElementTypes]::Integer_SerialDebuggerBaudRate) 115200 | Out-Null
RAM Defects
-----------
identifier {badmemory}
$BcdStore | Create-Object -Id $badmemory -Type ([uint32]"0x20100000") | Out-Null
Global Settings
---------------
identifier {globalsettings}
inherit {dbgsettings}
  {emssettings}
  {badmemory}
$global = $BcdStore | Create-Object -Id $globalsettings -Type ([uint32]"0x20100000") | `
    Set-InheritedObjects @($dbgsettings,$emssettings,$badmemory) | Out-Null 
Resume Loader Settings
----------------------
identifier {resumeloadersettings}
inherit {globalsettings}
$BcdStore | Create-Object -Id $resumeloadersettings -Type ([uint32]"0x20200004") | `
        Set-InheritedObjects -Value @($globalsettings) | Out-Null
Windows Legacy OS Loader
------------------------
identifier {ntldr}
path \ntldr
custom:45000001 1
custom:47000005 301989892
  6
$legacy = $BcdStore | Create-Object -Id $ntldr -Type ([uint32]"0x10300006")
$legacy | Set-ApplicationPath "\ntldr" | Out-Null
$legacy | Set-IntegerElement ([uint32]"0x45000001") 1 | Out-Null
$legacy | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),6) | Out-Null
Hypervisor Settings
-------------------
identifier {hypervisorsettings}
hypervisordebugtype Serial
hypervisordebugport 1
hypervisorbaudrate 115200
$hypervisor = $BcdStore | Create-Object -Id $hypervisorsettings -Type ([uint32]"0x20200003")
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerType) 0 | Out-Null
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerPortNumber) 1 | Out-Null
$hypervisor | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_HypervisorDebuggerBaudrate) 115200 | Out-Null
Boot Loader Settings
--------------------
identifier {bootloadersettings}
inherit {globalsettings}
  {hypervisorsettings}
$BcdStore | Create-Object -Id $bootloadersettings -Type ([uint32]"0x20200003") | `
    Set-InheritedObjects @($globalsettings,$hypervisorsettings) | Out-Null
Windows Memory Tester
---------------------
identifier {memdiag}
path \boot\memtest.exe
locale en-US
inherit {globalsettings}
badmemoryaccess Yes
custom:45000001 1
custom:47000005 301989892
  2
$memorytester = $BcdStore | Create-Object -Id $memdiag -Type ([uint32]"0x10200005")
$memorytester | Set-ApplicationPath "\boot\memtest.exe" | Out-Null
$memorytester | Set-PreferredLocale "en-US" | Out-Null
$memorytester | Set-InheritedObjects @($globalsettings) | Out-Null
$memorytester | Set-BooleanElement ([BcdLibraryElementTypes]::Boolean_AllowBadMemoryAccess) 1 | Out-Null
$memorytester | Set-IntegerElement ([uint32]"0x45000001") 1 | Out-Null
$memorytester | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),2) | Out-Null
Resume from Hibernate
---------------------
identifier {0c334284-9a41-4de1-99b3-a7e87e8ff07e}
description Windows Resume Application
locale en-US
inherit {resumeloadersettings}
filepath \hiberfil.sys
custom:42000002 \system32\winresume.efi
custom:45000001 2
custom:46000004 Yes
$hib2 = $BcdStore | Create-Object -Id "{0c334284-9a41-4de1-99b3-a7e87e8ff07e}" -Type ([uint32]"0x10200004")
$hib2 | Set-Description "Windows Resume Application" | Out-Null
$hib2 | Set-PreferredLocale "en-US" | Out-Null
$hib2 | Set-InheritedObjects @($resumeloadersettings) | Out-Null
# String_HiberFilePath
$hib2 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\hiberfil.sys" | Out-Null
$hib2 | Set-StringElement ([uint32]"0x42000002") "\system32\winresume.efi" | Out-Null
$hib2 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$hib2 | Set-BooleanElement ([uint32]"0x46000004") 1 | Out-Null
Resume from Hibernate
---------------------
identifier {98b02a23-0674-4ce7-bdad-e0a15a8ff97b}
description Windows Resume Application
locale en-US
inherit {resumeloadersettings}
filepath \hiberfil.sys
custom:42000002 \system32\winresume.exe
custom:45000001 2
custom:46000004 Yes
$hib1 = $BcdStore | Create-Object -Id "{98b02a23-0674-4ce7-bdad-e0a15a8ff97b}" -Type ([uint32]"0x10200004")
$hib1 | Set-Description "Windows Resume Application" | Out-Null
$hib1 | Set-PreferredLocale "en-US" | Out-Null
$hib1 | Set-InheritedObjects @($resumeloadersettings) | Out-Null
$hib1 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\hiberfil.sys" | Out-Null
$hib1 | Set-StringElement ([uint32]"0x42000002") "\system32\winresume.exe" | Out-Null
$hib1 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$hib1 | Set-BooleanElement ([uint32]"0x46000004") 1 | Out-Null
OS Target Template
------------------
identifier {a1943bbc-ea85-487c-97c7-c9ede908a38a}
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
systemroot \windows
resumeobject {98b02a23-0674-4ce7-bdad-e0a15a8ff97b}
nx OptIn
detecthal Yes
custom:42000002 \system32\winload.exe
custom:45000001 2
custom:47000005 301989892
  3
$template2 = $BcdStore | Create-Object -Id "{a1943bbc-ea85-487c-97c7-c9ede908a38a}" -Type ([uint32]"0x10200003")
$template2 | Set-PreferredLocale "en-US" | Out-Null
$template2 | Set-InheritedObjects @($bootloadersettings) | Out-Null
$template2 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\windows" | Out-Null
$template2 | Set-ObjectElement ([BcdOSLoaderElementTypes]::Object_AssociatedResumeObject) "{98b02a23-0674-4ce7-bdad-e0a15a8ff97b}" | Out-Null
$template2 | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 0 | Out-Null
$template2 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_DetectKernelAndHal) 1 | Out-Null
$template2 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null
$template2 | Set-StringElement ([uint32]"0x42000002") "\system32\winload.exe" | Out-Null
$template2 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$template2 | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),3) | Out-Null
OS Target Template
------------------
identifier {b012b84d-c47c-4ed5-b722-c0c42163e569}
locale en-US
inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}
systemroot \windows
resumeobject {0c334284-9a41-4de1-99b3-a7e87e8ff07e}
nx OptIn
detecthal Yes
custom:42000002 \system32\winload.efi
custom:45000001 2
custom:47000005 301989892
  3
$template1 = $BcdStore | Create-Object -Id "{b012b84d-c47c-4ed5-b722-c0c42163e569}" -Type ([uint32]"0x10200003")
$template1 | Set-PreferredLocale "en-US" | Out-Null
$template1 | Set-InheritedObjects @($bootloadersettings) | Out-Null
$template1 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\windows" | Out-Null
$template1 | Set-ObjectElement ([BcdOSLoaderElementTypes]::Object_AssociatedResumeObject) "{0c334284-9a41-4de1-99b3-a7e87e8ff07e}" | Out-Null
$template1 | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 0 | Out-Null
$template1 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_DetectKernelAndHal) 1 | Out-Null
$template1 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null
$template1 | Set-StringElement ([uint32]"0x42000002") "\system32\winload.efi" | Out-Null
$template1 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$template1 | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),3) | Out-Null
Windows Setup
-------------
identifier {default}
locale en-US
inherit {bootloadersettings}
systemroot \windows
nx OptOut
detecthal Yes
winpe Yes
custom:42000002 \system32\winload.exe
custom:42000003 \boot.wim
custom:45000001 2
custom:47000005 301989892
  1
$setup1 = $BcdStore | Create-Object -Id "{cbd971bf-b7b8-4885-951a-fa03044f5d71}" -Type ([uint32]"0x10200003")
$setup1 | Set-PreferredLocale "en-US" | Out-Null
$setup1 | Set-InheritedObjects @($bootloadersettings) | Out-Null
$setup1 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\windows" | Out-Null
$setup1 | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 1 | Out-Null
$setup1 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_DetectKernelAndHal) 1 | Out-Null
$setup1 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null
$setup1 | Set-StringElement ([uint32]"0x42000002") "\system32\winload.exe" | Out-Null
$setup1 | Set-StringElement ([uint32]"0x42000003") "\boot.wim" | Out-Null
$setup1 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$setup1 | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),1) | Out-Null
Windows Setup
-------------
identifier {7254a080-1510-4e85-ac0f-e7fb3d444736}
locale en-US
inherit {bootloadersettings}
systemroot \windows
nx OptOut
detecthal Yes
winpe Yes
custom:42000002 \system32\winload.efi
custom:42000003 \boot.wim
custom:45000001 2
custom:47000005 301989892
  1
$setup2 = $BcdStore | Create-Object -Id "{7254a080-1510-4e85-ac0f-e7fb3d444736}" -Type ([uint32]"0x10200003")
$setup2 | Set-PreferredLocale "en-US" | Out-Null
$setup2 | Set-InheritedObjects @($bootloadersettings) | Out-Null
$setup2 | Set-StringElement ([BcdOSLoaderElementTypes]::String_SystemRoot) "\windows" | Out-Null
$setup2 | Set-IntegerElement ([BcdOSLoaderElementTypes]::Integer_NxPolicy) 1 | Out-Null
$setup2 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_DetectKernelAndHal) 1 | Out-Null
$setup2 | Set-BooleanElement ([BcdOSLoaderElementTypes]::Boolean_WinPEMode) 1 | Out-Null
$setup2 | Set-StringElement ([uint32]"0x42000002") "\system32\winload.efi" | Out-Null
$setup2 | Set-StringElement ([uint32]"0x42000003") "\boot.wim" | Out-Null
$setup2 | Set-IntegerElement ([uint32]"0x45000001") 2 | Out-Null
$setup2 | Set-IntegerListElement ([uint32]"0x47000005") @(([uint32]"0x12000004"),1) | Out-Null
Windows Boot Manager
--------------------
identifier {bootmgr}
path \EFI\Microsoft\Boot\bootmgfw.efi
description Windows Boot Manager
locale en-US
inherit {globalsettings}
default {default}
timeout 30
custom:45000001 1
$bootManager = $BcdStore | Create-Object -Id $bootmgr -Type ([uint32]"0x10100002")
$bootManager | Set-ApplicationPath "\EFI\Microsoft\Boot\bootmgfw.efi" | Out-Null
$bootManager | Set-Description "Windows Boot Manager" | Out-Null
$bootManager | Set-PreferredLocale "en-US" | Out-Null
$bootManager | Set-InheritedObjects @($globalsettings) | Out-Null
$bootManager | Set-ObjectElement ([BcdBootMgrElementTypes]::Object_DefaultObject) "{cbd971bf-b7b8-4885-951a-fa03044f5d71}" | Out-Null
$bootManager | Set-IntegerElement ([BcdBootMgrElementTypes]::Integer_Timeout) 30 | Out-Null
$bootManager | Set-IntegerElement ([uint32]"0x45000001") 1 | Out-Null

 

Powershell BCD code

The following code can be saved to a file and linked using

. ("FileName.ps1")

This code is not complete. Although the WMI methods have been defined, new enumerators can be added for Object Type and many of the enumerators copied from Microsoft may still be incorrect. This code is only a foundation.

try {
    $check = ($deviceMethods -eq [Kernel32.NativeMethods])
}
catch {
$deviceMethods = Add-Type -MemberDefinition @'
[DllImport("Kernel32.dll", EntryPoint = "QueryDosDeviceA", CharSet = CharSet.Ansi, SetLastError=true)]
public static extern int QueryDosDevice(string lpDeviceName, System.Text.StringBuilder lpTargetPath, int ucchMax);
'@ -Name NativeMethods -Namespace Kernel32 -PassThru
}

function Get-DosDevice {
Param([Parameter(Mandatory=$true, Position=0)]$DriveLetter)
    $sb = New-Object System.Text.StringBuilder(30)
    $ret = $deviceMethods::QueryDosDevice($DriveLetter, $sb, 30)

    if($ret -gt 0) {
        $sb.ToString()
    }
}

function Has-Role {
    param([Security.Principal.WindowsBuiltInRole]$Role = [Security.Principal.WindowsBuiltInRole]::Administrator)
    
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal $identity
    return $principal.IsInRole($Role)
}


function Get-StaticBcdStore {
    $SWbemLocator = New-Object -ComObject WbemScripting.SWbemLocator
    $wmi = $SWbemLocator.ConnectServer(".","root\wmi")
    $wmi.Get("BcdStore")
}

function Set-InheritedObjects {
Param([Parameter(Position=0)]$Value, [Parameter(ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Set-ObjectListElement -Type ([BcdLibraryElementTypes]::ObjectList_InheritedObjects) $Value
}

function Set-ApplicationPath {
Param([Parameter(Position=0)][string]$Value, [Parameter(ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Set-StringElement ([BcdLibraryElementTypes]::String_ApplicationPath) $Value
}

function Set-Description {
Param([Parameter(Position=0)][string]$Value, [Parameter(ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Set-StringElement ([BcdLibraryElementTypes]::String_Description) $Value
}

function Set-PreferredLocale {
Param([Parameter(Position=0)][string]$Value, [Parameter(ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Set-StringElement ([BcdLibraryElementTypes]::String_PreferredLocale) $Value
}

##########################
###     COM Helper     ###
##########################

function New-InParameter {
Param([Parameter(Position=0)]$Method, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Methods_.Item($Method).InParameters.SpawnInstance_()
}

function Get-PropertyValue {
Param([Parameter(Position=0)]$Property, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Properties_.Item($Property).Value
}

function Set-PropertyValue {
Param([Parameter(Position=0)]$Property, [Parameter(Position=1)]$Value, [Parameter(ValueFromPipeLine=$true)]$Object)
    $Object.Properties_.Item($Property).Value=$Value
}

function Invoke-Method {
Param([Parameter(Position=0)]$Method, [Parameter(Position=1)]$ParameterNames, [Parameter(Position=2)]$ParameterValues,
    [Parameter(ValueFromPipeLine=$true)]$Object)
    if($ParameterNames -eq $null -or $ParameterValues -eq $null) {
        # If the method has required parameters: "The remote procedure call failed."
        $Object.ExecMethod_($Method)
    }
    else {
        $in = New-InParameter $Method -Object $Object
        if($ParameterNames.GetType() -eq [System.String]) {
            $in | Set-PropertyValue $ParameterNames $ParameterValues
        }
        else {
            for($i = 0; $i -lt $ParameterNames.LongLength; $i++) {
                if($ParameterValues[$i] -ne $null) {
                    $in | Set-PropertyValue $ParameterNames[$i] $ParameterValues[$i]
                }
            }
        }

        $Object.ExecMethod_($Method, $in)
    }
}


###########################
###     Known GUIDs     ###
###########################

# BCD-Template (Windows 7 Pro)
$bootmgr = "{9dea862c-5cdd-4e70-acc1-f32b344d4795}"
$bootloadersettings = "{6efb52bf-1766-41db-a6b3-0ee5eff72bd7}"
$resumeloadersettings = "{1afa9c49-16ab-4a5c-901b-212802da9460}"
$memdiag = "{b2721d73-1db4-4c62-bf78-c548a880142d}"
$ntldr = "{466f5a88-0af2-4f76-9038-095b170dc21c}"
$dbgsettings = "{4636856e-540f-4170-a130-a84776f4c654}"
$emssettings = "{0ce4991b-e6b3-4b16-b23c-5e0d9250e5d9}"
$bootloadersettings = "{6efb52bf-1766-41db-a6b3-0ee5eff72bd7}"
$hypervisorsettings = "{7ff607e0-4395-11db-b0de-0800200c9a66}"
$globalsettings = "{7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}"
$badmemory = "{5189b25c-5558-4bf2-bca4-289b11bd29e2}"

# BCD.doc - 2006
$fwbootmgr = "{a5a30fa2-3d06-4e9f-b5f4-a01df9d1fcba}"
$resumeapp = "{147aa509-0358-4473-b83b-d950dda00615}"

$ramdiskopt = "{AE5534E0-A924-466C-B836-758539A3EE3A}"


############################
###     Object Types     ###
############################

if(!(([System.Management.Automation.PSTypeName]"BcdBootMgrElementTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdBootMgrElementTypes : uint
    {
        ObjectList_DisplayOrder = 0x24000001,
        ObjectList_BootSequence = 0x24000002,
        Object_DefaultObject = 0x23000003,
        Integer_Timeout = 0x25000004,
        Boolean_AttemptResume = 0x26000005,
        Object_ResumeObject = 0x23000006,
        ObjectList_ToolsDisplayOrder = 0x24000010,
        Boolean_DisplayBootMenu = 0x26000020,
        Boolean_NoErrorDisplay = 0x26000021,
        Device_BcdDevice = 0x21000022,
        String_BcdFilePath = 0x22000023,
        Boolean_ProcessCustomActionsFirst = 0x26000028,
        IntegerList_CustomActionsList = 0x27000030,
        Boolean_PersistBootSequence = 0x26000031
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdDeviceObjectElementTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdDeviceObjectElementTypes : uint
    {
        Integer_RamdiskImageOffset = 0x35000001,
        Integer_TftpClientPort = 0x35000002,
        Device_SdiDevice = 0x31000003,
        String_SdiPath = 0x32000004,
        Integer_RamdiskImageLength = 0x35000005,
        Boolean_RamdiskExportAsCd = 0x36000006,
        Integer_RamdiskTftpBlockSize = 0x36000007,
        Integer_RamdiskTftpWindowSize = 0x36000008,
        Boolean_RamdiskMulticastEnabled = 0x36000009,
        Boolean_RamdiskMulticastTftpFallback = 0x3600000A,
        Boolean_RamdiskTftpVarWindow = 0x3600000B
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdLibrary_DebuggerType").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdLibrary_DebuggerType
    {
        DebuggerSerial = 0,
        Debugger1394 = 1,
        DebuggerUsb = 2,
        DebuggerNet = 3
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdLibrary_SafeBoot").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdLibrary_SafeBoot
    {
        SafemodeMinimal = 0,
        SafemodeNetwork = 1,
        SafemodeDsRepair = 2
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdLibraryElementTypes").Type)) {
Add-Type -TypeDefinition @'
public enum BcdLibraryElementTypes : uint
    {
        Device_ApplicationDevice = 0x11000001,
        String_ApplicationPath = 0x12000002,
        String_Description = 0x12000004,
        String_PreferredLocale = 0x12000005,
        ObjectList_InheritedObjects = 0x14000006,
        Integer_TruncatePhysicalMemory = 0x15000007,
        ObjectList_RecoverySequence = 0x14000008,
        Boolean_AutoRecoveryEnabled = 0x16000009,
        IntegerList_BadMemoryList = 0x1700000a,
        Boolean_AllowBadMemoryAccess = 0x1600000b,
        Integer_FirstMegabytePolicy = 0x1500000c,
        Integer_RelocatePhysicalMemory = 0x1500000D,
        Integer_AvoidLowPhysicalMemory = 0x1500000E,
        Boolean_DebuggerEnabled = 0x16000010,
        Integer_DebuggerType = 0x15000011,
        Integer_SerialDebuggerPortAddress = 0x15000012,
        Integer_SerialDebuggerPort = 0x15000013,
        Integer_SerialDebuggerBaudRate = 0x15000014,
        Integer_1394DebuggerChannel = 0x15000015,
        String_UsbDebuggerTargetName = 0x12000016,
        Boolean_DebuggerIgnoreUsermodeExceptions = 0x16000017,
        Integer_DebuggerStartPolicy = 0x15000018,
        String_DebuggerBusParameters = 0x12000019,
        Integer_DebuggerNetHostIP = 0x1500001A,
        Integer_DebuggerNetPort = 0x1500001B,
        Boolean_DebuggerNetDhcp = 0x1600001C,
        String_DebuggerNetKey = 0x1200001D,
        Boolean_EmsEnabled = 0x16000020,
        Integer_EmsPort = 0x15000022,
        Integer_EmsBaudRate = 0x15000023,
        String_LoadOptionsString = 0x12000030,
        Boolean_DisplayAdvancedOptions = 0x16000040,
        Boolean_DisplayOptionsEdit = 0x16000041,
        Device_BsdLogDevice = 0x11000043,
        String_BsdLogPath = 0x12000044,
        Boolean_GraphicsModeDisabled = 0x16000046,
        Integer_ConfigAccessPolicy = 0x15000047,
        Boolean_DisableIntegrityChecks = 0x16000048,
        Boolean_AllowPrereleaseSignatures = 0x16000049,
        String_FontPath = 0x1200004A,
        Integer_SiPolicy = 0x1500004B,
        Integer_FveBandId = 0x1500004C,
        Boolean_ConsoleExtendedInput = 0x16000050,
        Integer_GraphicsResolution = 0x15000052,
        Boolean_RestartOnFailure = 0x16000053,
        Boolean_GraphicsForceHighestMode = 0x16000054,
        Boolean_IsolatedExecutionContext = 0x16000060,
        Boolean_BootUxDisable = 0x1600006C,
        Boolean_BootShutdownDisabled = 0x16000074,
        IntegerList_AllowedInMemorySettings = 0x17000077,
        Boolean_ForceFipsCrypto = 0x16000079
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdMemDiagElementTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdMemDiagElementTypes : uint
    {
        Integer_PassCount = 0x25000001,
        Integer_FailureCount = 0x25000003
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdOSLoader_NxPolicy").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdOSLoader_NxPolicy
    {
        NxPolicyOptIn = 0,
        NxPolicyOptOut = 1,
        NxPolicyAlwaysOff = 2,
        NxPolicyAlwaysOn = 3
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdOSLoader_PAEPolicy").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdOSLoader_PAEPolicy
    {
        PaePolicyDefault = 0,
        PaePolicyForceEnable = 1,
        PaePolicyForceDisable = 2
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdOSLoaderElementTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdOSLoaderElementTypes : uint
    {
        Device_OSDevice = 0x21000001,
        String_SystemRoot = 0x22000002,
        Object_AssociatedResumeObject = 0x23000003,
        Boolean_DetectKernelAndHal = 0x26000010,
        String_KernelPath = 0x22000011,
        String_HalPath = 0x22000012,
        String_DbgTransportPath = 0x22000013,
        Integer_NxPolicy = 0x25000020,
        Integer_PAEPolicy = 0x25000021,
        Boolean_WinPEMode = 0x26000022,
        Boolean_DisableCrashAutoReboot = 0x26000024,
        Boolean_UseLastGoodSettings = 0x26000025,
        Boolean_AllowPrereleaseSignatures = 0x26000027,
        Boolean_NoLowMemory = 0x26000030,
        Integer_RemoveMemory = 0x25000031,
        Integer_IncreaseUserVa = 0x25000032,
        Boolean_UseVgaDriver = 0x26000040,
        Boolean_DisableBootDisplay = 0x26000041,
        Boolean_DisableVesaBios = 0x26000042,
        Boolean_DisableVgaMode = 0x26000043,
        Integer_ClusterModeAddressing = 0x25000050,
        Boolean_UsePhysicalDestination = 0x26000051,
        Integer_RestrictApicCluster = 0x25000052,
        Boolean_UseLegacyApicMode = 0x26000054,
        Integer_X2ApicPolicy = 0x25000055,
        Boolean_UseBootProcessorOnly = 0x26000060,
        Integer_NumberOfProcessors = 0x25000061,
        Boolean_ForceMaximumProcessors = 0x26000062,
        Boolean_ProcessorConfigurationFlags = 0x25000063,
        Boolean_MaximizeGroupsCreated = 0x26000064,
        Boolean_ForceGroupAwareness = 0x26000065,
        Integer_GroupSize = 0x25000066,
        Integer_UseFirmwarePciSettings = 0x26000070,
        Integer_MsiPolicy = 0x25000071,
        Integer_SafeBoot = 0x25000080,
        Boolean_SafeBootAlternateShell = 0x26000081,
        Boolean_BootLogInitialization = 0x26000090,
        Boolean_VerboseObjectLoadMode = 0x26000091,
        Boolean_KernelDebuggerEnabled = 0x260000a0,
        Boolean_DebuggerHalBreakpoint = 0x260000a1,
        Boolean_UsePlatformClock = 0x260000A2,
        Boolean_ForceLegacyPlatform = 0x260000A3,
        Integer_TscSyncPolicy = 0x250000A6,
        Boolean_EmsEnabled = 0x260000b0,
        Integer_DriverLoadFailurePolicy = 0x250000c1,
        Integer_BootMenuPolicy = 0x250000C2,
        Boolean_AdvancedOptionsOneTime = 0x260000C3,
        Integer_BootStatusPolicy = 0x250000E0,
        Boolean_DisableElamDrivers = 0x260000E1,
        Integer_HypervisorLaunchType = 0x250000F0,
        Boolean_HypervisorDebuggerEnabled = 0x260000F2,
        Integer_HypervisorDebuggerType = 0x250000F3,
        Integer_HypervisorDebuggerPortNumber = 0x250000F4,
        Integer_HypervisorDebuggerBaudrate = 0x250000F5,
        Integer_HypervisorDebugger1394Channel = 0x250000F6,
        Integer_BootUxPolicy = 0x250000F7,
        String_HypervisorDebuggerBusParams = 0x220000F9,
        Integer_HypervisorNumProc = 0x250000FA,
        Integer_HypervisorRootProcPerNode = 0x250000FB,
        Boolean_HypervisorUseLargeVTlb = 0x260000FC,
        Integer_HypervisorDebuggerNetHostIp = 0x250000FD,
        Integer_HypervisorDebuggerNetHostPort = 0x250000FE,
        Integer_TpmBootEntropyPolicy = 0x25000100,
        String_HypervisorDebuggerNetKey = 0x22000110,
        Boolean_HypervisorDebuggerNetDhcp = 0x26000114,
        Integer_HypervisorIommuPolicy = 0x25000115,
        Integer_XSaveDisable = 0x2500012b
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"BcdResumeElementTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum BcdResumeElementTypes : uint
    {
        Reserved1 = 0x21000001,
        Reserved2 = 0x22000002,
        Boolean_UseCustomSettings = 0x26000003,
        Device_AssociatedOsDevice = 0x21000005,
        Boolean_DebugOptionEnabled = 0x26000006,
        Integer_BootMenuPolicy = 0x25000008
    }
'@
}

if(!(([System.Management.Automation.PSTypeName]"ApplicationObjectTypes").Type)) {
Add-Type -TypeDefinition @'
    public enum ApplicationObjectTypes : uint
    {
        fwbootmgr = 0x10100001,
        bootmgr = 0x10100002,
        osloader = 0x10200003,
        resume = 0x10200004,
        memdiag = 0x10200005,
        ntldr = 0x10300006,
        bootsector = 0x10400008,
        startup = 0x10400009
    }
'@
}


#########################
###     BcdObject     ###
#########################


function Enumerate-ElementTypes {
    Param([Parameter(Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Invoke-Method "EnumerateElementTypes" | Get-PropertyValue "Types"
}

function Enumerate-Elements {
    Param([Parameter(Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Invoke-Method "EnumerateElements" | Get-PropertyValue "Elements"
}

function Get-Element {
        Param([Parameter(Position=0)][uint32]$Type, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "GetElement" "Type" $Type | Get-PropertyValue "Element"
}

function Get-ElementWithFlags {
        Param([Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][int]$Flags, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "GetElementWithFlags" "Id","Flags" $Id,$Flags | Get-PropertyValue "Element"
}

function Set-DeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][int]$DeviceType, 
        [Parameter(Position=2)][string]$AdditionalOptions, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions
    $BcdObject | Invoke-Method "SetDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-PartitionDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][int]$DeviceType, 
        [Parameter(Position=2)][string]$AdditionalOptions, 
        [Parameter(Position=3)][string]$Path, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions","Path"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions,$Path
    $BcdObject | Invoke-Method "SetPartitionDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-PartitionDeviceElementWithFlags {
    Param(
    [Parameter(Position=0)][uint32]$Type, 
    [Parameter(Position=1)][int]$DeviceType, 
    [Parameter(Position=2)][string]$AdditionalOptions, 
    [Parameter(Position=3)][string]$Path, 
    [Parameter(Position=4)][int]$Flags, 
    [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions","Path","Flags"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions,$Path,$Flags
    $BcdObject | Invoke-Method "SetPartitionDeviceElementWithFlags" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-FileDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][int]$DeviceType, 
        [Parameter(Position=2)][string]$AdditionalOptions, 
        [Parameter(Position=3)][string]$Path, 
        [Parameter(Position=4)][uint32]$ParentDeviceType, 
        [Parameter(Position=5)][string]$ParentAdditionalOptions, 
        [Parameter(Position=6)][string]$ParentPath, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","DeviceType","AdditionalOptions","Path","ParentDeviceType","ParentAdditionalOptions","ParentPath"
    $parameterValues = $Type,$DeviceType,$AdditionalOptions,$Path,$ParentDeviceType,$ParentAdditionalOptions,$ParentPath
    $BcdObject | Invoke-Method "SetFileDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-QualifiedPartitionDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type,
        [Parameter(Position=1)][int]$PartitionStyle, 
        [Parameter(Position=2)][string]$DiskSignature, 
        [Parameter(Position=3)][string]$PartitionIdentifier, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","PartitionStyle","DiskSignature","PartitionIdentifier"
    $parameterValues = $Type,$PartitionStyle,$DiskSignature,$PartitionIdentifier
    $BcdObject | Invoke-Method "SetQualifiedPartitionDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-VhdDeviceElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][string]$Path, 
        [Parameter(Position=2)][uint32]$ParentDeviceType, 
        [Parameter(Position=3)][string]$ParentAdditionalOptions, 
        [Parameter(Position=4)][string]$ParentPath, 
        [Parameter(Position=5)][uint32]$CustomLocate, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $parameterNames = "Type","Path","ParentDeviceType","ParentAdditionalOptions","ParentPath","CustomLocate"
    $parameterValues = $Type,$Path,$ParentDeviceType,$ParentAdditionalOptions,$ParentPath,$CustomLocate
    $BcdObject | Invoke-Method "SetVhdDeviceElement" $parameterNames $parameterValues | Get-PropertyValue "ReturnValue"
}

function Set-StringElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][string]$String, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetStringElement" "Type","String" $Type,$String | Get-PropertyValue "ReturnValue"
}

function Set-ObjectElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][string]$Id, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetObjectElement" "Type","Id" $Type,$Id | Get-PropertyValue "ReturnValue"
}

function Set-ObjectListElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)]$Ids, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetObjectListElement" "Type","Ids" $Type,$Ids | Get-PropertyValue "ReturnValue"
}

function Set-IntegerElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)]$Integer, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetIntegerElement" "Type","Integer" $Type,$Integer | Get-PropertyValue "ReturnValue"
}
    
function Set-IntegerListElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)]$Integers, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetIntegerListElement" "Type","Integers" $Type,$Integers | Get-PropertyValue "ReturnValue"
}

function Set-BooleanElement {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][bool]$Boolean, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "SetBooleanElement" "Type","Boolean" $Type,$Boolean | Get-PropertyValue "ReturnValue"
}

function Delete-Element {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(ValueFromPipeLine=$true)]$BcdObject
    )
    $BcdObject | Invoke-Method "DeleteElement" "Type" $Type | Get-PropertyValue "ReturnValue"
}


########################
###     BcdStore     ###
########################


 function Get-FilePath {
 Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStore)
    $BcdStore | Get-PropertyValue "FilePath"
 }

function Open-Store {
    Param(
        [Parameter(Position=0)][string]$File="", 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "OpenStore" "File" $File | Get-PropertyValue "Store"
}

function Import-Store {
    Param(
        [Parameter(Position=0)][string]$File, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
#### This will overwrite the current system store--use with caution! ####
    $BcdStore | Invoke-Method "ImportStore" "File" $File | Get-PropertyValue "ReturnValue"
}

function Import-StoreWithFlags {
    Param(
        [Parameter(Position=0)][string]$File, 
        [Parameter(Position=1)][int]$Flags=0, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "ImportStoreWithFlags" "File","Flags" $File,$Flags | Get-PropertyValue "ReturnValue"
}

function Export-Store {
    Param(
        [Parameter(Position=0)][string]$File, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "ExportStore" "File" $File | Get-PropertyValue "ReturnValue"
}

function Create-Store {
    Param(
        [Parameter(Position=0)][string]$File, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CreateStore" "File" $File | Get-PropertyValue "Store"
}

function Delete-SystemStore {
    Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStore)
    $BcdStore | Invoke-Method "DeleteSystemStore" | Get-PropertyValue "ReturnValue"
}

function Get-SystemDisk {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStore)
    $BcdStore | Invoke-Method "GetSystemDisk" | Get-PropertyValue "Disk"
}

function Get-SystemPartition {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStore)
    $BcdStore | Invoke-Method "GetSystemPartition" | Get-PropertyValue "Partition"
}

function Set-SystemStoreDevice {
    Param(
        [Parameter(Position=0)]$Partition, 
        [Parameter(Mandatory=$true, Position=2, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "SetSystemStoreDevice" | Get-PropertyValue "ReturnValue"
}

function Enumerate-Objects {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "EnumerateObjects" "Type" $Type | Get-PropertyValue "Objects"
}

function Open-Object {
    Param(
        [Parameter(Position=0)][string]$Id, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "OpenObject" "Id" $Id | Get-PropertyValue "Object"
}

function Create-Object {
    Param(
        [Parameter(Position=0)][uint32]$Type, 
        [Parameter(Position=1)][string]$Id, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CreateObject" "Id","Type" $Id,$Type | Get-PropertyValue "Object"
}

function Delete-Object {
    Param(
        [Parameter(Position=0)][string]$Id, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "DeleteObject" "Id" $Id | Get-PropertyValue "ReturnValue"
}

function Copy-Object {
    Param(
        [Parameter(Position=0)][string]$SourceStoreFile, 
        [Parameter(Position=1)][string]$SourceId, 
        [Parameter(Position=2)][int]$Flags, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CopyObject" "SourceStoreFile","SourceId","Flags" $SourceStoreFile,$SourceId,$Flags | Get-PropertyValue "Object"
}

function Copy-Objects {
    Param(
        [Parameter(Position=0)][string]$SourceStoreFile, 
        [Parameter(Position=1)][uint32]$Type, 
        [Parameter(Position=2)][int]$Flags, 
        [Parameter(Mandatory=$true, ValueFromPipeLine=$true)]$BcdStore
    )
    $BcdStore | Invoke-Method "CopyObjects" "SourceStoreFile","Type","Flags" $SourceStoreFile,$Type,$Flags | Get-PropertyValue "ReturnValue"
}


#################################
###     Other Bcd Objects     ###
#################################

function Get-StoreFilePath {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "StoreFilePath"
}

function Get-Id {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "Id"
}

function Get-Type {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "Type"
}

function Get-Path {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "Path"
}

function Get-ElementProperty {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "Element"
}

function Get-Parent {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObject)
    $BcdObject | Get-PropertyValue "Parent"
}

function Get-ObjectId {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdElement)
    $BcdElement | Get-PropertyValue "ObjectId"
}

function Get-Data {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceUnknownData)
    $BcdDeviceUnknownData | Get-PropertyValue "Data"
}

function Get-Device {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceElement)
    $BcdDeviceElement | Get-PropertyValue "Device"
}

function Get-DeviceType {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceData)
    $BcdDeviceData | Get-PropertyValue "DeviceType"
}

function Get-AdditionalOptions {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceData)
    $BcdDeviceData | Get-PropertyValue "AdditionalOptions"
}

function Get-PartitionStyle {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceQualifiedPartitionData)
    $BcdDeviceQualifiedPartitionData | Get-PropertyValue "PartitionStyle"
}

function Get-DiskSignature {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceQualifiedPartitionData)
    $BcdDeviceQualifiedPartitionData | Get-PropertyValue "DiskSignature"
}

function Get-PartitionIdentifier {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdDeviceQualifiedPartitionData)
    $BcdDeviceQualifiedPartitionData | Get-PropertyValue "PartitionIdentifier"
}

function Get-String {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdStringElement)
    Get-PropertyValue "String" -Object $BcdStringElement
}

function Get-Ids {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdObjectListElement)
    Get-PropertyValue "Ids" -Object $BcdObjectListElement
}

function Get-Integer {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdIntegerElement)
    Get-PropertyValue "Integer" -Object $BcdIntegerElement
}

function Get-Integers {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdIntegerListElement)
    Get-PropertyValue "Integers" -Object $BcdIntegerListElement
}

function Get-Boolean {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdBooleanElement)
    Get-PropertyValue "Boolean" -Object $BcdBooleanElement
}

function Get-ActualType {
Param([Parameter(Mandatory=$true, Position=0, ValueFromPipeLine=$true)]$BcdUnknownElement)
    Get-PropertyValue "ActualType" -Object $BcdUnknownElement
}

 

Points of Interest

 

It would seem that the BCD provider is content to accept a supplied GUID for objects like Boot Loader, even though it will generate these if allowed. It would also seem that "{" + [guid]::NewGuid() + "}" is an acceptable substitute. Though no adverse effects were seen during testing: it is highly recommended to use the GUIDs provided by BCD.

Microsoft Documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/bb986746(v=vs.85).aspx

BCD examples can be found in Windows SDK 7.1: BootConfigurationData Sample, Windows Vista AIK: SetAutoFailover.cmd, and at Hey Scripting Guy! http://technet.microsoft.com/en-us/magazine/2008.07.heyscriptingguy.aspx

As previously stated, details of BCD are sparse. I found the best method of learning BCD to be examining BCD files. A large bonus of using COM is the ability to iterate the Properties_ without foreknowledge of the Id or Type.

 

Additional note: this code was written for Powershell 4.0. As of Powershell 5.0, the uint32 was stepped on by Powershell during COM interop. I have no plans to wrestle the conversion in newer versions of Powershell as I still use it--as it is--on Lenovo P50 and T460s models without issue.

History

11/1/2014 - Initial release

2/19/2018 - Added note

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

awilson9010
United States United States
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
QuestionSupport from PowerShell 5 Pin
SuperJMN-CandyBeat20-Jun-18 1:08
memberSuperJMN-CandyBeat20-Jun-18 1:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190526.1 | Last Updated 19 Feb 2018
Article Copyright 2014 by awilson9010
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid