使用 C# 远程连接到 WMI

与其他语言(如 PowerShell、VBScript 或 C++)一样,可以使用 C# 远程监视远程计算机上的硬件和软件。 托管代码的远程连接通过 Microsoft.Management.Infrastructure 命名空间完成。 (WMI 的早期版本使用 System.Management,为了完整起见,此处包含该命名空间。)

注意

System.Management 是用于访问 WMI 的原始 .NET 命名空间;但是,此命名空间中的 API 通常运行较慢,并且相对于其更新式的 Microsoft.Management.Infrastructure 对应项,它们无法缩放。

 

使用 Microsoft.Management.Infrastructure 命名空间中的类建立远程连接时,使用 DCOM 作为基础远程机制。 WMI 远程连接必须符合 DCOM 对模拟和身份验证的安全要求。 默认情况下,范围会绑定到本地计算机和“Root\CIMv2”系统命名空间上。 但是,可以更改访问的计算机、域和 WMI 命名空间。 还可以设置颁发机构、模拟、凭据和其他连接选项。

使用 C# 远程连接到 WMI (Microsoft.Management.Infrastructure)

  1. 通过调用 CimSession.Create 在远程计算机上创建会话。

    如果使用与登录时使用的相同凭据(域和用户名)连接到远程计算机,则可以在 Create 调用中指定计算机的名称。 获得返回的 CimSession 对象后,即可进行 WMI 查询。

    using Microsoft.Management.Infrastructure;
    ...
    string Namespace = @"root\cimv2";
    string OSQuery = "SELECT * FROM Win32_OperatingSystem";
    CimSession mySession = CimSession.Create("Computer_B");
    IEnumerable<CimInstance> queryInstance = mySession.QueryInstances(Namespace, "WQL", OSQuery);
    

    有关在 C# 中使用 Microsoft.Management.Infrastructure API 进行 WMI 查询的详细信息,请参阅检索 WMI 类或实例数据

  2. 如果要为连接设置不同的选项,例如不同的凭据、区域设置或模拟级别,则需要在调用 CimSession.Create 时使用 CimSessionOptions 对象。

    CimSessionOptionsWSManSessionOptionsDComSessionOptions 的基类。 可以使用任一方法分别设置 WS-Man 会话和 DCOM 会话上的选项。 以下代码示例介绍如何使用 DComSessionOptions 对象将模拟级别设置为“模拟”。

    string computer = "Computer_B"
    DComSessionOptions DComOptions = new DComSessionOptions();
    DComOptions.Impersonation = ImpersonationType.Impersonate;
    
    CimSession Session = CimSession.Create(computer, DComOptions);
    
  3. 如果要设置连接的凭据,则需要创建 CimCredentials 对象并将其添加到 CimSessionOptions

    以下代码示例介绍创建 WSManSessionOptions 类,使用适当的 CimSessionOptions 填充该类,并在 CimSession.Create 调用中使用它。

    string computer = “Computer_B”;
    string domain = “Domain1″;
    string username = “User1″;
    
    string plaintextpassword; 
    
    //Retrieve password from the user. 
    //For the complete code, see the sample at the bottom of this topic.
    
    CimCredential Credentials = new CimCredential(PasswordAuthenticationMechanism.Default, domain, username, securepassword); 
    
    WSManSessionOptions SessionOptions = new WSManSessionOptions();
    SessionOptions.AddDestinationCredentials(Credentials); 
    
    CimSession Session = CimSession.Create(computer, SessionOptions);
    

    通常建议不要将密码硬编码到应用程序中;如上面的代码示例所示,尽可能尝试向用户查询密码,并安全地存储密码。

WMI 用于监视远程计算机上的硬件和软件。 WMI v1 的远程连接通过 ManagementScope 对象实现。

使用 C# 远程连接到 WMI (System.Management)

  1. 使用计算机名称和 WMI 路径创建 ManagementScope 对象,并通过调用 ManagementScope.Connect() 连接到目标。

    如果使用与登录时使用的相同凭据(域和用户名)连接到远程计算机,则只需要指定 WMI 路径。 连接后,可以进行 WMI 查询。

    using System.Management;
    ...
    ManagementScope scope = new ManagementScope("\\\\Computer_B\\root\\cimv2");
    scope.Connect();
    ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
    

    有关在 C# 中使用 System.Management API 进行 WMI 查询的详细信息,请参阅检索 WMI 类或实例数据

  2. 如果连接到不同域中的远程计算机,或者使用不同的用户名和密码,则必须在对 ManagementScope 的调用中使用 ConnectionOptions 对象。

    ConnectionOptions 包含用于描述身份验证、模拟、用户名、密码和其他连接选项的属性。 以下代码示例介绍如何使用 ConnectionOptions 对象将模拟级别设置为“模拟”。

    ConnectionOptions options = new ConnectionOptions();
    options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
    
    ManagementScope scope = new ManagementScope("\\\\FullComputerName\\root\\cimv2", options);
    scope.Connect();
    
    ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
    ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,query);
    

    通常,除非另有明确要求,否则建议将模拟级别设置为“模拟”。 此外,请尽量避免将名称和密码写入 C# 代码。 (如果可能,请查看是否可以查询用户以在运行时动态提供。)

    有关在远程 WMI 连接上设置不同属性的更多示例,请参阅 ConnectionOptions 参考页的“示例”部分。

Microsoft.Management.Infrastructure 示例

以下 C# 代码示例基于 TechNet 上的博客文章,介绍如何使用 CimCredentialsWSManSessionOptions 在远程连接上设置凭据。

using System;
using System.Text;
using System.Threading;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
using System.Security; 

namespace SMAPIQuery
{
    class Program
    {
        static void Main(string[] args)
        { 

            string computer = "Computer_B";
            string domain = "DOMAIN";
            string username = "AdminUserName";


            string plaintextpassword; 

            Console.WriteLine("Enter password:");
            plaintextpassword = Console.ReadLine(); 

            SecureString securepassword = new SecureString();
            foreach (char c in plaintextpassword)
            {
                securepassword.AppendChar(c);
            } 

            // create Credentials
            CimCredential Credentials = new CimCredential(PasswordAuthenticationMechanism.Default, 
                                                          domain, 
                                                          username, 
                                                          securepassword); 

            // create SessionOptions using Credentials
            WSManSessionOptions SessionOptions = new WSManSessionOptions();
            SessionOptions.AddDestinationCredentials(Credentials); 

            // create Session using computer, SessionOptions
            CimSession Session = CimSession.Create(computer, SessionOptions); 

            var allVolumes = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_Volume");
            var allPDisks = Session.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_DiskDrive"); 

            // Loop through all volumes
            foreach (CimInstance oneVolume in allVolumes)
            {
                // Show volume information

                if (oneVolume.CimInstanceProperties["DriveLetter"].ToString()[0] > ' '  )
                {
                    Console.WriteLine("Volume ‘{0}’ has {1} bytes total, {2} bytes available", 
                                      oneVolume.CimInstanceProperties["DriveLetter"], 
                                      oneVolume.CimInstanceProperties["Size"], 
                                      oneVolume.CimInstanceProperties["SizeRemaining"]);
                }

            } 

            // Loop through all physical disks
            foreach (CimInstance onePDisk in allPDisks)
            {
                // Show physical disk information
                Console.WriteLine("Disk {0} is model {1}, serial number {2}", 
                                  onePDisk.CimInstanceProperties["DeviceId"], 
                                  onePDisk.CimInstanceProperties["Model"].ToString().TrimEnd(), 
                                  onePDisk.CimInstanceProperties["SerialNumber"]);
            } 

            Console.ReadLine();
         }
     }
 }

System.Management 示例

以下 C# 代码示例介绍使用 System.Management 对象的常规远程连接。

using System;
using System.Management;
public class RemoteConnect 
{
    public static void Main() 
    {
        ConnectionOptions options = new ConnectionOptions();
        options.Impersonation = System.Management.ImpersonationLevel.Impersonate;

        
        ManagementScope scope = new ManagementScope("\\\\FullComputerName\\root\\cimv2", options);
        scope.Connect();

        //Query system for Operating System information
        ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,query);

        ManagementObjectCollection queryCollection = searcher.Get();
        foreach ( ManagementObject m in queryCollection)
        {
            // Display the remote computer information
            Console.WriteLine("Computer Name     : {0}", m["csname"]);
            Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
            Console.WriteLine("Operating System  : {0}", m["Caption"]);
            Console.WriteLine("Version           : {0}", m["Version"]);
            Console.WriteLine("Manufacturer      : {0}", m["Manufacturer"]);
        }
    }
}

连接到远程计算机上的 WMI