Maintaining accurate hardware records across mixed OS environments is painful when dealing with physical stickers. Here's how to extract critical identifiers programmatically:
For Windows systems (XP through Server 2008), WMI provides the most comprehensive access:
wmic bios get manufacturer,serialnumber
wmic csproduct get name,vendor,identifyingnumber
wmic baseboard get product,manufacturer,serialnumber
For structured output in PowerShell:
Get-WmiObject Win32_ComputerSystemProduct | Select-Object Vendor,Name,IdentifyingNumber
Get-WmiObject Win32_BIOS | Select-Object Manufacturer,SerialNumber
Most Linux distributions include dmidecode (run as root):
sudo dmidecode -t system | grep -E 'Manufacturer|Product Name|Serial Number'
sudo dmidecode -t baseboard | grep -E 'Manufacturer|Product Name|Serial Number'
For headless environments where dmidecode isn't available:
cat /sys/class/dmi/id/{sys_vendor,product_name,product_serial}
For environments mixing both OS families, this Python script handles both:
import platform
import subprocess
def get_hardware_info():
system = platform.system()
if system == "Windows":
try:
manufacturer = subprocess.check_output(
"wmic csproduct get vendor", shell=True
).decode().split('\n')[1].strip()
model = subprocess.check_output(
"wmic csproduct get name", shell=True
).decode().split('\n')[1].strip()
serial = subprocess.check_output(
"wmic bios get serialnumber", shell=True
).decode().split('\n')[1].strip()
return (manufacturer, model, serial)
except Exception as e:
print(f"Windows WMI query failed: {str(e)}")
return (None, None, None)
elif system == "Linux":
try:
vendor = subprocess.check_output(
"cat /sys/class/dmi/id/sys_vendor", shell=True
).decode().strip()
product = subprocess.check_output(
"cat /sys/class/dmi/id/product_name", shell=True
).decode().strip()
serial = subprocess.check_output(
"cat /sys/class/dmi/id/product_serial", shell=True
).decode().strip()
return (vendor, product, serial)
except Exception as e:
print(f"Linux DMI query failed: {str(e)}")
return (None, None, None)
else:
return (None, None, None)
For mass inventory collection:
- Package scripts as standalone executables using PyInstaller (Python) or compile to EXE (Windows batch)
- Schedule execution via Group Policy (Windows) or Ansible (Linux)
- Output to centralized SQL database using system-specific connectors
Common pitfalls to address:
# Virtual machines often return generic identifiers
# Check for hypervisor signatures:
wmic baseboard get product # Returns "Virtual Machine" for Hyper-V
dmidecode -s system-manufacturer # Returns "QEMU" for KVM
For systems where standard methods fail, consider:
# Windows fallback to registry
reg query "HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS"
# Linux alternative for ARM devices
cat /proc/device-tree/model
For enterprise inventory without third-party tools, we can leverage built-in OS capabilities. Windows provides WMI while Linux uses DMI through dmidecode
. Here's how to implement a unified collection method:
# For Windows systems (works from XP onward):
$computerInfo = Get-WmiObject -Class Win32_ComputerSystemProduct |
Select-Object Vendor, Version, IdentifyingNumber
Write-Output "Manufacturer: $($computerInfo.Vendor)"
Write-Output "Model: $($computerInfo.Version)"
Write-Output "Serial: $($computerInfo.IdentifyingNumber)"
# Alternative using WMIC (works on legacy systems):
wmic csproduct get vendor, name, identifyingnumber /format:csv
#!/bin/bash
# For Debian/Ubuntu/Fedora systems:
MANUFACTURER=$(sudo dmidecode -s system-manufacturer)
MODEL=$(sudo dmidecode -s system-product-name)
SERIAL=$(sudo dmidecode -s system-serial-number)
echo "Manufacturer: $MANUFACTURER"
echo "Model: $MODEL"
echo "Serial: $SERIAL"
# For systems without dmidecode:
cat /sys/class/dmi/id/{sys_vendor,product_name,product_serial} 2>/dev/null
import platform
import subprocess
def get_hardware_info():
system = platform.system()
if system == "Windows":
cmd = 'wmic csproduct get vendor, name, identifyingnumber /format:csv'
output = subprocess.check_output(cmd, shell=True).decode()
_, vendor, name, serial = output.strip().split(',')
else:
try:
vendor = subprocess.check_output(
'sudo dmidecode -s system-manufacturer',
shell=True).decode().strip()
name = subprocess.check_output(
'sudo dmidecode -s system-product-name',
shell=True).decode().strip()
serial = subprocess.check_output(
'sudo dmidecode -s system-serial-number',
shell=True).decode().strip()
except:
with open('/sys/class/dmi/id/sys_vendor') as f:
vendor = f.read().strip()
with open('/sys/class/dmi/id/product_name') as f:
name = f.read().strip()
with open('/sys/class/dmi/id/product_serial') as f:
serial = f.read().strip()
return {
'manufacturer': vendor,
'model': name,
'serial': serial
}
For database integration, modify the output format accordingly:
# MySQL INSERT format
print(f"INSERT INTO inventory VALUES ('{vendor}', '{name}', '{serial}');")
# JSON output
import json
print(json.dumps(get_hardware_info(), indent=2))
For mass deployment across networks:
- Use SSH (Linux) or WinRM (Windows) for remote execution
- Schedule through cron (Linux) or Task Scheduler (Windows)
- Output to centralized log file or database