Conexão remota ao WMI com C#

Assim como acontece com outras linguagens, como PowerShell, VBScript ou C++, você pode usar C# para monitorar hardware e software remotamente em computadores remotos. As conexões remotas para código gerenciado são realizadas por meio do namespace Microsoft.Management.Infrastructure . (As versões anteriores do WMI usavam o namespace System.Management, que está incluído aqui para efeito de integridade.)

Observação

System.Management era o namespace original do .NET usado para acessar o WMI. No entanto, as APIs nesse namespace geralmente são mais lentas e não escalam tão bem em relação às contrapartes mais modernas do Microsoft.Management.Infrastructure.

 

A conexão remota usando classes no namespace Microsoft.Management.Infrastructure usa o DCOM como mecanismo remoto subjacente. As conexões remotas do WMI devem estar em conformidade com os requisitos de segurança do DCOM para representação e autenticação. Por padrão, um escopo é associado ao computador local e ao namespace do sistema "Root\CIMv2". No entanto, você pode alterar o computador, o domínio e o namespace do WMI que você acessa. Você também pode definir autoridade, representação, credenciais e outras opções de conexão.

Para se conectar ao WMI remotamente com C# (Microsoft.Management.Infrastructure)

  1. Crie uma sessão no computador remoto com uma chamada para CimSession.Create.

    Se estiver se conectando a um computador remoto usando as mesmas credenciais (domínio e nome de usuário) com as quais está conectado, você poderá especificar o nome do computador na chamada Criate. Assim que tiver o objeto CimSession retornado, você poderá fazer sua consulta 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);
    

    Para obter mais informações sobre como fazer consultas no WMI com a API Microsoft.Management.Infrastructure em C#, consulte Recuperar dados de instância ou classe WMI.

  2. Se quiser definir opções diferentes para sua conexão, como credenciais diferentes, níveis de localidade ou representação, você precisará usar um objeto CimSessionOptions em sua chamada para CimSession.Create.

    CimSessionOptions é uma classe base para WSManSessionOptions e DComSessionOptions. Você pode usar qualquer uma delas para definir as opções em suas sessões WS-Man e DCOM, respectivamente. O exemplo de código a seguir descreve o uso de um objeto DComSessionOptions para definir o nível de Representação como Representar.

    string computer = "Computer_B"
    DComSessionOptions DComOptions = new DComSessionOptions();
    DComOptions.Impersonation = ImpersonationType.Impersonate;
    
    CimSession Session = CimSession.Create(computer, DComOptions);
    
  3. Se quiser definir as credenciais para sua conexão, você precisará criar e adicionar um objeto CimCredentials a CimSessionOptions.

    O exemplo de código a seguir descreve como criar uma classe WSManSessionOptions, preenchê-la com o CimSessionOptions adequado e usá-la em uma chamada 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);
    

    Geralmente, é recomendável que você não codifique uma senha em seus aplicativos; como indica o exemplo de código acima, sempre que possível, tente consultar a senha do usuário e armazená-la com segurança.

O WMI se destina a monitorar o hardware e o software em computadores remotos. As conexões remotas para o WMI v1 são realizadas por meio do objeto ManagementScope.

Para se conectar ao WMI remotamente com C# (System.Management)

  1. Crie um objeto ManagementScope usando o nome do computador e o caminho WMI e conecte-se ao seu destino com uma chamada para ManagementScope.Connect().

    Se estiver se conectando a um computador remoto usando as mesmas credenciais (domínio e nome de usuário) com as quais está conectado, basta especificar o caminho WMI. Depois de se conectar, você pode fazer sua consulta 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);
    

    Para obter mais informações sobre como fazer consultas no WMI com a API System.Management em C#, consulte Recuperar dados de instância ou classe WMI.

  2. Caso se conecte a um computador remoto em um domínio diferente ou usando um nome de usuário e senha diferentes, você deverá usar um objeto ConnectionOptions na chamada para o ManagementScope.

    O ConnectionOptions contém propriedades para descrever a autenticação, representação, nome de usuário, senha e outras opções de conexão. O exemplo de código a seguir descreve o uso de um ConnectionOptions para definir o nível de Representação como Representar.

    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);
    

    Em termos gerais, é recomendável que você defina o nível de Representação como Representar, a menos que o contrário seja explicitamente necessário. Além disso, tente evitar escrever seu nome e senha no código C#. (Se possível, veja se pode consultar o usuário para fornecê-lo dinamicamente em runtime.)

    Para obter mais exemplos de como definir propriedades diferentes em uma conexão WMI remota, consulte a seção Exemplos da página de referência ConnectionOptions.

Exemplo de Microsoft.Management.Infrastructure

O exemplo de código C# a seguir, com base na seguinte postagem de blog no TechNet, descreve como usar CimCredentials e WSManSessionOptions para definir credenciais em uma conexão remota.

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();
         }
     }
 }

Exemplo de System.Management

O exemplo de código C# a seguir descreve uma conexão remota geral, usando os objetos 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"]);
        }
    }
}

Conexão ao WMI em um computador remoto