bcdedit, bcdstore and powershell
Asked Answered
E

5

6

so i can write bcd commands in a powershell script as if i were in a cmd prompt, for example:

bcdedit /default '{current}'

however i need a script that does this:

bcdedit /default '{current}'
bcdedit /set '{otherboot}' description "my description"

if it didnt do that, it would be the other way around:

bcdedit /default '{otherboot}'
bcdedit /set '{current}' description "my description"

what i need to do is find the identifier of the other boot in powershell and im not sure how. all google searches say to do this:

$bcdStore=gwmi -name root\wmi -list bcdstore -enableall
$bcdStore|gm
$result=$bcdStore.OpenStore("") # can also use explicit file name.
$store=$result.Store

but i have no idea how to use the store once i have it and this seems a little too complicated. i mean there should be an easier way... no?

Employ answered 3/6, 2013 at 18:32 Comment(0)
C
7

I don't know of a way to do it with WMI, but you could use bcdedit in combination with Select-String:

$otherboot = bcdedit /enum |
  Select-String "path" -Context 2,0 |
  ForEach-Object { $_.Context.PreContext[0] -replace '^identifier +' } |
  Where-Object { $_ -ne "{current}" }

Explanation:

The output of bcdedit /enum looks roughly like this:

Windows Boot Manager
--------------------
identifier              {bootmgr}
device                  partition=\Device\HarddiskVolume1
description             Windows Boot Manager
locale                  en-US
...

Windows Boot Loader
-------------------
identifier              {current}
device                  partition=C:
path                    \Windows\system32\winload.exe
description             Windows 7
locale                  en-US
...

Windows Boot Loader
-------------------
identifier              {e0610d98-e116-11e1-8aa3-e57ee342122d}
device                  partition=C:
path                    \Windows\system32\winload.exe
description             DebugEntry
locale                  en-US
...

The relevant sections of this output are the Windows Boot Loader sections, which – unlike the Windows Boot Manager section – have a path record. Thus we can use this record to select only the Windows Boot Loader sections:

Select-String "path"

Since the identifier records are 2 lines before the path records, we need 2 lines of PreContext (and no PostContext):

Select-String "path" -Context 2,0

Now we have selected the follwing two chunks from the output of bcdedit /enum:

identifier              {current}
device                  partition=C:
path                    \Windows\system32\winload.exe
identifier              {e0610d98-e116-11e1-8aa3-e57ee342122d}
device                  partition=C:
path                    \Windows\system32\winload.exe

Since we're only interested in the first line of the PreContext we select these 2 lines using a ForEach-Object loop:

ForEach-Object { $_.Context.PreContext[0] }

which reduces the two chunks to this:

identifier              {current}
identifier              {e0610d98-e116-11e1-8aa3-e57ee342122d}

from which we remove the category (identifier) via string replacement:

ForEach-Object { $_.Context.PreContext[0] -replace '^identifier +' }

The regular expression '^identifier +' matches a (sub)string starting with the word "identifier" followed by one or more spaces, which is replaced with the empty string. After this replacement the two chunks are reduced to this:

{current}
{e0610d98-e116-11e1-8aa3-e57ee342122d}

So now we only need to filter out the chunk containing {current} and what's left is the identifier of the other boot record:

Where-Object { $_ -ne "{current}" }

After this, the variable $otherboot contains the identifier of the not-current boot record.

Cullender answered 3/6, 2013 at 19:51 Comment(1)
ok, so this is close, but it doesn't do what I want, if I insert $test in this line like so: | % {$test = $_.Context.PreContext[0] -replace '^identifier +' } ` $test is actually {current} and I played around with the context numbers, I tried to select-string "identifier" and that didn't help. i dont fully understand whats happening here. it looks to me like you are looping through each boot and trying t oreplace the identifier? am I right about that? I don't necessarily want to replace it. if i could make $test = the other boot identifier, i could then write: bcedit /default $testEmploy
M
1

Team!

I`am wrote the BCDEdit parser. I think it will be usefull.

$Configs   = @() #Array contains the parsed objects
$NameArray = @()

$Pattern = '^(?<name>[a-z]*)?\s*(?<value>.*)?$'
$enum    = bcdedit /enum

foreach ($item in $enum ){
    if ( $item.trim() ){
        $res = [regex]::matches( $item, $pattern )
        if ( $res ){
            $Value = $res[0].Groups['value'].value 
            $Name  = $res[0].Groups['name'].value
            if ( $Value ){
                if ( $Name ){
                    $PSO = [PSCustomObject]@{
                        Name  = $Name
                        Value = $Value
                    }
                    $NameArray += $PSO
                }
                Else {
                    if ( $NameArray.count ){
                        ( $NameArray | Select-Object -last 1 ).Value += "; $Value"
                    }
                }
            }            
        }
    }
    Else {
        if ( $NameArray ){
            $Configs  += ,$NameArray
            $NameArray = @()
        }
    }
}

#Show results
foreach ( $item in $Configs){
    $item | Format-Table
}

Mallorie answered 11/10, 2021 at 18:13 Comment(0)
S
0

I know this is not a complete answer, but it might be enough to get you started. The code below outputs the display names of all the operating systems that the BCD is aware of.

$cxOptions= new-object System.Management.ConnectionOptions
$cxOptions.Impersonation=[System.Management.ImpersonationLevel]::Impersonate
$cxOptions.EnablePrivileges=$true

$mgmtScope=new-object System.Management.ManagementScope -ArgumentList "root\WMI",$cxOptions
$mgmtPath=new-object System.Management.ManagementPath -ArgumentList 'root\WMI:BcdObject.Id="{9dea862c-5cdd-4e70-acc1-f32b344d4795}",StoreFilePath=""'
$mgmtObject=new-object System.Management.ManagementObject -ArgumentList $mgmtScope,$mgmtPath,$null

# Determine what elements exist in the object and output their value in HEX format
#$mgmtObject.EnumerateElementTypes().types | % { "{0:X0}" -f $_ }

$objBCD=$mgmtObject.GetElement(0x24000001)
$objElements=$objBCD.GetPropertyValue("Element")

$strOldID="{9dea862c-5cdd-4e70-acc1-f32b344d4795}"
for ($i=0; $i -lt $objElements.Ids.Count; $i++) {
  $mgmtPath.Path=$mgmtPath.Path.Replace($strOldID,$objElements.Ids[$i])
  $strOldID=$objElements.Ids[$i]
  $objBCDId=new-object System.Management.ManagementObject -ArgumentList $mgmtScope,$mgmtPath,$null
  $strOS=$objBCDId.GetElement(0x12000004)
  $strOS.Element.String
}
Supen answered 31/8, 2015 at 12:23 Comment(0)
M
0

my solution …

it's can't deal with language etc

but with english system …

not have a problem


<# 
#example 1
Get_Boot_info | ? description -eq 'Windows 10' | select description,identifier,path | format-list

#example 2
$id = @(Get_Boot_info | ? description -eq 'Windows 10')[0].identifier
bcdedit /default $id
bcdedit /toolsdisplayorder $id /addfirst
#>

class Boot_info {
    [string]$identifier
    [string]$device
    [string]$path
    [string]$description
    [string]$locale
    [string]$inherit
    [string]$recoverysequence
    [string]$displaymessageoverride
    [string]$recoveryenabled
    [string]$isolatedcontext
    [string]$allowedinmemorysettings
    [string]$nx
    [string]$bootmenupolicy
}

function Get_Boot_info {
    
    $nl =    [System.Environment]::NewLine
    $store = bcdedit /enum | Out-String  #combine into one string
    $List =  $store -split "$nl$nl"      #split the entries, only empty new lines
    $bl =    $List -match 'Windows Boot Loader'
    $arr =   [System.Collections.ArrayList]::new()

    $bl | % {
        $obj = $_ -Split $nl
        $bi = [Boot_info]::new()
        ForEach ($itm in $obj)
        {
            if ($itm -match 'Windows Boot Loader|-------------------') {
                continue
            }
            $data = [regex]::Replace($itm, "\s+", " ").Split(' ')
            switch ($data[0])
            {
                "identifier" {$bi.identifier = $data[1]}
                "device" {$bi.device = $data[1]}
                "path" {$bi.path = $data[1]}
                "description" {$bi.description = $data[1],$data[2]}
                "locale" {$bi.locale = $data[1]}
                "inherit" {$bi.inherit = $data[1]}
                "recoverysequence" {$bi.recoverysequence = $data[1]}
                "displaymessageoverride" {$bi.displaymessageoverride = $data[1]}
                "recoveryenabled" {$bi.recoveryenabled = $data[1]}
                "isolatedcontext" {$bi.isolatedcontext = $data[1]}
                "nx" {$bi.nx = $data[1]}
                "bootmenupolicy" {$bi.bootmenupolicy = $data[1]}
            }
        }
        $arr.Add($bi) | out-null
    }
    
    return $arr
}
Mayemayeda answered 5/2, 2023 at 21:26 Comment(3)
This code expects the description to have exactly one space, which doesn't need to be. This can be fixed by replacing Split(' ') with Split(' ', 2), and using only $data[1] for the description. I also don't understand $List -match 'Windows Boot Loader'. Why are only the Windows Boot Loader entries shown, and for example the Windows Boot Manager entries are ignored?Aliciaalick
Fixed it .. this version not good New version support more vars & spacesMayemayeda
Will upload it later ..Mayemayeda
M
0

PSM File

# Modify Windows BCD using Powershell - CodeProject
# https://www.codeproject.com/Articles/833655/Modify-Windows-BCD-using-Powershell

function Get-DosDevice {
Param(
  [Parameter(Mandatory=$true, Position=0)]
  $DriveLetter
  )
  
try {
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class API {
  [DllImport("Kernel32.dll", EntryPoint = "QueryDosDeviceA", CharSet = CharSet.Ansi, SetLastError=true)]
  public static extern int QueryDosDevice (string lpDeviceName, System.Text.StringBuilder lpTargetPath, int ucchMax);
}
"@
}
catch {
}

    $sb = New-Object System.Text.StringBuilder(30)
    $ret = [API]::QueryDosDevice($DriveLetter, $sb, 30)

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

Function Pharse_GUID {
   param (
     [parameter(Mandatory=$True)]
     [string] $Source
   )
   
   $Pattern = '^The entry(.*){(.*)}(.*)was successfully created.$'
   $Matches = [Regex]::Matches($Source ,$Pattern)
   if (!$Matches -or !($Matches.Success) -or !($Matches[0])) {
     return $null
   }
  
   try {
      return $Matches[0].Groups[2].Value
   }
   catch {
     ## Nothing here
   }
  
  return $null
}

# Function to detect -
# if we have live OS running from VHD

function Is-VHD-System {
    param (
     [ValidatePattern("^[a-zA-Z]$")]
     [parameter(Mandatory=$False)]
     [string] $Letter
    )

    if (!$Letter) {
      $Letter = $($env:SystemDrive).TrimEnd(":\")
    }
    
    if (!$Letter) {
      return $null
    }

    $Match   = $null
    $Matches = $null
    $Loc_pat = '^([a-zA-Z]:\\)(.*)(.)(vhdx|vhd)$'
    $Dev_pat = '^(\\Device\\HarddiskVolume)([0-9]|[1-9][0-9])(\\)(.*)(vhdx|vhd)$'

    # Group [1] -> \Device\HarddiskVolume
    # Group [2] -> Volume_ID
    # Group [3] -> ... Ignore ...
    # Group [4] -> Path, Name
    # Group [5] -> Ext [must be vhd/vhdx]

    $info = Get_Boot_info
    $disk = Get-Partition -DriveLetter $Letter -ErrorAction SilentlyContinue | Get-disk 
    #$curr = $info | ? Boot_type -eq ([BootType]::Windows_Boot_Loader) | ? identifier -eq "{current}" | ? osdevice -eq "locate=\windows" | ? {!($_).Is_vhd() -and !($_).Is_ramdisk() -and !($_).Is_partition()}

    if (!$disk) {
      throw "error ### no such disk exist."
    }

    if ($disk.FriendlyName -ne 'Msft Virtual Disk') {
      return $false
    }

    if ($disk.Location -eq $null) {
      return $false
    }

    $Matches = [Regex]::Matches($disk.Location ,$Dev_pat)
    if ($Matches -and $Matches.Success){
      return $true
    }

    $Match = [Regex]::Matches($disk.Location ,$Loc_pat)
    if ($Match -and $Match.Success) {  
      # Case of VHDX mounted volume
      return $true
    }

    throw "error ### can't phrase regex."
}

# Function to detect path -
# of live OS running from VHD

function Get-VHD-Path {
    param (
     [ValidatePattern("^[a-zA-Z]$")]
     [parameter(Mandatory=$False)]
     [string] $Letter
    )
    
    if (!$Letter) {
      $Letter = $($env:SystemDrive).TrimEnd(":\")
    }
    
    if (!$Letter) {
      return $null
    }
    
    $Match   = $null
    $Matches = $null
    $Loc_pat = '^([a-zA-Z]:\\)(.*)(.)(vhdx|vhd)$'
    $Dev_pat = '^(\\Device\\HarddiskVolume)([0-9]|[1-9][0-9])(\\)(.*)(vhdx|vhd)$'

    # Group [1] -> \Device\HarddiskVolume
    # Group [2] -> Volume_ID
    # Group [3] -> ... Ignore ...
    # Group [4] -> Path, Name
    # Group [5] -> Ext [must be vhd/vhdx]

    $info = Get_Boot_info
    $disk = Get-Partition -DriveLetter $Letter -ErrorAction SilentlyContinue | Get-disk 
    #$curr = $info | ? Boot_type -eq ([BootType]::Windows_Boot_Loader) | ? identifier -eq "{current}" | ? osdevice -eq "locate=\windows" | ? {!($_).Is_vhd() -and !($_).Is_ramdisk() -and !($_).Is_partition()}

    if (!$disk) {
      throw "error ### no such disk exist."
    }

    if ($disk -and ($disk.FriendlyName -eq 'Msft Virtual Disk') -and $disk.Location) {
      
      $Match = [Regex]::Match($disk.Location ,$Loc_pat)
      if ($Match -and $Match.Success) {
        return $disk.Location
      }

      $Matches = [Regex]::Matches($disk.Location ,$Dev_pat)
      if (!$Matches -or !($Matches.Success) -or !($Matches[0])) {
        return $null
      }

      $Source = "$($Matches[0].Groups[1])$($Matches[0].Groups[2])"
      $Target = gwmi win32_volume| ? {$_.DriveLetter -and ((Get-DosDevice -DriveLetter $_.DriveLetter) -eq $Source)}
      $LeftOver = "$($Matches[0].Groups[4])$($Matches[0].Groups[5])"
      $vhdx_Loc = "$($Target.DriveLetter)\$($LeftOver)"
    }

    if ($Target -and $LeftOver){
      return $vhdx_Loc
    }

    return $null
}

# based on --> CMD file to add a VHD(x) boot object in BCD by MaloK
# https://www.tenforums.com/virtualization/193557-cmd-file-add-vhd-x-boot-object-bcd.html

Function Add_PARTITION_BOOT {
   param (

     [parameter(Mandatory=$True)]
     [string] $Name,
     
     [ValidatePattern("^[a-zA-Z]$")]
     [parameter(Mandatory=$True)]
     [string] $Letter,

     [parameter(Mandatory=$False)]
     [string] $Store,

     [parameter(Mandatory=$False)]
     [Bool] $Add_First
   )

  $store_Addin = $null
  if ($Store -and (Test-Path($Store))) {
    $store_Addin = "/store ""$Store"""
  }

  if (!(Test-Path("$($Letter):\Windows\system32\winload.efi"))) {
    return $false
  }
  
  ####
  $Device_ID = $null
  $Results   = $null
  
  $Results = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /Device"  
  if ($Results) {
    $Device_ID = Pharse_GUID -Source $Results
  }
  
  if (!$Device_ID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####

  cmd /c "bcdedit $($store_Addin) /set {$($Device_ID)} device partition=$($letter):" *> $null

  ####
  $GUID = $null
  $Res  = $null
  
  $Res  = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /application osloader"
  if ($Res) {
    $GUID = Pharse_GUID -Source $Res
  }
  
  if (!$GUID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####

  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} device partition=$($letter):,{$($Device_ID)}" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} osdevice partition=$($letter):,{$($Device_ID)}" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} systemroot \windows" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} path \Windows\system32\winload.efi" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} winpe no" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} detecthal yes" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} locale en-US" *> $null
  
  if ($Add_First) {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addfirst" *> $null
  } else {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addlast" *> $null
  }

  cmd /c "bcdedit $($store_Addin) /set {bootmgr} displaybootmenu True" *> $null
  cmd /c "bcdedit $($store_Addin) /set {bootmgr} timeout 5" *> $null

  return $true
}

Function Add_VHDX_BOOT {
   param (

     [parameter(Mandatory=$True)]
     [string] $Name,
     
     [parameter(Mandatory=$True)] 
     [string] $VHD_File,

     [parameter(Mandatory=$False)]
     [string] $Store,

     [parameter(Mandatory=$False)]
     [Bool] $Add_First
   )

  $store_Addin = $null
  if ($Store -and (Test-Path($Store))) {
    $store_Addin = "/store ""$Store"""
  }

  $Item = Get-ChildItem $VHD_File
  if (!$Item.Exists) {
    return $false
  }
  
  ####
  $Device_ID = $null
  $Results   = $null
  
  $Results = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /Device"  
  if ($Results) {
    $Device_ID = Pharse_GUID -Source $Results
  }
  
  if (!$Device_ID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####

  $letter   = $item.PSDrive.Name
  $Sub_path = $item.FullName.Replace("$($item.PSDrive.Name):","")
  cmd /c "bcdedit $($store_Addin) /set {$($Device_ID)} device vhd=[$($letter):]""$($Sub_path)""" *> $null

  ####
  $GUID = $null
  $Res  = $null
  
  $Res  = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /application osloader"
  if ($Res) {
    $GUID = Pharse_GUID -Source $Res
  }
  
  if (!$GUID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####

  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} device vhd=[$($letter):]""$($Sub_path)"",{$($Device_ID)}" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} osdevice vhd=[$($letter):]""$($Sub_path)"",{$($Device_ID)}" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} systemroot \windows" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} path \Windows\system32\winload.efi" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} winpe no" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} detecthal yes" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} locale en-US" *> $null
  
  if ($Add_First) {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addfirst" *> $null
  } else {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addlast" *> $null
  }

  cmd /c "bcdedit $($store_Addin) /set {bootmgr} displaybootmenu True" *> $null
  cmd /c "bcdedit $($store_Addin) /set {bootmgr} timeout 5" *> $null

  return $true
}

# Add_RAM_DRIVE_BOOT -Name Windows_10 -Wim_File \Sources\boot.wim -Sdi_File "\Boot\boot.sdi"                         | [BOOT]
# Add_RAM_DRIVE_BOOT -Name Windows_10 -Wim_File \Sources\boot.wim -Sdi_File "\Boot\boot.sdi" -Sdi_Partition_Letter E | [E]

Function Add_RAM_DRIVE_BOOT {
   param (

     [parameter(Mandatory=$True)]
     [string] $Name,
     
     [parameter(Mandatory=$True)]
     [ValidatePattern("^(\\)(.*)(\\)(.*)(.wim|.esd|.swm)$")]
     [string] $Wim_File,

     [parameter(Mandatory=$True)]
     [ValidatePattern("^(\\)(.*)(\\)(.*)(.sdi)$")]
     [string] $Sdi_File,

     [parameter(Mandatory=$False)]
     [string] $Store,

     [ValidatePattern("^[a-zA-Z]$")]
     [parameter(Mandatory=$False)]
     [string] $Sdi_Partition_Letter,

     [parameter(Mandatory=$False)]
     [Bool] $Add_First
   )

  $store_Addin = $null
  if ($Store -and (Test-Path($Store))) {
    $store_Addin = "/store ""$Store"""
  }
  
  if ($Wim_File -and $Sdi_Partition_Letter) {
    $Wim_path = "$($Sdi_Partition_Letter):$($Wim_File)"
    if (!(Test-Path($Wim_path))) {
      Write-Host
      write-host "ERROR ## Wim File not exist"
      return $false
    }
  }

  if ($Sdi_File -and $Sdi_Partition_Letter) {
    $sdi_path = "$($Sdi_Partition_Letter):$($Sdi_File)"
    if (!(Test-Path($sdi_path))) {
      Write-Host
      write-host "ERROR ## Sdi File not exist"
      return $false
    }
  }

  if (!$Store -and !$Sdi_Partition_Letter) {
    Write-Host
    write-host "ERROR ## For local Boot store, you must use a Specific Partition"
    return $false
  }

  ####
  $Device_ID = $null
  $Results   = $null
  
  $Results = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /Device"

  if ($Results) {
    $Device_ID = Pharse_GUID -Source $Results
  }
  
  if (!$Device_ID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####
  if ($Sdi_Partition_Letter) {
    cmd /c "bcdedit $($store_Addin) /set {$($Device_ID)} ramdisksdidevice PARTITION=$($Sdi_Partition_Letter):" *> $null
  } else {
    cmd /c "bcdedit $($store_Addin) /set {$($Device_ID)} ramdisksdidevice BOOT" *> $null
  }

  cmd /c "bcdedit $($store_Addin) /set {$($Device_ID)} ramdisksdipath ""$($Sdi_File)""" *> $null

  ####
  $GUID = $null
  $Res  = $null

  $Res  = cmd /c "bcdedit $($store_Addin) /create /d ""$($Name)"" /application osloader"
  if ($Res) {
    $GUID = Pharse_GUID -Source $Res
  }
  
  if (!$GUID) {
     Write-Host
     write-host "ERROR ## Problem occurred"
     return $false
  }
  ####
   if ($Sdi_Partition_Letter) {
    cmd /c "bcdedit $($store_Addin) /set {$($GUID)} device ramdisk=[$($Sdi_Partition_Letter):]""$($Wim_File)"",{$($Device_ID)}" *> $null
    cmd /c "bcdedit $($store_Addin) /set {$($GUID)} osdevice ramdisk=[$($Sdi_Partition_Letter):]""$($Wim_File)"",{$($Device_ID)}" *> $null
  } else {
    cmd /c "bcdedit $($store_Addin) /set {$($GUID)} device ramdisk=[boot]""$($Wim_File)"",{$($Device_ID)}"  *> $null
    cmd /c "bcdedit $($store_Addin) /set {$($GUID)} osdevice ramdisk=[boot]""$($Wim_File)"",{$($Device_ID)}" *> $null
  }

  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} bootmenupolicy Standard" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} systemroot \windows" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} path \windows\system32\boot\winload.efi" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} inherit {bootloadersettings}" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} winpe yes" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} detecthal yes" *> $null
  cmd /c "bcdedit $($store_Addin) /set {$($GUID)} locale en-US" *> $null

  if ($Add_First) {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addfirst" *> $null
  } else {
    cmd /c "bcdedit $($store_Addin) /displayorder {$($GUID)} /addlast" *> $null
  }

  cmd /c "bcdedit $($store_Addin) /set {bootmgr} displaybootmenu True" *> $null
  cmd /c "bcdedit $($store_Addin) /set {bootmgr} timeout 5" *> $null

  return $true
}

enum BootType {
    unknown = 0
    Firmware_Application_101fffff = 1
    Resume_from_Hibernate = 2
    Firmware_Boot_Manager = 3
    Windows_Boot_Manager = 4
    Windows_Boot_Loader = 5
    Windows_Memory_Tester = 6
    EMS_Settings = 7
    Debugger_Settings = 8
    RAM_Defects = 9
    Global_Settings = 10
    Boot_Loader_Settings = 11
    Resume_Loader_Settings = 12
    Hypervisor_Settings = 13
    Device_options = 14
    Windows_Legacy_OS_Loader = 15
}

class Boot_info {
    [BootType]$Boot_type
    [int]$hypervisordebugport
    [int]$debugport
    [int]$baudrate
    [int]$hypervisorbaudrate
    [int]$timeout
    [string]$debugtype
    [string]$filedevice
    [string]$filepath
    [string]$identifier
    [string]$device
    [string]$path
    [string]$description
    [string]$locale
    [string]$osdevice
    [string]$inherit
    [string]$recoverysequence
    [string]$displaymessageoverride
    [string]$recoveryenabled
    [string]$isolatedcontext
    [string]$allowedinmemorysettings
    [string]$nx
    [string]$bootmenupolicy
    [string]$systemroot
    [string]$resumeobject
    [string]$hypervisordebugtype
    [string]$hypervisorlaunchtype
    [string]$bootems
    [string]$badmemoryaccess
    [string]$winpe
    [string]$default
    [string]$debugoptionenabled
    [string]$displayorder
    [string]$toolsdisplayorder
    [string]$displaybootmenu
    [string]$detecthal
    [string]$ramdisksdidevice
    [string]$ramdisksdipath

    [bool]Is_vhd(){
      if ($this.Boot_type -eq [BootType]::Windows_Boot_Loader) {
        
        # case Device Match VHD
        if ($this.osdevice -and ($this.Device -match 'vhd')) {
          return $true
        }

        # case {CURRENT} with universal Path & C drive is actualy a VHD disk
        if ($this.identifier -and ($this.identifier -eq '{current}') -and (!$this.Is_ramdisk()) -and (!$this.Is_partition()) -and (Is-VHD-System C)) {
          return $true
        }
      }
      return $false
    }

    [bool]Is_ramdisk(){
      if ($this.Boot_type -eq [BootType]::Windows_Boot_Loader) {
        if ($this.osdevice -and ($this.Device -match 'ramdisk'))
        {
          return $true
        }
      }
      return $false
    }

    [bool]Is_partition(){
      if ($this.Boot_type -eq [BootType]::Windows_Boot_Loader) {
        if ($this.osdevice -and ($this.Device -match 'partition'))
        {
          return $true
        }
      }
      return $false
    }

    [bool]Validate_vhd_Path(){
      $file_Path = $null
      $file_Path = $this.Get_VHD_Path()

      if ($file_Path -and (Test-path($file_Path))) {
          return $true
      }
      return $false
    }

    [string]Get_VHD_Path(){
      if ($this.Is_vhd() -and $this.device ) {

        # case of LiveOs Mounted VHD
        if ($this.device -match "^(.*)(Windows)(.*)(winload)(.efi|.exe)$") {
          try {
            return Get-VHD-Path C
          }
            catch {
          }
        }

        # case of Normal VHD :: PATH GUID
        $Pattern = "(^(vhd=\[)([a-zA-Z]:)\](.*)(.vhd|.vhdx)(,{.*})$)"
        $Matches = [Regex]::Matches($this.device, $Pattern)
        if ($Matches -and $Matches.Success -and $Matches[0]) {
          $ltr = $Matches[0].Groups[3].Value
          $loc = $Matches[0].Groups[4].Value
          $ext = $Matches[0].Groups[5].Value
          return "$($ltr)$($loc)$($ext)"
        }

        # case of Normal VHD :: PATH
        $Pattern = "(^(vhd=\[)([a-zA-Z]:)\](.*)(.vhd|.vhdx)$)"
        $Matches = [Regex]::Matches($this.device, $Pattern)
        if ($Matches -and $Matches.Success -and $Matches[0]) {
          $ltr = $Matches[0].Groups[3].Value
          $loc = $Matches[0].Groups[4].Value
          $ext = $Matches[0].Groups[5].Value
          return "$($ltr)$($loc)$($ext)"
        }
      }
      return $null
    }

    [int]Remove_ID(){
      if (!$this.identifier) {
        return 2
      }

      $result = start "bcdedit" -args " /delete $($this.identifier)" -Wait -WindowStyle Hidden -PassThru
      #write-host "Exit code :: $($result.ExitCode)"
      return  ($result.ExitCode -as [Int])
    }

    [int]Remove_ID([string] $Store){
      if (!$this.identifier) {
        return 2
      }

      $result = start "bcdedit" -args "/store $($Store) /delete $($this.identifier)" -Wait -WindowStyle Hidden -PassThru
      #write-host "Exit code :: $($result.ExitCode)"
      return  ($result.ExitCode -as [Int])
    }
}

function Update_Last_Access {
   param (
      [Boot_info] $data,
      [string] $last_Access,
      [string] $value
   )
   if ($last_Access -and $value) {
        switch ($last_Access)
        {
            "identifier" {$data.identifier += $value }
            "device" {$data.device  += $value }
            "path" {$data.path  += $value }
            "description" {$data.description += $value }
            "locale" {$data.locale += $value }
            "osdevice" {$data.osdevice += $value }
            "inherit" {$data.inherit += $value }
            "recoverysequence" {$data.recoverysequence += $value }
            "displaymessageoverride" {$data.displaymessageoverride += $value }
            "recoveryenabled" {$data.recoveryenabled += $value }
            "isolatedcontext" {$data.isolatedcontext += $value }
            "allowedinmemorysettings" {$data.allowedinmemorysettings += $value }
            "nx" {$data.nx += $value }
            "bootmenupolicy" {$data.bootmenupolicy += $value }
            "systemroot" {$data.systemroot += $value }
            "resumeobject" {$data.resumeobject += $value }
            "hypervisordebugtype" {$data.hypervisordebugtype += $value }
            "hypervisordebugport" {$data.hypervisordebugport += $value }
            "hypervisorbaudrate" {$data.hypervisorbaudrate += $value }
            "baudrate" {$data.baudrate += $value }
            "debugport" {$data.debugport += $value }
            "timeout" {$data.timeout += $value }
            "resumeobject" {$data.resumeobject += $value }
            "bootems" {$data.bootems += $value }
            "badmemoryaccess" {$data.badmemoryaccess += $value }
            "hypervisorlaunchtype" {$data.hypervisorlaunchtype += $value }
            "winpe" {$data.winpe += $value }
            "debugtype" {$data.debugtype += $value }
            "default" {$data.default += $value }
            "debugoptionenabled" {$data.debugoptionenabled += $value }
            "filepath" {$data.filepath += $value }
            "filedevice" {$data.filedevice += $value }
            "displayorder" {$data.displayorder += $value }
            "toolsdisplayorder" {$data.toolsdisplayorder += $value }
            "displaybootmenu" {$data.displaybootmenu += $value }
            "detecthal" {$data.detecthal += $value }
            "ramdisksdidevice" {$data.ramdisksdidevice += $value }
            "ramdisksdipath" {$data.ramdisksdipath += $value }
        }
   }
}

function Get_Boot_info {

    Param (
      [STRING]
      $path
    )

    if ($path -and (!(Test-Path($path)))) {
      return $null
    }

    $addin = $null
    if ($path) {
      $addin = "/store ""$($path)"""
    }

    $nl =    [System.Environment]::NewLine
    $store = (cmd /c "bcdedit $($addin) /enum ALL") | Out-String  #combine into one string
    $List =  $store -split "$nl$nl"                               #split the entries, only empty new lines
    $arr =   [System.Collections.ArrayList]::new()

    $List | % {
        $obj = $_ -Split $nl
        $bi = [Boot_info]::new()

        switch ($obj[0])
        {
            "Firmware Boot Manager" {$bi.Boot_type = [BootType]::Firmware_Boot_Manager}
            "Windows Boot Manager" {$bi.Boot_type = [BootType]::Windows_Boot_Manager}
            "Firmware Application (101fffff)" {$bi.Boot_type = [BootType]::Firmware_Application_101fffff}
            "Windows Boot Loader" {$bi.Boot_type = [BootType]::Windows_Boot_Loader}
            "Resume from Hibernate" {$bi.Boot_type = [BootType]::Resume_from_Hibernate}
            "Windows Memory Tester" {$bi.Boot_type = [BootType]::Windows_Memory_Tester}
            "EMS Settings" {$bi.Boot_type = [BootType]::EMS_Settings}
            "Debugger Settings" {$bi.Boot_type = [BootType]::Debugger_Settings}
            "RAM Defects" {$bi.Boot_type = [BootType]::RAM_Defects}
            "Global Settings" {$bi.Boot_type = [BootType]::Global_Settings}
            "Boot Loader Settings" {$bi.Boot_type = [BootType]::Boot_Loader_Settings}
            "Hypervisor Settings" {$bi.Boot_type = [BootType]::Hypervisor_Settings}
            "Resume Loader Settings" {$bi.Boot_type = [BootType]::Resume_Loader_Settings}
            "Device options" {$bi.Boot_type = [BootType]::Device_options}
            "Windows Legacy OS Loader" {$bi.Boot_type = [BootType]::Windows_Legacy_OS_Loader}
            default {$bi.Boot_type = [BootType]::unknown}
        }

        switch ($obj[1])
        {
            "Firmware Boot Manager" {$bi.Boot_type = [BootType]::Firmware_Boot_Manager}
            "Windows Boot Manager" {$bi.Boot_type = [BootType]::Windows_Boot_Manager}
            "Firmware Application (101fffff)" {$bi.Boot_type = [BootType]::Firmware_Application_101fffff}
            "Windows Boot Loader" {$bi.Boot_type = [BootType]::Windows_Boot_Loader}
            "Resume from Hibernate" {$bi.Boot_type = [BootType]::Resume_from_Hibernate}
            "Windows Memory Tester" {$bi.Boot_type = [BootType]::Windows_Memory_Tester}
            "EMS Settings" {$bi.Boot_type = [BootType]::EMS_Settings}
            "Debugger Settings" {$bi.Boot_type = [BootType]::Debugger_Settings}
            "RAM Defects" {$bi.Boot_type = [BootType]::RAM_Defects}
            "Global Settings" {$bi.Boot_type = [BootType]::Global_Settings}
            "Boot Loader Settings" {$bi.Boot_type = [BootType]::Boot_Loader_Settings}
            "Hypervisor Settings" {$bi.Boot_type = [BootType]::Hypervisor_Settings}
            "Device options" {$bi.Boot_type = [BootType]::Device_options}
            "Windows Legacy OS Loader" {$bi.Boot_type = [BootType]::Windows_Legacy_OS_Loader}
            "Resume Loader Settings" {$bi.Boot_type = [BootType]::Resume_Loader_Settings}
        }

        $last_Access = $null
        ForEach ($itm in $obj)
        {
            $raw  = [regex]::Replace($itm, "\s+", " ")
            $data = $raw.Split(' ')
            switch ($data[0])
            {
                "identifier" {$bi.identifier = $raw.Substring($data[0].Length+1); $last_Access='identifier'}
                "device" {if ($data[1] -ne 'options') {$bi.device  = $raw.Substring($data[0].Length+1); $last_Access='device'}}
                "path" {$bi.path  = $raw.Substring($data[0].Length+1); $last_Access='path'}
                "description" {$bi.description  = $raw.Substring($data[0].Length+1); $last_Access='description'}
                "locale" {$bi.locale = $raw.Substring($data[0].Length+1); $last_Access='locale'}
                "osdevice" {$bi.osdevice = $raw.Substring($data[0].Length+1); $last_Access='osdevice'}
                "inherit" {$bi.inherit = $raw.Substring($data[0].Length+1); $last_Access='inherit'}
                "recoverysequence" {$bi.recoverysequence = $raw.Substring($data[0].Length+1); $last_Access='recoverysequence'}
                "displaymessageoverride" {$bi.displaymessageoverride = $raw.Substring($data[0].Length+1); $last_Access='displaymessageoverride'}
                "recoveryenabled" {$bi.recoveryenabled = $raw.Substring($data[0].Length+1); $last_Access='recoveryenabled'}
                "isolatedcontext" {$bi.isolatedcontext = $raw.Substring($data[0].Length+1); $last_Access='isolatedcontext'}
                "allowedinmemorysettings" {$bi.allowedinmemorysettings = $raw.Substring($data[0].Length+1); $last_Access='allowedinmemorysettings'}
                "nx" {$bi.nx = $raw.Substring($data[0].Length+1); $last_Access='nx'}
                "bootmenupolicy" {$bi.bootmenupolicy = $raw.Substring($data[0].Length+1); $last_Access='bootmenupolicy'}
                "systemroot" {$bi.systemroot = $raw.Substring($data[0].Length+1); $last_Access='systemroot'}
                "resumeobject" {$bi.resumeobject = $raw.Substring($data[0].Length+1); $last_Access='resumeobject'}
                "hypervisordebugtype" {$bi.hypervisordebugtype = $raw.Substring($data[0].Length+1); $last_Access='hypervisordebugtype'}
                "hypervisordebugport" {$bi.hypervisordebugport = $data[1] -as [INT]; $last_Access='hypervisordebugport'}
                "hypervisorbaudrate" {$bi.hypervisorbaudrate = $data[1] -as [INT]; $last_Access='hypervisorbaudrate'}
                "baudrate" {$bi.baudrate = $data[1] -as [INT]; $last_Access='baudrate'}
                "debugport" {$bi.debugport = $data[1] -as [INT]; $last_Access='debugport'}
                "timeout" {$bi.timeout = $data[1] -as [INT]; $last_Access='timeout'}
                "bootems" {$bi.bootems = $raw.Substring($data[0].Length+1); $last_Access='bootems'}
                "badmemoryaccess" {$bi.badmemoryaccess = $raw.Substring($data[0].Length+1); $last_Access='badmemoryaccess'}
                "hypervisorlaunchtype" {$bi.hypervisorlaunchtype = $raw.Substring($data[0].Length+1); $last_Access='hypervisorlaunchtype'}
                "winpe" {$bi.winpe = $raw.Substring($data[0].Length+1); $last_Access='winpe'}
                "debugtype" {$bi.debugtype = $raw.Substring($data[0].Length+1); $last_Access='debugtype'}
                "default" {$bi.default = $raw.Substring($data[0].Length+1); $last_Access='default'}
                "debugoptionenabled" {$bi.debugoptionenabled = $raw.Substring($data[0].Length+1); $last_Access='debugoptionenabled'}
                "filepath" {$bi.filepath = $raw.Substring($data[0].Length+1); $last_Access='filepath'}
                "filedevice" {$bi.filedevice = $raw.Substring($data[0].Length+1); $last_Access='filedevice'}
                "displayorder" {$bi.displayorder = $raw.Substring($data[0].Length+1); $last_Access='displayorder'}
                "toolsdisplayorder" {$bi.toolsdisplayorder = $raw.Substring($data[0].Length+1); $last_Access='toolsdisplayorder'}
                "displaybootmenu" {$bi.displaybootmenu = $raw.Substring($data[0].Length+1); $last_Access='displaybootmenu'}
                "detecthal" {$bi.detecthal = $raw.Substring($data[0].Length+1); $last_Access='detecthal'}
                "ramdisksdidevice" {$bi.ramdisksdidevice = $raw.Substring($data[0].Length+1); $last_Access='ramdisksdidevice'}
                "ramdisksdipath" {$bi.ramdisksdipath = $raw.Substring($data[0].Length+1); $last_Access='ramdisksdipath'}
                "Firmware" {continue}
                "Windows" {continue}
                "Resume" {continue}
                "EMS" {continue}
                "Debugger" {continue}
                "RAM" {continue}
                "Global" {continue}
                "Boot" {continue}
                "Hypervisor"{continue}
                default { Update_last_access -Data $bi -last_Access $last_Access -value $data }
            }
        }
        $arr.Add($bi) | out-null
    }
  
    return $arr
}

PSD File

@{
GUID="9e256ffa-df61-4bc0-93d2-bdbd6f9bf566"
Author="Mr X.Y.Z"
CompanyName="Microsoft Corporation"
Copyright="© Microsoft Corporation. All rights reserved."
ModuleVersion="1.6.0.0"
PowerShellVersion = '5.1'
CLRVersion="4.0"
FunctionsToExport= "Get_Boot_info", "Add_PARTITION_BOOT","Add_VHDX_BOOT","Add_RAM_DRIVE_BOOT","Is-VHD-System","Get-VHD-Path"
NestedModules="Microsoft.Windows.BcdLIB.Cmdlets.psm1"
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=390787'
CompatiblePSEditions = @('Desktop')
}

Mayemayeda answered 13/6, 2023 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.