Skip to content

Instantly share code, notes, and snippets.

@jborean93
Created May 18, 2026 03:36
Show Gist options
  • Select an option

  • Save jborean93/24fa71278a8c4c365007735fe30605ae to your computer and use it in GitHub Desktop.

Select an option

Save jborean93/24fa71278a8c4c365007735fe30605ae to your computer and use it in GitHub Desktop.
Get and parse SMBIOS data using PowerShell
# Copyright: (c) 2026, Jordan Borean (@jborean93) <jborean93@gmail.com>
# MIT License (see LICENSE or https://opensource.org/licenses/MIT)
function Get-RawSmbiosData {
[OutputType([byte[]])]
[CmdletBinding()]
param ()
Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
public static class FirmwareTables
{
[DllImport("kernel32.dll", SetLastError=true)]
private static extern int GetSystemFirmwareTable(
int FirmwareTableProviderSignature,
int FirmwareTableID,
IntPtr pFirmwareTableBuffer,
int BufferSize);
public static byte[] GetRsmbTable()
{
const int RSMB = 0x52534D42; // 'RSMB' in ASCII
int size = GetSystemFirmwareTable(RSMB, 0, IntPtr.Zero, 0);
if (size == 0)
{
throw new Win32Exception();
}
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
int result = GetSystemFirmwareTable(RSMB, 0, buffer, size);
if (result == 0)
{
throw new Win32Exception();
}
byte[] rawData = new byte[size];
Marshal.Copy(buffer, rawData, 0, size);
return rawData;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
}
'@
try {
$rawData = [FirmwareTables]::GetRsmbTable()
$callingMethod = $rawData[0]
$smbiosMajorVersion = $rawData[1]
$smbiosMinorVersion = $rawData[2]
$dmiRevision = $rawData[3]
$smbiosTableLength = [BitConverter]::ToInt32($rawData, 4)
$data = [byte[]]::new($smbiosTableLength)
if ($rawData.Length -lt (8 + $smbiosTableLength)) {
throw "The raw data length is insufficient for the specified SMBIOS table length."
}
[Array]::Copy($rawData, 8, $data, 0, $smbiosTableLength)
[PSCustomObject]@{
CallingMethod = $callingMethod
SmbiosVersion = [Version]"$($smbiosMajorVersion).$smbiosMinorVersion"
DmiRevision = $dmiRevision
Length = $smbiosTableLength
Data = $data
}
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
function Get-SmbiosEntry {
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias("Data")]
[byte[]]
$InputObject,
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias("SmbiosVersion")]
[Version]
$Version
)
$readString = {
param ([string[]]$Table, [byte]$Index)
if ($Index -le $Table.Length) {
return $Table[$Index - 1]
}
else {
return $null
}
}
$typeUnpacker = @{
# BIOS Information (Type 0)
0 = {
param ([IO.BinaryReader]$Reader, [string[]]$StringTable)
$props = [Ordered]@{
Vendor = & $readString $StringTable $Reader.ReadByte()
Version = & $readString $StringTable $Reader.ReadByte()
BiosStartingAddressSegment = $Reader.ReadInt16()
ReleaseDate = & $readString $StringTable $Reader.ReadByte()
RomSize = $Reader.ReadByte()
Characteristics = $Reader.ReadInt64()
}
[PSCustomObject]$props
}
# System Information (Type 1)
1 = {
param ([IO.BinaryReader]$Reader, [string[]]$StringTable)
$props = [Ordered]@{
Manufacturer = & $readString $StringTable $Reader.ReadByte()
ProductName = & $readString $StringTable $Reader.ReadByte()
Version = & $readString $StringTable $Reader.ReadByte()
SerialNumber = & $readString $StringTable $Reader.ReadByte()
}
if ($Version -ge '2.1') {
$props.Uuid = [Guid]::New($Reader.ReadBytes(16))
$props.WakeUpType = $Reader.ReadByte()
}
if ($Version -ge '2.4') {
$props.SkuNumber = & $readString $StringTable $Reader.ReadByte()
$props.Family = & $readString $StringTable $Reader.ReadByte()
}
[PSCustomObject]$props
}
# System Enclosure (Type 3)
3 = {
param ([IO.BinaryReader]$Reader, [string[]]$StringTable)
$props = [Ordered]@{
Manufacturer = & $readString $StringTable $Reader.ReadByte()
ChassisType = $Reader.ReadByte()
Version = & $readString $StringTable $Reader.ReadByte()
SerialNumber = & $readString $StringTable $Reader.ReadByte()
AssetTagNumber = & $readString $StringTable $Reader.ReadByte()
}
if ($Version -ge '2.1') {
$props.BootupState = $Reader.ReadByte()
$props.PowerSupplyState = $Reader.ReadByte()
$props.ThermalState = $Reader.ReadByte()
$props.SecurityStatus = $Reader.ReadByte()
}
if ($Version -ge '2.3') {
$props.OemDefined = $Reader.ReadInt32()
$props.Height = $Reader.ReadByte()
$props.NumberOfPowerCords = $Reader.ReadByte()
$props.ContainedElementCount = $Reader.ReadByte()
$props.ContainedElementRecordLength = $Reader.ReadByte()
$props.ContainedElements = @(
for ($i = 0; $i -lt $props.ContainedElementCount; $i++) {
[PSCustomObject]@{
Type = $Reader.ReadByte()
Length = $Reader.ReadByte()
Handle = $Reader.ReadInt16()
}
}
)
}
if ($Version -ge '2.7') {
$props.SkuNumber = & $readString $StringTable $Reader.ReadByte()
}
[PSCustomObject]$props
}
# Processor Information (Type 4)
4 = {
param ([IO.BinaryReader]$Reader, [string[]]$StringTable)
$props = [Ordered]@{
SocketDesignation = & $readString $StringTable $Reader.ReadByte()
ProcessorType = $Reader.ReadByte()
ProcessorFamily = $Reader.ReadByte()
Manufacturer = & $readString $StringTable $Reader.ReadByte()
ProcessorId = $Reader.ReadInt64()
ProcessorVersion = & $readString $StringTable $Reader.ReadByte()
Voltage = $Reader.ReadByte()
ExternalClock = $Reader.ReadInt16()
MaxSpeed = $Reader.ReadInt16()
CurrentSpeed = $Reader.ReadInt16()
Status = $Reader.ReadByte()
ProcessorUpgrade = $Reader.ReadByte()
}
if ($Version -ge '2.1') {
$props.L1CacheHandle = $Reader.ReadInt16()
$props.L2CacheHandle = $Reader.ReadInt16()
$props.L3CacheHandle = $Reader.ReadInt16()
}
if ($Version -ge '2.3') {
$props.SerialNumber = & $readString $StringTable $Reader.ReadByte()
$props.AssetTag = & $readString $StringTable $Reader.ReadByte()
$props.PartNumber = & $readString $StringTable $Reader.ReadByte()
}
if ($Version -ge '2.5') {
$props.CoreCount = $Reader.ReadByte()
$props.CoreEnabled = $Reader.ReadByte()
$props.ThreadCount = $Reader.ReadByte()
$props.ProcessorCharacteristics = $Reader.ReadInt16()
}
if ($Version -ge '2.6') {
$props.ProcessorFamily2 = $Reader.ReadInt16()
}
if ($Version -ge '3.0') {
$props.CoreCount2 = $Reader.ReadInt16()
$props.CoreEnabled2 = $Reader.ReadInt16()
$props.ThreadCount2 = $Reader.ReadInt16()
}
[PSCustomObject]$props
}
# End of Table (Type 127)
127 = {
param ([IO.BinaryReader]$Reader, [string[]]$StringTable)
[PSCustomObject]@{}
}
}
Write-Verbose "Parsing SMBIOS data with version $Version"
$current = $InputObject
while ($current.Length) {
try {
if ($current.Length -lt 4) {
$current = @()
throw "Remaining data is too short to contain a valid SMBIOS entry header"
}
$headerType = $current[0]
$headerLength = $current[1]
$headerHandle = [BitConverter]::ToInt16($current, 2)
$headerData = [byte[]]$current[4..($headerLength + 3)]
Write-Verbose "Processing SMBIOS entry of type $headerType with handle $headerHandle and length $headerLength"
# Extract the string table after the header data
$i = $headerLength
while (($i + 1) -le $current.Length) {
if ($current[$i] -eq 0 -and $current[$i + 1] -eq 0) {
break
}
$i++
}
if ($i -gt $current.Length) {
$rawHeaderStrings = $current[$headerLength..($current.Length - 1)]
$current = @()
} else {
$rawHeaderStrings = $current[$headerLength..($i - 1)]
$current = $current[($i + 2)..($current.Length - 1)]
}
$stringTable = [Text.Encoding]::UTF8.GetString($rawHeaderStrings) -split "`0"
if ($typeUnpacker.ContainsKey([int]$headerType)) {
$rawStream = [IO.MemoryStream]::new($headerData)
$reader = [IO.BinaryReader]::new($rawStream)
$entry = & $typeUnpacker[[int]$headerType] -Reader $reader -StringTable $stringTable
$entry | Add-Member -MemberType NoteProperty -Name Type -Value $headerType -Force
$entry | Add-Member -MemberType NoteProperty -Name Handle -Value $headerHandle -Force
$entry | Add-Member -MemberType NoteProperty -Name RawData -Value ([Convert]::ToBase64String($headerData)) -Force
$entry | Add-Member -MemberType NoteProperty -Name StringTable -Value $stringTable -Force
$entry
} else {
[PSCustomObject]@{
Type = $headerType
Handle = $headerHandle
RawData = [Convert]::ToBase64String($headerData)
StringTable = $stringTable
}
}
if ($headerType -eq 127) {
break
}
}
catch {
$PSCmdlet.WriteError($_)
}
}
}
Get-RawSmbiosData | Get-SmbiosEntry -Verbose | ConvertTo-Json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment