张赐荣,视障者,信息无障碍专家
深耕Web/PC/移动端可访问性研究与实践工作多年,对跨平台无障碍解决方案拥有深刻的独特理论和丰富的实战经验。
精通视障用户软件交互设计,致力于用专业的能力改善、提升产品可及性体验。

張賜榮

张赐荣的技术博客

博客园 首页 新随笔 联系 订阅 管理

C# 使用 WMI 查询系统信息

【文 / 张赐荣】

前言

Windows Management Instrumentation (WMI) 是Windows系统管理的核心技术之一,它提供了统一的接口来访问操作系统各个层面的信息。无论是系统管理员、安全工程师还是开发人员,掌握WMI都能极大提升工作效率。本文介绍WMI的核心基础概念,并通过C#实例演示如何利用WMI进行系统信息查询。

一、WMI基础概念

1.1 什么是WMI?

WMI(Windows Management Instrumentation)是微软基于Web-Based Enterprise Management (WBEM)和Common Information Model (CIM)标准实现的Windows系统管理框架。简单来说,它是Windows系统的"神经系统",可以实现:

  • 查询硬件和软件配置
  • 监控系统状态
  • 执行管理任务
  • 响应系统事件

1.2 WMI架构组成

WMI采用三层架构模型:

  1. 管理应用程序层:如我们的C#程序、PowerShell脚本等
  2. WMI基础设施层:包括CIM对象管理器(CIMOM)和WMI存储库
  3. WMI提供程序层:与实际被管理资源交互的组件

1.3 WMI命名空间

WMI使用命名空间组织管理数据,类似于文件系统的目录结构。常见命名空间包括:

  • root\cimv2:最常用的命名空间,包含大多数系统类
  • root\default:注册表相关类
  • root\security:安全相关类
  • root\directory\ldap:Active Directory相关类

二、WMI查询语言(WQL)

WQL是WMI的查询语言,语法类似于SQL。基本语法结构:

SELECT [属性列表] FROM [类名] 
[WHERE 条件] 

示例查询:

SELECT Name, ProcessId FROM Win32_Process WHERE Name = 'nvda.exe'

三、C#中的WMI编程

3.1 准备工作

在C#中使用WMI需要添加System.Management命名空间:

using System.Management;

3.2 核心类介绍

  1. ManagementObjectSearcher:执行WQL查询
  2. ManagementObjectCollection:查询结果集合
  3. ManagementObject:表示单个WMI对象

3.3 基础查询示例

请看下面的代码:

// 创建查询器,查询Win32_Process类的所有实例
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Process");

// 遍历查询结果中的每个进程对象
foreach (ManagementObject os in searcher.Get())
{
    // 遍历对象的每个属性
    foreach (var property in os.Properties)
    {
        // 输出属性名和值
        Console.WriteLine($"{property.Name}: {property.Value}");
    }
    Console.WriteLine("----------");
}

这段代码做了以下几件事:

  1. 查询所有正在运行的进程(Win32_Process类)
  2. 获取查询结果集合
  3. 遍历每个进程对象
  4. 输出每个进程的所有属性

3.4 代码讲解

创建查询器

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Process");

这里创建了一个ManagementObjectSearcher实例,传入WQL查询语句。默认使用root\cimv2命名空间。

执行查询

foreach (ManagementObject os in searcher.Get())

searcher.Get()执行查询并返回ManagementObjectCollection集合,我们可以用foreach遍历结果。

处理结果

foreach (var property in os.Properties)
{
    Console.WriteLine($"{property.Name}: {property.Value}");
}

每个ManagementObject都有Properties集合,包含该WMI类的所有属性。我们可以遍历这些属性获取详细信息。

四、实用WMI查询示例

4.1 获取系统信息

using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem"))
{
    foreach (ManagementObject os in searcher.Get())
    {
        Console.WriteLine($"OS名称: {os["Caption"]}");
        Console.WriteLine($"版本: {os["Version"]}");
        Console.WriteLine($"安装日期: {ManagementDateTimeConverter.ToDateTime(os["InstallDate"].ToString())}");
    }
}

4.2 查询CPU信息

using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"))
{
    foreach (ManagementObject cpu in searcher.Get())
    {
        Console.WriteLine($"CPU型号: {cpu["Name"]}");
        Console.WriteLine($"核心数: {cpu["NumberOfCores"]}");
        Console.WriteLine($"时钟频率: {cpu["MaxClockSpeed"]}MHz");
    }
}

4.3 监控进程创建事件

// 创建事件查询
WqlEventQuery query = new WqlEventQuery(
    "__InstanceCreationEvent",
    new TimeSpan(0, 0, 1),
    "TargetInstance isa 'Win32_Process'");

// 创建事件监听器
ManagementEventWatcher watcher = new ManagementEventWatcher(query);

// 设置事件处理程序
watcher.EventArrived += (sender, e) => 
{
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    Console.WriteLine($"新进程创建: {instance["Name"]} (PID: {instance["ProcessId"]})");
};

// 开始监听
watcher.Start();

五、WMI高级主题

5.1 远程WMI查询

只需在创建ManagementObjectSearcher时指定连接选项:

ConnectionOptions options = new ConnectionOptions();
options.Username = "username";
options.Password = "password";
options.Authority = "ntlmdomain:DOMAIN";

ManagementScope scope = new ManagementScope(
    @"\\远程计算机名\root\cimv2", 
    options);

ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, 
    new ObjectQuery("SELECT * FROM Win32_Process"));

5.2 异步查询

ManagementOperationObserver observer = new ManagementOperationObserver();

observer.Completed += (sender, e) => 
{
    Console.WriteLine("查询完成!");
};

observer.ObjectReady += (sender, e) => 
{
    Console.WriteLine($"进程名: {e.NewObject["Name"]}");
};

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Process");
searcher.Get(observer);

5.3 调用WMI方法

许多WMI类提供了可调用的方法。例如,终止进程:

using (ManagementObject process = new ManagementObject($"Win32_Process.Handle='{pid}'"))
{
    ManagementBaseObject outParams = process.InvokeMethod("Terminate", null, null);
    uint returnValue = (uint)outParams["ReturnValue"];
    Console.WriteLine($"方法返回值: {returnValue}");
}

六、WMI最佳实践

  1. 资源释放:始终确保释放WMI资源,推荐使用using语句
  2. 错误处理:WMI操作可能抛出ManagementException
  3. 性能优化
    • 只查询需要的属性
    • 对远程查询使用异步方式
    • 合理设置查询超时
  4. 安全考虑
    • 最小权限原则
    • 加密远程连接(DCOM加密或使用WinRM)

七、常见问题解答

Q1: WMI和注册表有什么区别?

A1: WMI提供了更高层次的抽象,可以访问包括但不限于注册表的信息。相比直接访问注册表,WMI更安全、更结构化,且支持远程访问。

Q2: 为什么我的WMI查询很慢?

A2: WMI查询性能受多种因素影响:

  • 查询范围过大(使用WHERE子句缩小范围)
  • 远程网络延迟
  • 目标系统负载高
  • 查询了大型数据集(如事件日志)

Q3: 如何排查WMI问题?

A3: 可以使用以下工具:

  • wbemtest:WMI测试工具
  • Windows事件查看器:查看WMI-Activity日志
  • winmgmt /verifyrepository:检查WMI存储库完整性

结语

通过本文,我们全面了解了WMI的核心概念和架构,并通过C#实例演示了如何利用WMI进行系统信息查询。WMI是Windows系统管理的强大工具,掌握它可以让你在系统管理、监控和自动化方面如虎添翼。建议读者从简单的查询开始,逐步探索WMI的更多可能性。

附录:常用WMI类参考

类名 描述
Win32_OperatingSystem 操作系统信息
Win32_Processor CPU信息
Win32_PhysicalMemory 内存信息
Win32_DiskDrive 物理磁盘信息
Win32_Process 进程信息
Win32_Service 服务信息
Win32_NetworkAdapterConfiguration 网络配置
Win32_Product 安装的软件
Win32_StartupCommand 启动项
posted on 2025-06-22 22:27  张赐荣  阅读(177)  评论(0)    收藏  举报

感谢您访问张赐荣的技术分享博客!
博客地址:https://cnblogs.com/netlog/
知乎主页:https://www.zhihu.com/people/tzujung-chang
个人网站:https://prc.cx/