Advertisement
jheinrichs79

Legacy BIOS vs UEFI

Oct 29th, 2019
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2.  
  3. This script shows three methods to determine the underlying system firmware (BIOS) type - either UEFI or Legacy BIOS.
  4.  
  5. The first method relies on the fact that Windows setup detects the firmware type as a part of the Windows installation
  6. routine and records its findings in the setupact.log file in the \Windows\Panther folder.  It's a trivial task to use
  7. Select-String to extract the relevent line from this file and to pick off the (U)EFI or BIOS keyword it contains.
  8.  
  9. To do a proper job there are two choices; both involve using Win32 APIs which we call from PowerShell through a compiled
  10. (Add-Type) class using P/Invoke.
  11.  
  12. For Windows 7/Server 2008R2 and above, the GetFirmwareEnvironmentVariable Win32 API (designed to extract firmware environment
  13. variables) can be used.  This API is not supported on non-UEFI firmware and will fail in a predictable way when called - this
  14. will identify a legacy BIOS.  On UEFI firmware, the API can be called with dummy parameters, and while it will still fail
  15. (probably!) the resulting error code will be different from the legacy BIOS case.
  16.  
  17. For Windows 8/Server 2012 and above there's a more elegant solution in the form of the GetFirmwareType() API.  This
  18. returns an enum (integer) indicating the underlying firmware type.
  19.  
  20. Chris Warwick, @cjwarwickps,  September 2013
  21. chrisjwarwick.wordpress.com
  22.  
  23. #>
  24.  
  25.  
  26.  
  27. # First method, one-liner, extract answer from setupact.log using Select-String and tidy-up with -replace
  28.  
  29. # Look in the setup logfile to see what bios type was detected (EFI or BIOS)
  30. (Select-String 'Detected boot environment' C:\Windows\Panther\setupact.log -AllMatches ).line -replace '.*:\s+'
  31.  
  32.  
  33.  
  34.  
  35. <#
  36. Second method, use the GetFirmwareEnvironmentVariable Win32 API.
  37.  
  38. From MSDN (http://msdn.microsoft.com/en-ca/library/windows/desktop/ms724325%28v=vs.85%29.aspx):
  39.  
  40. "Firmware variables are not supported on a legacy BIOS-based system. The GetFirmwareEnvironmentVariable function will
  41. always fail on a legacy BIOS-based system, or if Windows was installed using legacy BIOS on a system that supports both
  42. legacy BIOS and UEFI.
  43.  
  44. "To identify these conditions, call the function with a dummy firmware environment name such as an empty string ("") for
  45. the lpName parameter and a dummy GUID such as "{00000000-0000-0000-0000-000000000000}" for the lpGuid parameter.
  46. On a legacy BIOS-based system, or on a system that supports both legacy BIOS and UEFI where Windows was installed using
  47. legacy BIOS, the function will fail with ERROR_INVALID_FUNCTION. On a UEFI-based system, the function will fail with
  48. an error specific to the firmware, such as ERROR_NOACCESS, to indicate that the dummy GUID namespace does not exist."
  49.  
  50.  
  51. From PowerShell, we can call the API via P/Invoke from a compiled C# class using Add-Type.  In Win32 any resulting
  52. API error is retrieved using GetLastError(), however, this is not reliable in .Net (see
  53. blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx), instead we mark the pInvoke signature for
  54. GetFirmwareEnvironmentVariableA with SetLastError=true and use Marshal.GetLastWin32Error()
  55.  
  56. Note: The GetFirmwareEnvironmentVariable API requires the SE_SYSTEM_ENVIRONMENT_NAME privilege.  In the Security
  57. Policy editor this equates to "User Rights Assignment": "Modify firmware environment values" and is granted to
  58. Administrators by default.  Because we don't actually read any variables this permission appears to be optional.
  59.  
  60. #>
  61.  
  62.  
  63. Function IsUEFI {
  64.  
  65. <#
  66. .Synopsis
  67.    Determines underlying firmware (BIOS) type and returns True for UEFI or False for legacy BIOS.
  68. .DESCRIPTION
  69.    This function uses a complied Win32 API call to determine the underlying system firmware type.
  70. .EXAMPLE
  71.    If (IsUEFI) { # System is running UEFI firmware... }
  72. .OUTPUTS
  73.    [Bool] True = UEFI Firmware; False = Legacy BIOS
  74. .FUNCTIONALITY
  75.    Determines underlying system firmware type
  76. #>
  77.  
  78. [OutputType([Bool])]
  79. Param ()
  80.  
  81. Add-Type -Language CSharp -TypeDefinition @'
  82.  
  83.    using System;
  84.    using System.Runtime.InteropServices;
  85.  
  86.    public class CheckUEFI
  87.    {
  88.        [DllImport("kernel32.dll", SetLastError=true)]
  89.        static extern UInt32
  90.        GetFirmwareEnvironmentVariableA(string lpName, string lpGuid, IntPtr pBuffer, UInt32 nSize);
  91.  
  92.        const int ERROR_INVALID_FUNCTION = 1;
  93.  
  94.        public static bool IsUEFI()
  95.        {
  96.            // Try to call the GetFirmwareEnvironmentVariable API.  This is invalid on legacy BIOS.
  97.  
  98.            GetFirmwareEnvironmentVariableA("","{00000000-0000-0000-0000-000000000000}",IntPtr.Zero,0);
  99.  
  100.            if (Marshal.GetLastWin32Error() == ERROR_INVALID_FUNCTION)
  101.  
  102.                return false;     // API not supported; this is a legacy BIOS
  103.  
  104.            else
  105.  
  106.                return true;      // API error (expected) but call is supported.  This is UEFI.
  107.        }
  108.    }
  109. '@
  110.  
  111.  
  112.     [CheckUEFI]::IsUEFI()
  113. }
  114.  
  115.  
  116.  
  117.  
  118. <#
  119.  
  120. Third method, use GetFirmwareTtype() Win32 API.
  121.  
  122. In Windows 8/Server 2012 and above there's an API that directly returns the firmware type and doesn't rely on a hack.
  123. GetFirmwareType() in kernel32.dll (http://msdn.microsoft.com/en-us/windows/desktop/hh848321%28v=vs.85%29.aspx) returns
  124. a pointer to a FirmwareType enum that defines the following:
  125.  
  126. typedef enum _FIRMWARE_TYPE {
  127.   FirmwareTypeUnknown  = 0,
  128.   FirmwareTypeBios     = 1,
  129.   FirmwareTypeUefi     = 2,
  130.   FirmwareTypeMax      = 3
  131. } FIRMWARE_TYPE, *PFIRMWARE_TYPE;
  132.  
  133. Once again, this API call can be called in .Net via P/Invoke.  Rather than defining an enum the function below
  134. just returns an unsigned int.
  135.  
  136. #>
  137.  
  138.  
  139.  
  140.  
  141. # Windows 8/Server 2012 or above:
  142.  
  143.  
  144. Function Get-BiosType {
  145.  
  146. <#
  147. .Synopsis
  148.    Determines underlying firmware (BIOS) type and returns an integer indicating UEFI, Legacy BIOS or Unknown.
  149.    Supported on Windows 8/Server 2012 or later
  150. .DESCRIPTION
  151.    This function uses a complied Win32 API call to determine the underlying system firmware type.
  152. .EXAMPLE
  153.    If (Get-BiosType -eq 1) { # System is running UEFI firmware... }
  154. .EXAMPLE
  155.     Switch (Get-BiosType) {
  156.         1       {"Legacy BIOS"}
  157.         2       {"UEFI"}
  158.         Default {"Unknown"}
  159.     }
  160. .OUTPUTS
  161.    Integer indicating firmware type (1 = Legacy BIOS, 2 = UEFI, Other = Unknown)
  162. .FUNCTIONALITY
  163.    Determines underlying system firmware type
  164. #>
  165.  
  166. [OutputType([UInt32])]
  167. Param()
  168.  
  169. Add-Type -Language CSharp -TypeDefinition @'
  170.  
  171.    using System;
  172.    using System.Runtime.InteropServices;
  173.  
  174.    public class FirmwareType
  175.    {
  176.        [DllImport("kernel32.dll")]
  177.        static extern bool GetFirmwareType(ref uint FirmwareType);
  178.  
  179.        public static uint GetFirmwareType()
  180.        {
  181.            uint firmwaretype = 0;
  182.            if (GetFirmwareType(ref firmwaretype))
  183.                return firmwaretype;
  184.            else
  185.                return 0;   // API call failed, just return 'unknown'
  186.        }
  187.    }
  188. '@
  189.  
  190.  
  191.     [FirmwareType]::GetFirmwareType()
  192. }
  193.  
  194.  
  195.  
  196. # An electron is pulled-up for speeding. The policeman says, “Sir, do you realise you were travelling at 130mph?” The electron says, “Oh great, now I’m lost.”
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement