65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 WMI 收集远程系统信息

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.45/5 (16投票s)

2004年11月15日

4分钟阅读

viewsIcon

261141

downloadIcon

11364

一篇解释如何使用 WMI 接口连接并从远程计算机收集信息的文章。

引言

最近在对几台服务器进行清点时,我意识到必须登录到每台服务器并访问默认的 Windows 系统信息实用程序是件很麻烦的事。经过一番阅读,我在 MSDN 上找到了 WMI 类。虽然这些类允许访问 Windows 操作系统上的几乎任何信息,但它们需要大量的输入和对多个 WMI 类的调用。并不是只有一个地方可以访问所有信息。这个类解决了这个问题。

背景

这个类是对一些基本 WMI 接口的封装,提供了有关系统的详细信息。该类允许使用当前的安全上下文或指定的用户名和密码来访问远程或本地计算机。一旦连接成功,该类就会用来自该计算机的值进行填充。这让我们能够轻松地访问信息,而不必担心对每个 WMI 接口的调用或如何存储所有信息。我不会花太多时间解释 WMI 或它是什么,除了它是一个用于访问计算机上管理信息的接口。如果您想阅读更多关于该主题的资料,请查看微软的以下链接:Windows Management Instrumentation

使用代码

这个封装类旨在方便地访问本地或远程系统相关的信息。一旦类使用系统数据进行初始化,就不再需要连接到该机器。如果单独完成,用户需要对每个 WMI 接口进行多次调用,然后存储信息。该类会处理所有这些。

要开始使用代码,请先为 DLL 添加引用。要用本地计算机的信息填充该类,请按如下所示传递环回地址:

//
// Create an instance of the class.
//
SystemInformation sysinfo = new SystemInformation();
//
// Set the output error stream to the standard console output.
//
sysinfo.stderr = Console.OpenStandardOutput();
//
// Populate the class and make sure it didn't fail.
//
if (sysinfo.Get("127.0.0.1") != 0)
{
  MessageBox.Show("Error getting system information.", "System Information");
}
else
{
  MessageBox.Show("The current OS version is " + sysinfo.OSVersion.description, 
                                                        "System Information");
}
...

在上面的示例中,还设置了 stderr 属性。此属性允许将封装类中发生的内部错误管道传输到外部流。在此示例中,使用了 Console 类的标准输出流。这个小技巧允许通过调用应用程序控制内部调试信息,这样 SystemInformation 类就不必担心日志记录问题。

要访问远程计算机的信息,您只需将上面的地址更改为外部计算机的地址即可。连接到远程或本地计算机时,将使用当前用户上下文来验证用户。如果当前上下文没有访问该计算机的权限,则会出现问题。例如,如果在作为匿名用户帐户运行的 Web 应用程序中使用此类。要解决此问题,您可以将用户凭据传递给该类的 Get 方法,如下所示:

//
// Create an instance of the class.
//
SystemInformation sysinfo = new SystemInformation();
//
// Set the output error stream to the standard console output.
//
sysinfo.stderr = Console.OpenStandardOutput();
//
// Populate the class and make sure it didn't fail.
//
if (sysinfo.Get("127.0.0.1", "johndoe", "password") != 0)
{
  MessageBox.Show("Error getting system information.", "System Information");
}
else
{
  MessageBox.Show("The current OS version is " + sysinfo.OSVersion.description, 
                                                        "System Information");
}
...

这样做时,连接到远程计算机时将模拟指定的用户。如果需要,用户名还可以包含域。请注意,如果用户名或密码在您正在连接的计算机上无效,该方法将失败并返回错误代码。

包含的演示项目连接到本地计算机,并以与 Windows 自带的系统信息实用程序类似的方式显示所有信息。它不是一个完整的应用程序,仅用于演示类的功能。

关注点

上面的代码仅在 Windows 2000/2003/XP 上进行了测试。它可能适用于其他系统,但我没有测试过。另外,为了使类能够连接到计算机,必须可用 RPC 服务。大多数防火墙会阻止此类流量。

在类中,您可能会注意到有两个方法用于查询接口。第一种方法使用 ManagementObjectSearcher 类。另一种使用 ManagementClass 类。虽然这两种方法都执行类似的任务并返回数据集合,但后者不允许指定要返回的属性,也不允许使用 WHERE 子句进行过滤。

我发现的一个问题是,在查询数据时,时区被返回为表示与 GMT 时间偏移(以分钟为单位)的整数。虽然这对于进行计算很有用,但很难阅读。虽然可以构建一个包含所有时区的静态列表并将值映射到此,但我选择了一种更动态的方式。Windows 在注册表中存储有关时区的所有信息。通过查询这些键,您可以确定分钟数对应于哪个时区。结构会填充时区信息,因此同时包含以分钟为单位的偏移量和可读的时区版本。

历史

  • v1.0
    • 首次构建。没什么特别的。
  • v1.1
    • 添加了从注册表中获取标准时区名称的功能,使其更具可读性。
  • v1.2
    • 该类现在返回正确的错误代码,并有一个新方法用于访问扩展错误代码(如果适用)。还修改了示例以允许连接到多个主机。
© . All rights reserved.