serverRoom/backend-csharp/AmtScanner.Api/Services/AmtHardwareQueryService.cs
lvfengfree eebbacafde feat: 实现OS设备扫描和UUID绑定功能
- 添加OsDevice模型和OsDevicesController
- 实现WindowsScannerService用于网络扫描和WMI查询
- 添加AMT设备UUID查询功能(从CIM_ComputerSystemPackage获取PlatformGUID)
- 实现PlatformGUID到标准UUID格式的转换(字节序转换)
- 修复HardwareInfoRepository保存UUID的问题
- 前端添加OS设备管理页面和UUID获取/刷新按钮
- 添加数据库迁移脚本
2026-01-21 16:16:48 +08:00

837 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AmtScanner.Api.Models;
using Intel.Management.Wsman;
using System.Security;
namespace AmtScanner.Api.Services;
public class AmtHardwareQueryService : IAmtHardwareQueryService
{
private readonly ILogger<AmtHardwareQueryService> _logger;
public AmtHardwareQueryService(ILogger<AmtHardwareQueryService> logger)
{
_logger = logger;
}
public async Task<HardwareInfo> QueryHardwareInfoAsync(
string ipAddress,
string username,
string password,
List<int> openPorts)
{
var hardwareInfo = new HardwareInfo
{
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
LastUpdated = DateTime.UtcNow
};
try
{
// Determine protocol and port
string protocol;
int port;
if (openPorts.Contains(16992))
{
protocol = "http";
port = 16992;
}
else if (openPorts.Contains(16993))
{
protocol = "https";
port = 16993;
}
else
{
throw new Exception("No suitable AMT port found");
}
_logger.LogInformation("Querying hardware info from {Protocol}://{Ip}:{Port}", protocol, ipAddress, port);
// Create secure password
var securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
securePassword.MakeReadOnly();
// Create WS-Management connection
var connection = new WsmanConnection();
connection.Address = $"{protocol}://{ipAddress}:{port}/wsman";
connection.SetCredentials(username, securePassword);
// Accept self-signed certificates for HTTPS
if (protocol == "https")
{
connection.Options.ServerCertificateValidationCallback = (certificate, sslPolicyErrors) =>
{
if (certificate.Subject.Equals(certificate.Issuer))
{
return true;
}
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
return false;
};
}
await Task.Run(() =>
{
// Query all hardware components sequentially (not in parallel)
QuerySystemInfo(connection, hardwareInfo);
QueryProcessorInfo(connection, hardwareInfo);
QueryMemoryInfo(connection, hardwareInfo);
QueryStorageInfo(connection, hardwareInfo);
});
_logger.LogInformation("Successfully queried hardware info from {Ip}", ipAddress);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error querying hardware info from {Ip}", ipAddress);
throw;
}
return hardwareInfo;
}
private void QuerySystemInfo(IWsmanConnection connection, HardwareInfo hardwareInfo)
{
try
{
_logger.LogDebug("Querying system information");
var query = connection.ExecQuery("SELECT * FROM CIM_ComputerSystem WHERE Name='ManagedSystem'");
int count = 0;
foreach (IWsmanItem item in query)
{
count++;
_logger.LogDebug("Found CIM_ComputerSystem item {Count}", count);
var manufacturer = item.Object.GetProperty("Manufacturer");
_logger.LogDebug("Manufacturer IsNull: {IsNull}, Value: {Value}", manufacturer.IsNull, manufacturer.IsNull ? "null" : manufacturer.ToString());
if (!manufacturer.IsNull)
{
hardwareInfo.SystemManufacturer = manufacturer.ToString();
}
var model = item.Object.GetProperty("Model");
_logger.LogDebug("Model IsNull: {IsNull}, Value: {Value}", model.IsNull, model.IsNull ? "null" : model.ToString());
if (!model.IsNull)
{
hardwareInfo.SystemModel = model.ToString();
}
// Try to get serial number (may not be available)
try
{
var serialNumber = item.Object.GetProperty("SerialNumber");
_logger.LogDebug("SerialNumber IsNull: {IsNull}, Value: {Value}", serialNumber.IsNull, serialNumber.IsNull ? "null" : serialNumber.ToString());
if (!serialNumber.IsNull)
{
hardwareInfo.SystemSerialNumber = serialNumber.ToString();
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Serial number property not available");
}
break; // Only need first result
}
if (count == 0)
{
_logger.LogWarning("No CIM_ComputerSystem items found");
}
_logger.LogDebug("System info: {Manufacturer} {Model}",
hardwareInfo.SystemManufacturer, hardwareInfo.SystemModel);
// Query UUID from CIM_ComputerSystemPackage (在同一个 try 块内查询,确保连接有效)
QuerySystemUuid(connection, hardwareInfo);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to query system information");
}
}
private void QuerySystemUuid(IWsmanConnection connection, HardwareInfo hardwareInfo)
{
try
{
_logger.LogInformation("Querying system UUID");
// 通过 CIM_ComputerSystemPackage 获取 PlatformGUID (UUID)
var query = connection.ExecQuery("SELECT * FROM CIM_ComputerSystemPackage");
foreach (IWsmanItem item in query)
{
try
{
// 尝试获取 PlatformGUID
var platformGuid = item.Object.GetProperty("PlatformGUID");
_logger.LogInformation("PlatformGUID IsNull: {IsNull}, Value: {Value}",
platformGuid.IsNull, platformGuid.IsNull ? "null" : platformGuid.ToString());
if (!platformGuid.IsNull && !string.IsNullOrWhiteSpace(platformGuid.ToString()))
{
var rawGuid = platformGuid.ToString().Trim();
// 将 PlatformGUID 转换为标准 UUID 格式
var formattedUuid = FormatPlatformGuidToUuid(rawGuid);
hardwareInfo.SystemUuid = formattedUuid;
_logger.LogInformation("Found UUID from CIM_ComputerSystemPackage.PlatformGUID: Raw={Raw}, Formatted={Formatted}",
rawGuid, formattedUuid);
return;
}
}
catch (Exception ex)
{
_logger.LogInformation(ex, "PlatformGUID not available from CIM_ComputerSystemPackage");
}
// 备选:尝试从 Antecedent (CIM_Chassis) 获取 UUID
try
{
var antecedent = item.Object.GetProperty("Antecedent");
_logger.LogInformation("Antecedent IsNull: {IsNull}, IsA CIM_Chassis: {IsChassis}",
antecedent.IsNull, !antecedent.IsNull && antecedent.IsA("CIM_Chassis"));
if (!antecedent.IsNull && antecedent.IsA("CIM_Chassis"))
{
var chassisObj = antecedent.Ref.Get();
var uuid = chassisObj.GetProperty("UUID");
_logger.LogInformation("CIM_Chassis UUID IsNull: {IsNull}, Value: {Value}",
uuid.IsNull, uuid.IsNull ? "null" : uuid.ToString());
if (!uuid.IsNull && !string.IsNullOrWhiteSpace(uuid.ToString()))
{
hardwareInfo.SystemUuid = uuid.ToString().Trim();
_logger.LogInformation("Found UUID from CIM_Chassis: {Uuid}", hardwareInfo.SystemUuid);
return;
}
}
}
catch (Exception ex)
{
_logger.LogInformation(ex, "UUID not available from CIM_Chassis");
}
}
// 备选方案:尝试从 CIM_PhysicalPackage 获取
try
{
_logger.LogInformation("Trying CIM_PhysicalPackage for UUID");
var physicalQuery = connection.ExecQuery("SELECT * FROM CIM_PhysicalPackage");
foreach (IWsmanItem item in physicalQuery)
{
try
{
var uuid = item.Object.GetProperty("UUID");
_logger.LogInformation("CIM_PhysicalPackage UUID IsNull: {IsNull}, Value: {Value}",
uuid.IsNull, uuid.IsNull ? "null" : uuid.ToString());
if (!uuid.IsNull && !string.IsNullOrWhiteSpace(uuid.ToString()))
{
hardwareInfo.SystemUuid = uuid.ToString().Trim();
_logger.LogInformation("Found UUID from CIM_PhysicalPackage: {Uuid}", hardwareInfo.SystemUuid);
return;
}
}
catch (Exception ex)
{
_logger.LogInformation(ex, "UUID property not available from CIM_PhysicalPackage item");
}
}
}
catch (Exception ex)
{
_logger.LogInformation(ex, "Failed to query CIM_PhysicalPackage for UUID");
}
_logger.LogWarning("Could not find system UUID from any source");
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to query system UUID");
}
}
/// <summary>
/// 将 AMT PlatformGUID 转换为标准 UUID 格式
/// PlatformGUID 是 32 位十六进制字符串,需要转换为 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 格式
///
/// 示例:
/// AMT PlatformGUID: B826D58CD3E2E31187820B47ABD01400
/// Windows UUID: 8CD526B8-E2D3-11E3-8782-0B47ABD01400
///
/// 转换规则前三组需要按字节反转每2个十六进制字符为1字节
/// </summary>
private string FormatPlatformGuidToUuid(string platformGuid)
{
// 移除可能存在的连字符
var cleanGuid = platformGuid.Replace("-", "").ToUpperInvariant();
if (cleanGuid.Length != 32)
{
_logger.LogWarning("Invalid PlatformGUID length: {Length}, expected 32", cleanGuid.Length);
return platformGuid; // 返回原始值
}
// AMT PlatformGUID 格式32字符
// B826D58C D3E2 E311 8782 0B47ABD01400
// 位置: 0-7 8-11 12-15 16-19 20-31
// 标准 UUID 格式:
// 8CD526B8-E2D3-11E3-8782-0B47ABD01400
// 第一组4 字节8字符按字节反转
// B826D58C -> 8C D5 26 B8 -> 8CD526B8
var part1 = cleanGuid.Substring(0, 8);
var part1Reversed = $"{part1[6]}{part1[7]}{part1[4]}{part1[5]}{part1[2]}{part1[3]}{part1[0]}{part1[1]}";
// 第二组2 字节4字符按字节反转
// D3E2 -> E2 D3 -> E2D3
var part2 = cleanGuid.Substring(8, 4);
var part2Reversed = $"{part2[2]}{part2[3]}{part2[0]}{part2[1]}";
// 第三组2 字节4字符按字节反转
// E311 -> 11 E3 -> 11E3
var part3 = cleanGuid.Substring(12, 4);
var part3Reversed = $"{part3[2]}{part3[3]}{part3[0]}{part3[1]}";
// 第四组2 字节4字符不反转
var part4 = cleanGuid.Substring(16, 4);
// 第五组6 字节12字符不反转
var part5 = cleanGuid.Substring(20, 12);
var result = $"{part1Reversed}-{part2Reversed}-{part3Reversed}-{part4}-{part5}";
_logger.LogInformation("UUID conversion: {Raw} -> {Formatted}", cleanGuid, result);
return result;
}
private void QueryProcessorInfo(IWsmanConnection connection, HardwareInfo hardwareInfo)
{
try
{
_logger.LogDebug("Querying processor information");
var query = connection.ExecQuery("SELECT * FROM CIM_Realizes");
foreach (IWsmanItem item in query)
{
if (item.Object.GetProperty("Dependent").IsA("CIM_Processor"))
{
var cpuObj = item.Object.GetProperty("Dependent").Ref.Get();
var chipObj = item.Object.GetProperty("Antecedent").Ref.Get();
// Try to get CPU model from Chip Version (more detailed)
try
{
var version = chipObj.GetProperty("Version");
if (!version.IsNull && !string.IsNullOrWhiteSpace(version.ToString()))
{
hardwareInfo.ProcessorModel = version.ToString().Trim();
}
}
catch
{
// Version not available, fall back to Family
}
// If no version, use processor family
if (string.IsNullOrEmpty(hardwareInfo.ProcessorModel))
{
var family = cpuObj.GetProperty("Family");
if (!family.IsNull)
{
hardwareInfo.ProcessorModel = MapProcessorFamily(family.ToString());
}
}
// Get clock speeds
var maxClockSpeed = cpuObj.GetProperty("MaxClockSpeed");
if (!maxClockSpeed.IsNull)
{
hardwareInfo.ProcessorMaxClockSpeed = int.Parse(maxClockSpeed.ToString());
}
var currentClockSpeed = cpuObj.GetProperty("CurrentClockSpeed");
if (!currentClockSpeed.IsNull)
{
hardwareInfo.ProcessorCurrentClockSpeed = int.Parse(currentClockSpeed.ToString());
}
// Try to get core count (may not be available on all systems)
try
{
var numberOfCores = cpuObj.GetProperty("NumberOfCores");
if (!numberOfCores.IsNull)
{
hardwareInfo.ProcessorCores = int.Parse(numberOfCores.ToString());
}
}
catch
{
// Core count not available
}
// Try to get thread count
try
{
var numberOfLogicalProcessors = cpuObj.GetProperty("NumberOfLogicalProcessors");
if (!numberOfLogicalProcessors.IsNull)
{
hardwareInfo.ProcessorThreads = int.Parse(numberOfLogicalProcessors.ToString());
}
}
catch
{
// Thread count not available
}
break; // Only need first processor
}
}
_logger.LogDebug("Processor info: {Model} @ {Speed}MHz",
hardwareInfo.ProcessorModel, hardwareInfo.ProcessorMaxClockSpeed);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to query processor information");
}
}
private void QueryMemoryInfo(IWsmanConnection connection, HardwareInfo hardwareInfo)
{
try
{
_logger.LogDebug("Querying memory information");
var query = connection.ExecQuery("SELECT * FROM CIM_PhysicalMemory");
long totalMemory = 0;
foreach (IWsmanItem item in query)
{
var module = new MemoryModule();
var tag = item.Object.GetProperty("Tag");
if (!tag.IsNull)
{
module.SlotLocation = tag.ToString();
}
var bankLabel = item.Object.GetProperty("BankLabel");
if (!bankLabel.IsNull && string.IsNullOrEmpty(module.SlotLocation))
{
module.SlotLocation = bankLabel.ToString();
}
var capacity = item.Object.GetProperty("Capacity");
if (!capacity.IsNull)
{
module.CapacityBytes = long.Parse(capacity.ToString());
totalMemory += module.CapacityBytes.Value;
}
// Try ConfiguredMemoryClockSpeed first (this is in MHz, available in newer AMT versions)
try
{
var configuredSpeed = item.Object.GetProperty("ConfiguredMemoryClockSpeed");
_logger.LogDebug("Memory ConfiguredMemoryClockSpeed: IsNull={IsNull}, Value={Value}",
configuredSpeed.IsNull, configuredSpeed.IsNull ? "null" : configuredSpeed.ToString());
if (!configuredSpeed.IsNull)
{
var configuredSpeedValue = int.Parse(configuredSpeed.ToString());
if (configuredSpeedValue > 0)
{
module.SpeedMHz = configuredSpeedValue;
}
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "ConfiguredMemoryClockSpeed not available");
}
// If ConfiguredMemoryClockSpeed not available, try MaxMemorySpeed (also in MHz)
if (module.SpeedMHz == null || module.SpeedMHz == 0)
{
try
{
var maxSpeed = item.Object.GetProperty("MaxMemorySpeed");
_logger.LogDebug("Memory MaxMemorySpeed: IsNull={IsNull}, Value={Value}",
maxSpeed.IsNull, maxSpeed.IsNull ? "null" : maxSpeed.ToString());
if (!maxSpeed.IsNull)
{
var maxSpeedValue = int.Parse(maxSpeed.ToString());
if (maxSpeedValue > 0)
{
module.SpeedMHz = maxSpeedValue;
}
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "MaxMemorySpeed not available");
}
}
// Speed property is in nanoseconds, convert to MHz if other properties not available
// Note: Speed in nanoseconds can be converted to MHz: MHz = 1000 / nanoseconds
if (module.SpeedMHz == null || module.SpeedMHz == 0)
{
var speed = item.Object.GetProperty("Speed");
_logger.LogDebug("Memory Speed (nanoseconds): IsNull={IsNull}, Value={Value}",
speed.IsNull, speed.IsNull ? "null" : speed.ToString());
if (!speed.IsNull)
{
var speedNs = int.Parse(speed.ToString());
if (speedNs > 0)
{
// Convert nanoseconds to MHz: MHz = 1000 / ns
// For example: 0.625 ns = 1600 MHz, but AMT typically returns 0 for this
// If speed is a reasonable nanosecond value (like 1-100), convert it
if (speedNs <= 100)
{
module.SpeedMHz = (int)(1000.0 / speedNs);
}
else
{
// Some older AMT versions might return MHz directly in Speed field
module.SpeedMHz = speedNs;
}
}
}
}
var memoryType = item.Object.GetProperty("MemoryType");
if (!memoryType.IsNull)
{
module.MemoryType = MapMemoryType(memoryType.ToString());
}
// Try to get FormFactor
try
{
var formFactor = item.Object.GetProperty("FormFactor");
if (!formFactor.IsNull)
{
var formFactorStr = MapFormFactor(formFactor.ToString());
_logger.LogDebug("Memory FormFactor: {FormFactor}", formFactorStr);
// We could add FormFactor to MemoryModule model if needed
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "FormFactor not available");
}
var manufacturer = item.Object.GetProperty("Manufacturer");
if (!manufacturer.IsNull)
{
module.Manufacturer = manufacturer.ToString();
}
var partNumber = item.Object.GetProperty("PartNumber");
if (!partNumber.IsNull)
{
module.PartNumber = partNumber.ToString();
}
try
{
var serialNumber = item.Object.GetProperty("SerialNumber");
if (!serialNumber.IsNull)
{
module.SerialNumber = serialNumber.ToString();
}
}
catch
{
// Serial number not available
}
hardwareInfo.MemoryModules.Add(module);
}
hardwareInfo.TotalMemoryBytes = totalMemory;
_logger.LogDebug("Memory info: {Count} modules, {TotalGB}GB total",
hardwareInfo.MemoryModules.Count, totalMemory / 1024 / 1024 / 1024);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to query memory information");
}
}
private void QueryStorageInfo(IWsmanConnection connection, HardwareInfo hardwareInfo)
{
try
{
_logger.LogDebug("Querying storage information");
var query = connection.ExecQuery("SELECT * FROM CIM_MediaAccessDevice");
foreach (IWsmanItem item in query)
{
var device = new StorageDevice();
var deviceId = item.Object.GetProperty("DeviceID");
if (!deviceId.IsNull)
{
device.DeviceId = deviceId.ToString();
}
// Try to get model from CIM_PhysicalPackage via CIM_Realizes association
// This is how the SDK gets the model number
try
{
var realizesQuery = connection.ExecQuery("SELECT * FROM CIM_Realizes");
foreach (IWsmanItem realizesItem in realizesQuery)
{
try
{
var dependent = realizesItem.Object.GetProperty("Dependent");
if (!dependent.IsNull && dependent.IsA("CIM_MediaAccessDevice"))
{
// Check if this is the same device
var depObj = dependent.Ref.Get();
var depDeviceId = depObj.GetProperty("DeviceID");
if (!depDeviceId.IsNull && depDeviceId.ToString() == device.DeviceId)
{
var antecedent = realizesItem.Object.GetProperty("Antecedent");
if (!antecedent.IsNull && antecedent.IsA("CIM_PhysicalPackage"))
{
var packageObj = antecedent.Ref.Get();
var model = packageObj.GetProperty("Model");
if (!model.IsNull && !string.IsNullOrWhiteSpace(model.ToString()))
{
device.Model = model.ToString().Trim();
_logger.LogDebug("Storage Model from CIM_PhysicalPackage: {Model}", device.Model);
}
// Also try to get serial number from package
try
{
var serialNumber = packageObj.GetProperty("SerialNumber");
if (!serialNumber.IsNull && !string.IsNullOrWhiteSpace(serialNumber.ToString()))
{
_logger.LogDebug("Storage SerialNumber from CIM_PhysicalPackage: {SerialNumber}", serialNumber.ToString());
}
}
catch { }
break;
}
}
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Error processing CIM_Realizes item");
}
}
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed to query CIM_Realizes for storage model");
}
// Fallback: try to get model from MediaAccessDevice properties
if (string.IsNullOrEmpty(device.Model))
{
var caption = item.Object.GetProperty("Caption");
if (!caption.IsNull && !string.IsNullOrWhiteSpace(caption.ToString()))
{
device.Model = caption.ToString().Trim();
}
}
// If Caption is empty, try Name
if (string.IsNullOrEmpty(device.Model))
{
try
{
var name = item.Object.GetProperty("Name");
if (!name.IsNull && !string.IsNullOrWhiteSpace(name.ToString()))
{
device.Model = name.ToString().Trim();
}
}
catch { }
}
// If still empty, try Description
if (string.IsNullOrEmpty(device.Model))
{
try
{
var description = item.Object.GetProperty("Description");
if (!description.IsNull && !string.IsNullOrWhiteSpace(description.ToString()))
{
device.Model = description.ToString().Trim();
}
}
catch { }
}
// Try different capacity properties
try
{
var maxMediaSize = item.Object.GetProperty("MaxMediaSize");
if (!maxMediaSize.IsNull)
{
device.CapacityBytes = long.Parse(maxMediaSize.ToString()) * 1024; // Convert KB to bytes
}
}
catch
{
try
{
var capacity = item.Object.GetProperty("Capacity");
if (!capacity.IsNull)
{
device.CapacityBytes = long.Parse(capacity.ToString());
}
}
catch
{
// Capacity not available
}
}
// Try to get interface type
try
{
var interfaceType = item.Object.GetProperty("InterfaceType");
if (!interfaceType.IsNull)
{
device.InterfaceType = interfaceType.ToString();
}
}
catch
{
// Interface type not available
}
hardwareInfo.StorageDevices.Add(device);
}
_logger.LogDebug("Storage info: {Count} devices", hardwareInfo.StorageDevices.Count);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to query storage information");
}
}
private string MapProcessorFamily(string familyCode)
{
// Map processor family codes to readable names
// Based on DMTF SMBIOS Reference Specification
return familyCode switch
{
"2" => "Unknown",
"3" => "8086",
"4" => "80286",
"5" => "80386",
"6" => "80486",
"11" => "Pentium",
"12" => "Pentium Pro",
"13" => "Pentium II",
"15" => "Celeron",
"16" => "Pentium II Xeon",
"17" => "Pentium III",
"179" => "Intel Core i3",
"180" => "Intel Core i5",
"181" => "Intel Core i7",
"183" => "Intel Core i9",
"198" => "Intel Core", // Generic Intel Core processor
"205" => "Intel Core i9 (12th Gen)",
"206" => "Intel Core i7 (12th Gen)",
"207" => "Intel Core i5 (12th Gen)",
"208" => "Intel Core i3 (12th Gen)",
_ => $"Processor Family {familyCode}"
};
}
private string MapMemoryType(string typeCode)
{
// Map memory type codes to readable names
// Based on DMTF SMBIOS Reference Specification
return typeCode switch
{
"0" => "Unknown",
"1" => "Other",
"2" => "DRAM",
"3" => "Synchronous DRAM",
"4" => "Cache DRAM",
"5" => "EDO",
"6" => "EDRAM",
"7" => "VRAM",
"8" => "SRAM",
"9" => "RAM",
"10" => "ROM",
"11" => "Flash",
"12" => "EEPROM",
"13" => "FEPROM",
"14" => "EPROM",
"15" => "CDRAM",
"16" => "3DRAM",
"17" => "SDRAM",
"18" => "SGRAM",
"19" => "RDRAM",
"20" => "DDR",
"21" => "DDR2",
"22" => "DDR2 FB-DIMM",
"24" => "DDR3",
"25" => "FBD2",
"26" => "DDR4",
"27" => "LPDDR",
"28" => "LPDDR2",
"29" => "LPDDR3",
"30" => "LPDDR4",
"31" => "Logical non-volatile device",
"32" => "HBM (High Bandwidth Memory)",
"33" => "HBM2 (High Bandwidth Memory Generation 2)",
"34" => "DDR5",
"35" => "LPDDR5",
_ => $"Type {typeCode}"
};
}
private string MapFormFactor(string formFactorCode)
{
// Map form factor codes to readable names
// Based on DMTF SMBIOS Reference Specification
return formFactorCode switch
{
"0" => "Unknown",
"1" => "Other",
"2" => "Unknown",
"3" => "SIMM",
"4" => "SIP",
"5" => "Chip",
"6" => "DIP",
"7" => "ZIP",
"8" => "Proprietary Card",
"9" => "DIMM",
"10" => "TSOP",
"11" => "Row of chips",
"12" => "RIMM",
"13" => "SODIMM",
"14" => "SRIMM",
"15" => "FB-DIMM",
_ => $"FormFactor {formFactorCode}"
};
}
}