简介:这是一款面向企业IT运维人员与设备管理者的电脑硬件信息采集与资产管理工具,基于C#开发,可一键获取CPU、内存、硬盘、显卡、主板等关键硬件的型号与规格参数,并支持资产分类存储、增删改查及使用状态记录,帮助解决企业硬件信息手工登记繁琐、资产台账更新滞后的问题。资源包共32个文件,约115KB,以18个cs源码文件为核心,配合5个resx界面资源、sln解决方案与csproj工程文件,另含README说明、LICENSE授权、ico图标及html页面等,结构完整,便于直接编译运行或二次开发。目前已有327人学习下载。通过该源码,读者可了解C#桌面端硬件信息采集的实现思路、.NET工程组织方式以及资产数据管理模块的代码结构,适合作为企业IT工具开发的学习参考或功能扩展基础。
1. 企业IT资产盘点:从一台电脑的硬件信息采集说起
公司新采购了五十台笔记本,IT部门需要在一周内完成资产录入。如果一台台开机、手动抄写CPU型号、内存容量、硬盘序列号,两个人干三天也未必能对齐数据。更麻烦的是,半年后要做资产核查,发现台账上写的“8GB内存”和实际机器里的“8GB(4+4)”对不上,保修申请被驳回。这类场景在企业IT运维里反复出现,核心痛点只有一个:硬件信息采集没有标准化、自动化。
所谓一键收集电脑硬件信息,本质是写一个脚本或小工具,在目标机器上运行后,自动读取主板、CPU、内存、硬盘、网卡、显卡等部件的型号、序列号、容量、使用状态,并输出成结构化数据(CSV、JSON或直接入库)。它解决的是企业电脑设备资产从“人工抄写”到“自动上报”的问题,适合IT运维、资产管理、设备巡检岗位的从业者。你不需要买昂贵的资产管理系统,用系统自带的命令行工具加一段脚本,就能跑通最小闭环。
2. 硬件信息到底从哪里读:WMI、SMBIOS与系统命令的选型对比
2.1 为什么优先选WMI而不是直接读注册表
Windows系统里获取硬件信息的途径很多,注册表、设备管理器、系统API、WMI(Windows Management Instrumentation)都能拿到部分数据。但注册表里的硬件信息分散且不完整,比如内存条的具体型号和序列号在注册表里往往缺失;设备管理器只适合人眼看,不适合程序批量提取。WMI是微软官方提供的管理接口,它把硬件抽象成类,每个类对应一类设备,查询语法统一,返回字段稳定。
常见做法是用Win32_Processor拿CPU,Win32_PhysicalMemory拿内存条,Win32_DiskDrive拿物理硬盘,Win32_BIOS拿主板和BIOS序列号。这些类在Windows 7到Windows 11上都存在,兼容性好。我一般会先用WMI跑一遍,如果某个字段为空,再考虑用wmic命令或PowerShell的Get-CimInstance兜底。
2.2 用PowerShell跑通第一台机器的采集
下面这段脚本在PowerShell里直接运行,输出当前机器的核心硬件信息。注意以管理员身份运行,否则部分字段(如硬盘序列号)可能读不到。
# 采集CPU信息 $cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed # 采集内存信息 $memory = Get-CimInstance -ClassName Win32_PhysicalMemory | Select-Object Manufacturer, Capacity, Speed, SerialNumber # 采集硬盘信息 $disk = Get-CimInstance -ClassName Win32_DiskDrive | Select-Object Model, Size, SerialNumber, InterfaceType # 采集BIOS和主板 $bios = Get-CimInstance -ClassName Win32_BIOS | Select-Object SerialNumber, Manufacturer, SMBIOSBIOSVersion $board = Get-CimInstance -ClassName Win32_BaseBoard | Select-Object Product, Manufacturer, SerialNumber # 输出为JSON $result = [PSCustomObject]@{ CPU = $cpu Memory = $memory Disk = $disk BIOS = $bios Board = $board } $result | ConvertTo-Json -Depth 3 | Out-File -FilePath "C:\AssetInfo.json" -Encoding UTF8逻辑说明:Get-CimInstance是PowerShell推荐的WMI查询方式,比老旧的Get-WmiObject性能更好。Select-Object只保留需要的字段,避免输出冗余。ConvertTo-Json把对象转成JSON,方便后续入库或上传。参数方面,-Depth 3确保嵌套对象(如内存数组)被完整序列化,-Encoding UTF8防止中文型号乱码。
2.3 用wmic命令做轻量级采集
如果目标机器不允许运行PowerShell脚本,或者你只想快速看一眼,wmic命令是最轻量的选择。下面几条命令分别采集CPU、内存、硬盘和主板序列号。
wmic cpu get Name,NumberOfCores,NumberOfLogicalProcessors /format:csv wmic memorychip get Manufacturer,Capacity,Speed,SerialNumber /format:csv wmic diskdrive get Model,Size,SerialNumber,InterfaceType /format:csv wmic bios get SerialNumber,Manufacturer,SMBIOSBIOSVersion /format:csv wmic baseboard get Product,Manufacturer,SerialNumber /format:csv/format:csv让输出直接是逗号分隔,方便重定向到文件。注意wmic在Windows 11部分版本里已被标记为弃用,但截至我写这篇文章时仍能正常使用。如果遇到命令不存在,改用Get-CimInstance即可。
2.4 跨平台场景:Linux下用dmidecode和lshw
企业里如果有Linux服务器或国产化终端,采集方式不同。dmidecode能读SMBIOS信息,lshw能列出所有硬件。下面这条命令输出JSON格式的硬件摘要。
sudo lshw -json > /tmp/hardware.json sudo dmidecode -t system -t baseboard -t processor -t memory > /tmp/dmi.txtlshw -json适合程序解析,dmidecode适合人工核对。注意dmidecode需要root权限,普通用户只能看到部分信息。
3. 把采集结果变成资产台账:批量执行与数据清洗
3.1 批量下发脚本的三种方式
单台机器跑通后,下一步是批量执行。常见做法有三种:域环境用组策略登录脚本,非域环境用PsExec远程执行,或者用计划任务定时运行。我一般会写一个入口脚本,放在共享目录,然后通过组策略推送到每台机器。
# 入口脚本:采集后写入网络共享 $sharePath = "\\192.168.1.10\asset$" $fileName = "$env:COMPUTERNAME" + "_" + (Get-Date -Format "yyyyMMdd") + ".json" $localFile = "C:\Temp\AssetInfo.json" # 调用采集脚本 & "\\192.168.1.10\asset$\collect.ps1" # 复制到共享目录 Copy-Item -Path $localFile -Destination (Join-Path $sharePath $fileName) -Force逻辑说明:$env:COMPUTERNAME作为文件名前缀,避免多台机器覆盖。Get-Date加日期,方便追溯。Copy-Item -Force覆盖旧文件。参数方面,共享目录需要给域计算机账户写权限,否则复制失败。
3.2 用Python做数据清洗和去重
采集上来的JSON文件往往有重复、字段缺失、单位不统一的问题。比如内存容量是字节数,硬盘容量也是字节数,但台账里需要GB。下面这段Python脚本读取所有JSON,清洗后输出CSV。
import json import glob import csv import os def bytes_to_gb(value): if value is None: return 0 return round(int(value) / (1024**3), 2) rows = [] for file in glob.glob("//192.168.1.10/asset$/*.json"): with open(file, "r", encoding="utf-8") as f: data = json.load(f) hostname = os.path.basename(file).split("_")[0] cpu = data.get("CPU", [{}])[0] memory_list = data.get("Memory", []) disk_list = data.get("Disk", []) total_mem = sum(bytes_to_gb(m.get("Capacity")) for m in memory_list) total_disk = sum(bytes_to_gb(d.get("Size")) for d in disk_list) rows.append({ "主机名": hostname, "CPU型号": cpu.get("Name", "").strip(), "核心数": cpu.get("NumberOfCores", ""), "内存GB": total_mem, "硬盘GB": total_disk, "BIOS序列号": data.get("BIOS", {}).get("SerialNumber", "").strip(), "主板序列号": data.get("Board", {}).get("SerialNumber", "").strip() }) with open("asset_summary.csv", "w", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=rows[0].keys()) writer.writeheader() writer.writerows(rows)逻辑说明:glob.glob遍历共享目录下所有JSON。bytes_to_gb统一单位。data.get("CPU", [{}])[0]防止CPU字段为空导致索引报错。encoding="utf-8-sig"让Excel打开CSV不乱码。参数方面,共享目录路径需要根据实际环境修改,rows[0].keys()要求至少有一个文件,否则报错。
3.3 入库与去重策略
如果企业有资产管理系统,可以把CSV导入数据库。常见做法是用主机名加BIOS序列号作为唯一键,每次采集后做UPSERT。下面这条SQL在MySQL里创建表并插入数据。
CREATE TABLE asset ( id INT AUTO_INCREMENT PRIMARY KEY, hostname VARCHAR(64) NOT NULL, cpu_model VARCHAR(128), cores INT, memory_gb DECIMAL(10,2), disk_gb DECIMAL(10,2), bios_sn VARCHAR(64), board_sn VARCHAR(64), collect_date DATE, UNIQUE KEY uk_host_sn (hostname, bios_sn) ); INSERT INTO asset (hostname, cpu_model, cores, memory_gb, disk_gb, bios_sn, board_sn, collect_date) VALUES ('PC-001', 'Intel Core i5-10400', 6, 16.00, 512.00, 'ABC123', 'DEF456', CURDATE()) ON DUPLICATE KEY UPDATE cpu_model = VALUES(cpu_model), cores = VALUES(cores), memory_gb = VALUES(memory_gb), disk_gb = VALUES(disk_gb), board_sn = VALUES(board_sn), collect_date = VALUES(collect_date);逻辑说明:UNIQUE KEY确保同一台机器同一天不会重复插入。ON DUPLICATE KEY UPDATE实现UPSERT,硬件变更时更新字段。参数方面,bios_sn作为唯一标识比主机名更可靠,因为主机名可能被修改。
4. 避坑与排查:硬件信息采集的五个血泪教训
4.1 现象:硬盘序列号读出来是乱码或空值
原因:部分NVMe硬盘的序列号在WMI里返回的是十六进制字符串,或者需要管理员权限才能读取。另外,某些品牌机(如部分联想、戴尔机型)的硬盘序列号被厂商工具隐藏。
解决:以管理员身份运行脚本;如果仍为空,改用Get-PhysicalDisk | Select-Object SerialNumber;再不行就用厂商提供的命令行工具(如戴尔的omreport)兜底。
4.2 现象:内存条只读到一条,实际插了两条
原因:Win32_PhysicalMemory在某些主板BIOS下只返回第一条内存的信息,或者双通道内存被识别为一条。
解决:改用Win32_PhysicalMemoryArray读插槽总数,再结合Win32_PhysicalMemory逐条读取。如果还是不对,用wmic memorychip list full交叉验证。
4.3 现象:脚本在部分机器上执行超时
原因:WMI查询本身较慢,尤其是硬盘和网卡类,如果机器同时在做Windows更新,查询可能卡住。
解决:给每个查询加超时限制。PowerShell里可以用-OperationTimeoutSec参数,或者把采集拆成多个小脚本,分步执行。
4.4 现象:采集上来的JSON文件中文乱码
原因:PowerShell默认输出编码是UTF-16或ANSI,Python读取时按UTF-8解析会乱码。
解决:在PowerShell里用Out-File -Encoding UTF8,Python读取时用encoding="utf-8-sig"。如果还是乱码,用chardet库检测编码后再读。
4.5 现象:域环境下组策略脚本不执行
原因:组策略登录脚本默认在用户登录时运行,如果用户没有管理员权限,部分WMI查询会失败。另外,脚本路径如果用了映射驱动器,计算机账户可能访问不到。
解决:改用计算机启动脚本,以系统权限运行;共享目录用IP地址而不是映射驱动器;在组策略里勾选“以最高权限运行”。
5. 进阶:用Python封装成可执行文件并自动上报
5.1 为什么用PyInstaller打包
企业里不是每台机器都装了Python,把采集脚本打包成单个exe,双击就能跑,是最省事的落地方式。PyInstaller能把Python脚本和依赖库打包成一个文件,目标机器不需要装Python。
pip install pyinstaller pyinstaller --onefile --noconsole --name AssetCollector collect.py--onefile生成单个exe,--noconsole不弹黑窗口,--name指定输出文件名。生成的exe在dist目录下,复制到目标机器即可运行。
5.2 自动上报到HTTP接口
采集完成后,把JSON通过HTTP POST上报到资产服务器。下面这段Python代码用requests库实现。
import requests import json import socket def report(data, server_url): payload = { "hostname": socket.gethostname(), "data": data } try: resp = requests.post(server_url, json=payload, timeout=10) if resp.status_code == 200: print("上报成功") else: print(f"上报失败,状态码:{resp.status_code}") except requests.exceptions.RequestException as e: print(f"网络异常:{e}") if __name__ == "__main__": with open("AssetInfo.json", "r", encoding="utf-8") as f: data = json.load(f) report(data, "http://192.168.1.10:8000/api/asset")逻辑说明:socket.gethostname()获取主机名,requests.post发送JSON,timeout=10防止卡死。参数方面,server_url替换成实际接口地址,接口需要支持接收JSON并返回200。
5.3 验证采集完整性的三个检查点
第一,对比设备管理器里看到的硬件数量和脚本采集到的数量是否一致。第二,用Get-CimInstance Win32_ComputerSystem读到的总内存和Win32_PhysicalMemory累加值是否吻合。第三,把采集结果和采购台账做一次全量比对,重点看序列号字段。
我一般会在脚本里加一个自检逻辑:如果CPU、内存、硬盘任一字段为空,就写一条警告日志,方便后续排查。这个习惯帮我省了很多后悔药,因为硬件信息采集最怕的不是采不到,而是采到了但字段是空的,台账看起来有数据,实际没法用。
希望帮到你。
本文还有配套的精品资源,点击获取