Skip to content

Instantly share code, notes, and snippets.

@mckabue
Created August 11, 2026 08:27
Show Gist options
  • Select an option

  • Save mckabue/e8c05a13bdadfdf654bb279fb9b37d55 to your computer and use it in GitHub Desktop.

Select an option

Save mckabue/e8c05a13bdadfdf654bb279fb9b37d55 to your computer and use it in GitHub Desktop.
Profile & verify a used laptop's real specs (RAM, SSD, CPU/threads, battery, TPM)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
hardware_profile.py — Verify a (second-hand) laptop's real hardware.
Cross-platform: Windows (PowerShell/WMIC), Linux and macOS.
Zero dependencies (stdlib only).
Why: used laptops are often sold as "16GB / 256GB SSD / i7" but actually
arrive with 8GB, an HDD, or a different CPU. This script builds a detailed
profile (CPU + cores/threads, RAM modules/type/speed, disk type & health,
GPU, battery health, TPM / Windows 11 readiness) and can cross-check it
against the specs you were promised.
Usage:
python3 hardware_profile.py # print profile
python3 hardware_profile.py --json # also write hardware_profile.json
python3 hardware_profile.py \
--expect-ram 16 --expect-ssd 256 \
--expect-cpu "4600U" --expect-threads 12 # PASS/FAIL against the ad
python3 hardware_profile.py --expect-all 16,256,"4600U",12
Exit code: 0 = ok, 2 = a --expect check failed, 3 = something could not be read.
"""
import argparse
import json
import os
import platform
import re
import subprocess
import sys
from datetime import datetime
# --------------------------------------------------------------------------- #
# Helpers
# --------------------------------------------------------------------------- #
def run(cmd, timeout=40, binary=False):
"""Run a shell command, return stdout (or b'' when binary=True)."""
try:
p = subprocess.run(
cmd, shell=True, capture_output=True, text=not binary, timeout=timeout
)
return p.stdout if not binary else p.stdout.encode() if p.stdout else b""
except Exception:
return "" if not binary else b""
def gb_bytes(value):
"""Best-effort bytes -> GiB, returns None if unknown."""
try:
return int(value) / (1024 ** 3)
except (TypeError, ValueError):
return None
def fmt_gb(bytes_n):
g = gb_bytes(bytes_n)
return f"{g:.0f} GB" if g is not None else "unknown"
def pretty_json(obj):
return json.dumps(obj, indent=2, default=str)
# --------------------------------------------------------------------------- #
# Per-OS collectors
# --------------------------------------------------------------------------- #
def cpu_info(os_name):
info = {"model": None, "cores": None, "threads": None, "max_mhz": None, "virtualized": None}
if os_name == "Windows":
out = run('wmic cpu get Name,NumberOfCores,NumberOfLogicalProcessors,MaxClockSpeed /value')
m = re.search(r"Name=(.+)", out)
if m:
info["model"] = m.group(1).strip()
m = re.search(r"NumberOfCores=(\d+)", out)
if m:
info["cores"] = int(m.group(1))
m = re.search(r"NumberOfLogicalProcessors=(\d+)", out)
if m:
info["threads"] = int(m.group(1))
m = re.search(r"MaxClockSpeed=(\d+)", out)
if m:
info["max_mhz"] = int(m.group(1))
elif os_name == "Linux":
out = run("lscpu")
m = re.search(r"Model name:\s*(.+)", out)
if m:
info["model"] = m.group(1).strip()
m = re.search(r"^CPU\(s\):\s*(\d+)", out, re.M)
if m:
info["threads"] = int(m.group(1))
m = re.search(r"^Core\(s\) per socket:\s*(\d+)", out, re.M)
if m:
info["cores"] = int(m.group(1))
m = re.search(r"^CPU max MHz:\s*([\d.]+)", out, re.M)
if m:
info["max_mhz"] = float(m.group(1))
info["virtualized"] = "Hypervisor vendor" in out
if info["model"] is None: # fallback
m = re.search(r'"model name"\s*:\s*(.+)', run("grep -m1 'model name' /proc/cpuinfo"))
if m:
info["model"] = m.group(1).strip()
elif os_name == "Darwin":
out = run("sysctl -n machdep.cpu.brand_string machdep.cpu.core_count machdep.cpu.thread_count")
lines = out.splitlines()
info["model"] = lines[0].strip() if lines else None
info["cores"] = int(lines[1]) if len(lines) > 1 and lines[1].strip().isdigit() else None
info["threads"] = int(lines[2]) if len(lines) > 2 and lines[2].strip().isdigit() else None
return info
def ram_info(os_name):
"""Returns (total_gb, modules[])."""
modules = []
total = None
if os_name == "Windows":
out = run('wmic computersystem get TotalPhysicalMemory /value')
m = re.search(r"TotalPhysicalMemory=(\d+)", out)
if m:
total = gb_bytes(m.group(1))
out = run('wmic memorychip get Capacity,Speed,MemoryType,Manufacturer,PartNumber /value')
blocks = re.split(r"\n\s*\n", out.strip())
for b in blocks:
cap = re.search(r"Capacity=(\d+)", b)
spd = re.search(r"Speed=(\d+)", b)
typ = re.search(r"MemoryType=(\d+)", b)
man = re.search(r"Manufacturer=(.*)", b)
pn = re.search(r"PartNumber=(.*)", b)
if cap:
mem_type = {20: "DDR", 21: "DDR2", 24: "DDR3", 26: "DDR4", 0: "Unknown"}.get(
int(typ.group(1)) if typ else 0, "Unknown")
modules.append({
"capacity_gb": gb_bytes(cap.group(1)),
"speed_mhz": int(spd.group(1)) if spd else None,
"type": mem_type,
"manufacturer": (man.group(1).strip() if man else None),
"part": (pn.group(1).strip() if pn else None),
})
elif os_name == "Linux":
out = run("free -b | awk 'NR==2{print $2}'")
if out.strip().isdigit():
total = gb_bytes(out.strip())
# module detail needs dmidecode (root); fallback silently if unavailable
out = run("sudo -n dmidecode -t memory 2>/dev/null || dmidecode -t memory 2>/dev/null || true")
if out:
for b in re.split(r"Memory Device$", out, flags=re.M):
if "Size:" not in b or "No Module Installed" in b:
continue
sz = re.search(r"Size:\s*(\d+)\s*MB", b)
spd = re.search(r"Speed:\s*(\d+)\s*MT/s", b)
typ = re.search(r"Type:\s*(\S+)", b)
man = re.search(r"Manufacturer:\s*(\S+)", b)
pn = re.search(r"Part Number:\s*(\S+)", b)
if sz:
modules.append({
"capacity_gb": int(sz.group(1)) / 1024,
"speed_mhz": int(spd.group(1)) if spd else None,
"type": typ.group(1) if typ else None,
"manufacturer": man.group(1) if man else None,
"part": pn.group(1) if pn else None,
})
if not modules and total: # fallback: single aggregate entry
modules.append({"capacity_gb": total, "speed_mhz": None,
"type": "unknown (run with sudo for detail)", "manufacturer": None, "part": None})
elif os_name == "Darwin":
out = run("sysctl -n hw.memsize")
if out.strip().isdigit():
total = gb_bytes(out.strip())
out = run("system_profiler SPMemoryDataType 2>/dev/null")
for b in re.split(r"BANK\s*\d+/", out):
cap = re.search(r"Size:\s*(\d+)\s*GB", b)
spd = re.search(r"Speed:\s*(\d+)\s*MHz", b)
typ = re.search(r"Type:\s*(\S+)", b)
if cap:
modules.append({"capacity_gb": int(cap.group(1)),
"speed_mhz": int(spd.group(1)) if spd else None,
"type": typ.group(1) if typ else None,
"manufacturer": None, "part": None})
if not modules and total:
modules.append({"capacity_gb": total, "speed_mhz": None,
"type": "unknown", "manufacturer": None, "part": None})
return total, modules
def disk_info(os_name):
"""List of disks: model, size_gb, type(SSD/HDD/NVMe), health lines, wear%."""
disks = []
if os_name == "Windows":
# PowerShell gives reliable MediaType (SSD vs HDD)
out = run(
"powershell -NoProfile -Command "
"\"Get-PhysicalDisk | Select-Object FriendlyName,MediaType,BusType,Size | ConvertTo-Csv -NoTypeInformation\""
)
for row in out.strip().splitlines()[1:]:
if not row.strip():
continue
parts = [p.strip().strip('"') for p in row.split(",")]
if len(parts) >= 4:
media = parts[1]
bus = parts[2]
kind = "NVMe" if "NVMe" in bus else ("SSD" if media == "SSD" else ("HDD" if media == "HDD" else media or "unknown"))
disks.append({"model": parts[0], "size_gb": gb_bytes(parts[3]) if parts[3].isdigit() else None,
"type": kind})
elif os_name == "Linux":
out = run("lsblk -d -o NAME,MODEL,SIZE,ROTA,TRAN,TYPE 2>/dev/null")
for line in out.splitlines()[1:]:
parts = line.split()
if len(parts) >= 5 and parts[-1] in ("disk",):
name = parts[0]
model = parts[1] if parts[1] not in ("disk",) and not parts[1].startswith("/dev") else name
size_raw = parts[2]
rota = parts[3]
tran = parts[4] if len(parts) > 4 else ""
size_gb = None
m = re.match(r"([\d.]+)([GT])", size_raw)
if m:
v = float(m.group(1))
size_gb = v * 1024 if m.group(2) == "T" else v
kind = "NVMe" if "nvme" in tran else ("HDD" if rota == "1" else "SSD")
health = run(f"sudo -n smartctl -H -A /dev/{name} 2>/dev/null | tail -n +1 | grep -E 'SMART overall|Percentage Used|Temperature_Celsius|Reallocated_Sector|Power_On_Hours' || true")
disks.append({"model": model, "size_gb": size_gb, "type": kind, "health": health.strip()})
elif os_name == "Darwin":
out = run("system_profiler SPStorageDataType 2>/dev/null")
for block in re.split(r"\n\s*\n", out):
if "Medium Type:" not in block:
continue # skips virtual Disk Images
dev = re.search(r"Device Name:\s*(.+)", block)
med = re.search(r"Medium Type:\s*(.+)", block)
cap = re.search(r"Capacity:\s*([\d.]+)\s*(\w+)", block)
size_gb = None
if cap:
size_gb = float(cap.group(1)) * 1024 if cap.group(2) == "TB" else float(cap.group(1))
kind = med.group(1).strip() if med else "unknown"
disks.append({"model": dev.group(1).strip() if dev else "",
"size_gb": size_gb, "type": kind, "health": ""})
# De-duplicate: macOS lists the same physical disk once per volume.
seen, deduped = set(), []
for d in disks:
key = d.get("model") or id(d)
if key not in seen:
seen.add(key)
deduped.append(d)
return deduped
def gpu_info(os_name):
if os_name == "Windows":
out = run('wmic path win32_VideoController get Name,AdapterRAM /value')
gpus = re.findall(r"Name=(.+?)(?:\n|$)", out)
return [g.strip() for g in gpus if g.strip()] or ["(none detected)"]
if os_name == "Linux":
out = run("lspci | grep -Ei 'vga|3d|display' || true")
return [l.split(":", 2)[-1].strip() for l in out.splitlines() if l.strip()] or ["(none detected)"]
if os_name == "Darwin":
out = run("system_profiler SPDisplaysDataType 2>/dev/null | grep -E 'Chipset Model|Vendor'")
return [l.strip() for l in out.splitlines() if l.strip()] or ["(none detected)"]
return []
def battery_info(os_name):
info = {"percent": None, "health_pct": None}
if os_name == "Windows":
out = run("powershell -NoProfile -Command \"(Get-CimInstance Win32_Battery | Select-Object EstimatedChargeRemaining,DesignCapacity,FullChargeCapacity | ConvertTo-Csv -NoTypeInformation)\"")
rows = out.strip().splitlines()
if len(rows) > 1:
parts = [p.strip().strip('"') for p in rows[1].split(",")]
try:
info["percent"] = int(parts[0])
except (ValueError, IndexError):
pass
try:
if parts[2] and float(parts[2]) > 0:
info["health_pct"] = round(float(parts[2]) / float(parts[1]) * 100, 1)
except (ValueError, ZeroDivisionError, IndexError):
pass
elif os_name == "Linux":
out = run("cat /sys/class/power_supply/BAT0/capacity 2>/dev/null || cat /sys/class/power_supply/BAT1/capacity 2>/dev/null || true")
if out.strip().isdigit():
info["percent"] = int(out.strip())
de = run("grep -E 'ENERGY_FULL_DESIGN|ENERGY_FULL' /sys/class/power_supply/BAT0/uevent 2>/dev/null || true")
m_full = re.search(r"ENERGY_FULL=(\d+)", de)
m_design = re.search(r"ENERGY_FULL_DESIGN=(\d+)", de)
if m_full and m_design and float(m_design.group(1)) > 0:
info["health_pct"] = round(float(m_full.group(1)) / float(m_design.group(1)) * 100, 1)
elif os_name == "Darwin":
out = run("ioreg -rn AppleSmartBattery 2>/dev/null | grep -E '\"(CurrentCapacity|MaxCapacity|DesignCapacity)\" ='")
cap = dict(re.findall(r'"(\w+)"\s*=\s*(\d+)', out))
if cap.get("MaxCapacity") and cap.get("CurrentCapacity"):
info["percent"] = round(float(cap["CurrentCapacity"]) / float(cap["MaxCapacity"]) * 100)
if cap.get("MaxCapacity") and cap.get("DesignCapacity"):
info["health_pct"] = round(float(cap["MaxCapacity"]) / float(cap["DesignCapacity"]) * 100, 1)
return info
def system_info(os_name):
sys_info = {}
if os_name == "Windows":
out = run('wmic computersystem get Manufacturer,Model /value')
m = re.search(r"Manufacturer=(.+)", out)
if m:
sys_info["manufacturer"] = m.group(1).strip()
m = re.search(r"Model=(.+)", out)
if m:
sys_info["model"] = m.group(1).strip()
out = run('wmic bios get SerialNumber,SMBIOSBIOSVersion /value')
m = re.search(r"SerialNumber=(.+)", out)
if m:
sys_info["serial"] = m.group(1).strip()
m = re.search(r"SMBIOSBIOSVersion=(.+)", out)
if m:
sys_info["bios"] = m.group(1).strip()
elif os_name == "Linux":
for key, path in [("manufacturer", "/sys/class/dmi/id/sys_vendor"),
("model", "/sys/class/dmi/id/product_name"),
("serial", "/sys/class/dmi/id/product_serial")]:
try:
with open(path) as f:
sys_info[key] = f.read().strip()
except OSError:
pass
sys_info["os"] = run("grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d '\"'").strip() or platform.platform()
elif os_name == "Darwin":
out = run("system_profiler SPHardwareDataType 2>/dev/null | grep -E 'Model Name|Model Identifier|Serial Number|Chip|Memory'")
for line in out.splitlines():
if ":" in line:
k, v = [x.strip() for x in line.split(":", 1)]
sys_info[k.lower().replace(" ", "_")] = v
return sys_info
def tpm_windows11(os_name):
"""Windows 11 readiness signals: TPM present + generation."""
if os_name == "Windows":
out = run("powershell -NoProfile -Command \"Get-Tpm | Select-Object TpmPresent,TpmReady | ConvertTo-Csv -NoTypeInformation\" 2>/dev/null || wmic /namespace:\\\\root\\cimv2\\security\\microsofttpm path Win32_Tpm get IsEnabled_InitialValue /value 2>/dev/null || echo unavailable")
return out.strip() or "unavailable"
if os_name == "Linux":
if os.path.isdir("/sys/class/tpm/tpm0"):
out = run("cat /sys/class/tpm/tpm0/device/description 2>/dev/null || echo TPM present")
return out.strip()
return "no TPM device found in /sys/class/tpm"
return "not-applicable (macOS)"
# --------------------------------------------------------------------------- #
# Report + verification
# --------------------------------------------------------------------------- #
def build_profile():
os_name = platform.system()
os_release = platform.release()
cpu = cpu_info(os_name)
ram_total, ram_modules = ram_info(os_name)
disks = disk_info(os_name)
gpus = gpu_info(os_name)
battery = battery_info(os_name)
sysinfo = system_info(os_name)
profile = {
"generated_at": datetime.now().isoformat(timespec="seconds"),
"os": f"{os_name} {os_release}",
"hostname": platform.node(),
"system": sysinfo,
"cpu": cpu,
"ram": {
"total_gb": round(ram_total, 1) if ram_total else None,
"module_count": len(ram_modules),
"modules": ram_modules,
},
"disks": disks,
"gpu": gpus,
"battery": battery,
"tpm": tpm_windows11(os_name),
}
return profile
def render(profile):
s = profile["system"]
c = profile["cpu"]
r = profile["ram"]
disks = profile["disks"]
gpus = profile["gpu"]
battery = profile["battery"]
lines = []
w = 78
lines.append("=" * w)
lines.append(" LAPTOP HARDWARE PROFILE")
lines.append(" " + profile["generated_at"])
lines.append("=" * w)
lines.append(f" Host OS : {profile['os']} (host: {profile['hostname']})")
if s:
for k, v in s.items():
if v:
lines.append(f" {k.replace('_', ' ').title():<15}: {v}")
lines.append("-" * w)
lines.append(" CPU")
if c.get("model"):
lines.append(f" Model : {c['model']}")
lines.append(f" Cores / Threads: {c.get('cores', '?')} / {c.get('threads', '?')}")
if c.get("max_mhz"):
lines.append(f" Max clock : {c['max_mhz']} MHz")
if c.get("virtualized"):
lines.append(" WARNING: This machine looks VIRTUALIZED (a VM, not real hardware)!")
lines.append("-" * w)
lines.append(" RAM")
lines.append(f" Total : {r['total_gb']} GB ({r['module_count']} module(s))")
for i, mod in enumerate(r["modules"], 1):
lines.append(
f" Module {i} : {mod['capacity_gb']} GB {mod['type']} @ {mod['speed_mhz']} MHz"
f"{' (' + mod['manufacturer'] + ')' if mod.get('manufacturer') else ''}"
)
lines.append("-" * w)
lines.append(" STORAGE")
for d in profile["disks"]:
lines.append(f" {d['type']:<5} {d.get('model', '')} {round(d['size_gb']) if d.get('size_gb') else '?':>6} GB")
if d.get("health"):
lines.append(" SMART: " + d["health"].replace("\n", " | "))
lines.append("-" * w)
lines.append(" GRAPHICS")
for g in profile["gpu"]:
lines.append(f" {g}")
lines.append("-" * w)
lines.append(" BATTERY")
lines.append(f" Current charge : {battery.get('percent', '?')} %")
lines.append(f" Health (wear) : {battery.get('health_pct', '?')} % of design capacity")
if battery.get("health_pct") is not None and battery["health_pct"] < 60:
lines.append(" WARNING: Battery health < 60% — expect poor battery life.")
lines.append("-" * w)
lines.append(" WINDOWS 11 / TPM")
lines.append(f" {profile['tpm']}")
lines.append("=" * w)
return "\n".join(lines)
def verify(profile, expect):
"""expect: dict with ram_gb, ssd_gb, cpu_sub, threads."""
failures = []
warns = []
passes = []
ram = profile["ram"]["total_gb"]
if expect.get("ram_gb"):
if ram is None:
warns.append(f"RAM: could not read total RAM, cannot verify against {expect['ram_gb']} GB")
elif ram >= expect["ram_gb"] - 0.5:
passes.append(f"RAM: {ram} GB >= expected {expect['ram_gb']} GB")
else:
failures.append(f"RAM: found {ram} GB, expected ~{expect['ram_gb']} GB")
if expect.get("ssd_gb"):
total_ssd = sum(d["size_gb"] or 0 for d in profile["disks"] if d.get("type") in ("SSD", "NVMe"))
has_ssd = any(d.get("type") in ("SSD", "NVMe") for d in profile["disks"])
if not has_ssd:
failures.append("STORAGE: no SSD/NVMe found (likely an HDD — bad for CapCut)")
elif total_ssd >= expect["ssd_gb"] - 30:
passes.append(f"SSD: {total_ssd:.0f} GB SSD/NVMe >= expected {expect['ssd_gb']} GB")
else:
failures.append(f"SSD: only {total_ssd:.0f} GB SSD found, expected ~{expect['ssd_gb']} GB")
if expect.get("cpu_sub"):
model = (profile["cpu"].get("model") or "").lower()
if expect["cpu_sub"].lower() in model:
passes.append(f"CPU: '{expect['cpu_sub']}' present in '{profile['cpu'].get('model')}'")
else:
failures.append(f"CPU: expected substring '{expect['cpu_sub']}' NOT in '{profile['cpu'].get('model')}'")
if expect.get("threads"):
t = profile["cpu"].get("threads")
if t is None:
warns.append("THREADS: could not read thread count")
elif t == expect["threads"]:
passes.append(f"THREADS: {t} == expected {expect['threads']}")
else:
failures.append(f"THREADS: found {t}, expected {expect['threads']}")
return passes, warns, failures
def main():
ap = argparse.ArgumentParser(description="Profile & verify laptop hardware.")
ap.add_argument("--json", action="store_true", help="write hardware_profile.json")
ap.add_argument("--expect-ram", type=float, help="expected RAM in GB (e.g. 16)")
ap.add_argument("--expect-ssd", type=float, help="expected SSD size in GB (e.g. 256)")
ap.add_argument("--expect-cpu", help="expected CPU substring (e.g. 4600U or i7)")
ap.add_argument("--expect-threads", type=int, help="expected logical processors (e.g. 12)")
ap.add_argument("--expect-all", help="comma list: RAM,SSD,cpu,threads (e.g. 16,256,4600U,12)")
args = ap.parse_args()
profile = build_profile()
if args.expect_all:
parts = [p.strip() for p in args.expect_all.split(",")]
try:
args.expect_ram = float(parts[0])
except (ValueError, IndexError):
pass
try:
args.expect_ssd = float(parts[1])
except (ValueError, IndexError):
pass
if len(parts) > 2:
args.expect_cpu = parts[2]
try:
args.expect_threads = int(parts[3])
except (ValueError, IndexError):
pass
expect = {
"ram_gb": args.expect_ram,
"ssd_gb": args.expect_ssd,
"cpu_sub": args.expect_cpu,
"threads": args.expect_threads,
}
print(render(profile))
if args.json:
with open("hardware_profile.json", "w") as f:
f.write(pretty_json(profile))
print("\nProfile written to hardware_profile.json")
exit_code = 0
if any(expect.values()):
passes, warns, failures = verify(profile, expect)
print("=" * 78)
print(" VERIFICATION vs. the advertised specs")
print("=" * 78)
for p in passes:
print(f" [PASS] {p}")
for w in warns:
print(f" [WARN] {w}")
for f in failures:
print(f" [FAIL] {f}")
if failures:
print("\n >>> MACHINE DOES NOT MATCH THE AD. Negotiate or walk away.")
exit_code = 2
elif warns:
print("\n >>> Matches claimed specs, but some details unverified.")
else:
print("\n >>> All claimed specs verified. Happy CapCut editing!")
return exit_code
if __name__ == "__main__":
sys.exit(main())
@mckabue

mckabue commented Aug 11, 2026

Copy link
Copy Markdown
Author

Cross-platform (Windows / Linux / macOS) hardware profiler that verifies a
(second-hand) laptop against the specs you were promised.

Used laptops are often advertised as "16GB RAM / 256GB SSD / i7" but arrive
with 8GB, an HDD, or a different CPU. This zero-dependency Python script
(auto-detects the OS) builds a detailed hardware profile and can PASS/FAIL
each claimed spec so you can negotiate or walk away.

Collected:
• CPU: exact model, cores / threads, max clock (flags VMs)
• RAM: total GB + module-by-module (capacity, DDR3/4 type, MHz, brand)
• Storage: SSD vs HDD vs NVMe detection, size, SMART health/wear (if smartctl)
• Graphics: integrated + discrete GPU (for CapCut hardware encoding)
• Battery: charge % + health % vs design capacity
• TPM / Windows 11 readiness
• System: manufacturer, model, serial number, BIOS

Usage:
python3 laptop-hardware-verify.py # print profile
python3 laptop-hardware-verify.py --json # + hardware_profile.json
python3 laptop-hardware-verify.py --expect-all 16,256,4600U,12 # verify vs ad
python3 laptop-hardware-verify.py --expect-ram 16 --expect-ssd 256
--expect-cpu 4600U --expect-threads 12

Exit codes: 0 = matches ad, 2 = mismatch, 3 = unreadable. No external
dependencies — copy it to a USB stick and run it on the machine at pickup.

@mckabue

mckabue commented Aug 11, 2026

Copy link
Copy Markdown
Author
# Just see the profile (no expectations)
curl -sL https://gist.githubusercontent.com/mckabue/e8c05a13bdadfdf654bb279fb9b37d55/raw/laptop-hardware-verify.py | python3 -

# Save the JSON report too (writes hardware_profile.json in cwd)
curl -sL https://gist.githubusercontent.com/mckabue/e8c05a13bdadfdf654bb279fb9b37d55/raw/laptop-hardware-verify.py | python3 - --json

# One check at a time
curl -sL <url> | python3 - --expect-ram 16 --expect-ssd 256 --expect-cpu 4600U --expect-threads 12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment