
在日常开发中,可能需要获取每台设备的一个唯一码,那么如何获取每台设备的唯一码呢?一般的做法是获取系统唯一的序列号之类,比如硬盘序列号、CPU序列号、系统ID等等,因为每个电脑的序列号不一定一样(不排除有完全一样的,例如拷贝的虚拟机等),所以想要绝对的不一样也有一定的困难。
那么问题来了,如何获取诸如硬盘序列号、CPU序列号或者硬盘容量等呢?有多种方法,比如使用三方的控件,本文介绍的方法不适用第三方控件,直接使用windows的WMI框架来获取。
下面先介绍下WMI,然后提供一个通过WMI实现获取电脑唯一码的程序。
Windows Management Instrumentation(WMI,Windows 管理规范)是微软推出的一套用于管理 Windows 系统及应用程序的标准化接口和技术,基于分布式管理任务组(DMTF)的通用信息模型(CIM)标准,提供了统一的方式来查询、配置、监控和控制系统资源。
一、WMI 的核心组成
-
CIM 对象管理器(CIMOM) WMI 的核心服务(
winmgmt服务),负责处理 WMI 请求、管理 CIM 对象库(存储系统资源的元数据),并协调与底层系统的交互。 -
**WMI 命名空间(Namespace)**用于组织和隔离管理对象的逻辑容器,类似文件系统的目录。常用命名空间:
root\cimv2:最常用,包含操作系统、硬件、软件等核心管理对象(如进程、服务、磁盘)。root\subscription:用于 WMI 事件订阅(如监控进程创建、服务启动)。root\securitycenter2:系统安全相关信息(如防火墙、 antivirus 状态)。
-
WMI 类(Class) 描述可管理资源的模板,每个类对应一类系统资源(如
Win32_Process对应进程,Win32_Service对应服务)。类包含属性 (资源的特征,如Name、ProcessId)和方法 (可执行的操作,如Create创建进程、StopService停止服务)。 -
WQL 查询语言WMI 查询语言(WMI Query Language),语法类似 SQL,用于从 WMI 类中查询对象。例如:
wql
SELECT Name, ProcessId FROM Win32_Process WHERE Name = 'notepad.exe'
二、WMI 的核心功能
-
系统信息查询获取硬件(CPU、内存、磁盘、网络适配器)、软件(进程、服务、安装的程序)、操作系统(版本、启动时间、用户)等信息。
-
系统配置管理远程或本地修改系统设置,如启动 / 停止服务、创建 / 终止进程、修改注册表、配置网络适配器等。
-
事件监控与响应订阅系统事件(如进程创建、服务状态变化、磁盘空间不足),并触发自定义操作(如日志记录、自动修复)。
-
远程管理通过网络远程管理其他 Windows 设备(需权限配置),支持跨域、防火墙穿透(基于 DCOM 或 WS-Management 协议)。
三、WMI 的典型应用场景
1. 系统监控与诊断
- 硬件监控 :查询 CPU 使用率(
Win32_Processor.LoadPercentage)、内存占用(Win32_PhysicalMemory)、磁盘空间(Win32_LogicalDisk.FreeSpace)等,用于性能分析或告警。 - 软件监控 :实时监控进程启动 / 退出(通过
Win32_ProcessTrace事件类)、服务状态(Win32_Service.State),排查异常程序。
2. 批量管理与自动化
- 企业级设备管理:通过脚本(PowerShell/VBScript)或工具批量查询域内所有计算机的硬件配置(如是否安装某型号显卡)、软件版本(如 Office 版本)。
- 自动化运维 :编写脚本自动执行重复性任务,例如:
- 停止所有名为 "testService" 的服务:
Get-WmiObject Win32_Service -Filter "Name='testService'" | Invoke-WmiMethod -Name StopService(PowerShell)。 - 远程在多台计算机上创建文件夹:调用
Win32_FileSystemObject的CreateFolder方法。
- 停止所有名为 "testService" 的服务:
3. 安全审计与日志
- 进程审计 :记录所有新启动的进程(通过
Win32_Process的Create事件),追踪可疑程序。 - 权限检查 :查询用户组信息(
Win32_Group)、登录会话(Win32_LogonSession),审计未授权访问。
4. 开发集成
- 应用程序扩展:在 C++/C#/Delphi 等语言中调用 WMI 接口,让程序获取系统信息(如在安装程序中检查磁盘空间是否足够)。
- 设备驱动管理 :查询即插即用设备(
Win32_PnPEntity),开发硬件监控工具。
四、WMI 的使用工具与方式
-
命令行工具
-
wmic:Windows 命令行 WMI 客户端,支持直接执行 WQL 查询。例如:cmd
wmic process where "name='notepad.exe'" get name, processid # 查询记事本进程 wmic service where "state='running'" get name, displayname # 查询运行中的服务 -
PowerShell:更强大的 WMI 交互工具,通过
Get-WmiObject(旧)或Get-CimInstance(新) cmdlet 操作。
-
-
脚本语言
-
VBScript:通过
GetObject("winmgmts:")连接 WMI 服务,适合编写简单管理脚本。 -
PowerShell:原生支持 WMI/CIM,语法更简洁,例如: powershell
# 获取所有物理磁盘大小 Get-CimInstance -ClassName Win32_DiskDrive | Select-Object Model, Size
-
-
编程语言
- C#:通过
System.Management命名空间(如ManagementObjectSearcher类)调用 WMI。 - Delphi:通过
ISWbemLocator、ISWbemServices等 COM 接口操作(如前文示例)。 - C++:使用 WMI C API(如
IWbemLocator接口)。
- C#:通过
-
图形化工具
- WMI Explorer:第三方工具,可视化浏览 WMI 命名空间、类、属性和方法,适合学习和调试。
- 计算机管理 :Windows 自带工具(
compmgmt.msc),通过 "WMI 控制" 管理 WMI 配置(如安全权限)。
五、WMI 的优缺点
-
优点:
- 标准化:基于 CIM 标准,接口统一,无需针对不同硬件 / 软件编写专用代码。
- 功能全面:覆盖系统管理的几乎所有场景(硬件、软件、事件、配置)。
- 远程能力:支持跨网络管理,适合企业级批量操作。
-
缺点:
- 复杂度高:类和属性繁多,初学者需花时间学习(可参考微软 WMI 类文档)。
- 性能开销:复杂查询或大量对象遍历可能占用较多系统资源。
- 安全风险:若配置不当,可能被恶意利用(如远程执行命令),需严格控制 WMI 权限。
六、总结
WMI 是 Windows 系统管理的核心技术,通过统一的接口和查询语言,实现了对系统资源的全方位管理。无论是日常运维、批量管理、应用程序开发还是安全审计,WMI 都能提供强大的支持。掌握 WMI 的使用,能显著提升 Windows 系统管理的效率和自动化水平。
七、Delphi 样例说明
Delphi
function Get_Win32_Item_Value(Win32_ClassName,ItemName : string) : string;
var
FSWbemLocator : OleVariant;
FWMIService : OleVariant;
FWbemObjectSet: OleVariant;
FWbemObject : OleVariant;
oEnum : IEnumvariant;
QueryStr : string;
iValue : LongWord;
OleValue : OleVariant;
i : Integer;
begin
//初始化数据
if not VarIsClear(FSWbemLocator) then FSWbemLocator := Null;
if not VarIsClear(FWMIService) then FWMIService := Null;
if not VarIsClear(FWbemObjectSet) then FWbemObjectSet := Null;
if not VarIsClear(FWbemObject) then FWbemObject := Null;
CoInitialize(nil);
try
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost','root\CIMV2','','');
QueryStr := 'SELECT ' + ItemName + ' FROM ' + Win32_ClassName;
FWbemObjectSet:= FWMIService.ExecQuery(QueryStr,'WQL',0,Null);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVARIANT;
while oEnum.Next(1,FWbemObject,iValue) = S_OK do
begin
if iValue <> 1 then Break;
OleValue := FWbemObject.Properties_.Item(ItemName); //取得返回的属性值
if VarIsNull(OleValue) then
Result := 'NULL'
else
if VarIsArray(OleValue) then
begin
Result := '';
for I := VarArrayLowBound(Result, 1) to VarArrayHighBound(Result, 1) do
Result := Result + ' | ' + VarToStr(VarArrayGet(OleValue,[i]));
end
else
begin
Result := VarToStr(OleValue);
if varType(OleValue) = varDispatch then //日期型
Result := Result.Substring(0,14);
end;
//只需要循环一次,直接退出
Break;
end;
finally
CoUninitialize;
end;
end;