Question:
I am looking for a way to reliably detect when I boot into WinPE 4 (powershell) (or WinPE 3 (vbs) as an alternative), have I booted from a UEFI or BIOS System? (without running a third party exe as I am in a restricted environment)
This significantly changes how I would be partitioning a windows deployment as the partitions layout changes and format. (GPT vs. MBR, etc)
I have one working that is an adaptation of this C++ code in powershell v3 but it feels pretty hack-ish :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
## Check if we can get a dummy flag from the UEFI via the Kernel ## [Bool] check the result of the kernel's fetch of the dummy GUID from UEFI ## The only way I found to do it was using the C++ compiler in powershell Function Compile-UEFIDectectionClass{ $win32UEFICode= @' using System; using System.Runtime.InteropServices; public class UEFI { [DllImport("kernel32.dll")] public static extern UInt32 GetFirmwareEnvironmentVariableA([MarshalAs(UnmanagedType.LPWStr)] string lpName, [MarshalAs(UnmanagedType.LPWStr)] string lpGuid, IntPtr pBuffer, UInt32 nSize); public static UInt32 Detect() { return GetFirmwareEnvironmentVariableA("", "{00000000-0000-0000-0000-000000000000}", IntPtr.Zero, 0); } } '@ Add-Type $win32UEFICode } ## A Function added just to check if the assembly for ## UEFI is loaded as is the name of the class above in C++. Function Check-IsUEFIClassLoaded{ return ([System.AppDomain]::CurrentDomain.GetAssemblies() | % { $_.GetTypes()} | ? {$_.FullName -eq "UEFI"}).Count } ## Just incase someone was to call my code without running the Compiled code run first If (!(Check-IsUEFIClassLoaded)){ Compile-UEFIDectectionClass } ## The meat of the checking. ## Returns 0 or 1 ([BOOL] if UEFI or not) Function Get-UEFI{ return [UEFI]::Detect() } |
This seems pretty over the top just to get a simple flag.
Does anyone know if there is there a better way to get this done?
Answer:
It is no less hacky, in the sense it will still require interop from powershell, but the interop code might be neater if you use (or can call): GetFirmwareType()
.
This returns a FIRMWARE_TYPE
enumeration documented here. I can’t believe given both functions are introduced in Windows 8 and exported by kernel32.dll that Microsoft’s own documentation points you at “using a dummy variable”!
Internally, GetFirmwareType
calls NtQuerySystemInformation
. I will dig into what it is doing, but I do not think it is necessarily going to be enlightening.
Unfortunately, this only works for PE4 (Windows 8) since these functions were only added then.