bcdedit, bcdstore and powershell
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\HarddiskVolume1description Windows Boot Managerlocale en-US...Windows Boot Loader-------------------identifier {current}device partition=C:path \Windows\system32\winload.exedescription Windows 7locale en-US...Windows Boot Loader-------------------identifier {e0610d98-e116-11e1-8aa3-e57ee342122d}device partition=C:path \Windows\system32\winload.exedescription DebugEntrylocale 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.
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}
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 /enumforeach ($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 resultsforeach ( $item in $Configs){ $item | Format-Table}