Connessione a WMI in modalità remota con C #

Come per altri linguaggi, ad esempio PowerShell, VBScript o C++, è possibile usare C# per monitorare in remoto l'hardware e il software nei computer remoti. Le connessioni remote per il codice gestito vengono eseguite tramite lo spazio dei nomi Microsoft.Management.Infrastructure . Nelle versioni precedenti di WMI è stato usato lo spazio dei nomi System.Management , incluso qui per completezza.

Nota

System.Management era lo spazio dei nomi .NET originale usato per accedere a WMI; Tuttavia, le API in questo spazio dei nomi sono in genere più lente e non vengono ridimensionate anche rispetto alle controparti Microsoft.Management.Infrastructure più moderne.

 

La connessione remota tramite classi nello spazio dei nomi Microsoft.Management.Infrastructure usa DCOM come meccanismo remoto sottostante. Le connessioni remote WMI devono soddisfare i requisiti di sicurezza DCOM per la rappresentazione e l'autenticazione. Per impostazione predefinita, un ambito è associato al computer locale e allo spazio dei nomi di sistema "Root\CIMv2". È tuttavia possibile modificare sia il computer, il dominio che lo spazio dei nomi WMI a cui si accede. È anche possibile impostare autorità, rappresentazione, credenziali e altre opzioni di connessione.

Per connettersi a WMI in remoto con C# (Microsoft.Management.Infrastructure)

  1. Creare una sessione nel computer remoto con una chiamata a CimSession.Create.

    Se ci si connette a un computer remoto usando le stesse credenziali (dominio e nome utente) con cui si è connessi, è possibile specificare il nome del computer nella chiamata Crea . Dopo aver restituito l'oggetto CimSession , è possibile eseguire la query 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);
    

    Per altre informazioni sull'esecuzione di query WMI con l'API Microsoft.Management.Infrastructure in C#, vedere Recupero di dati di istanza o classe WMI.

  2. Se si desidera impostare opzioni diverse per la connessione, ad esempio credenziali, impostazioni locali o livelli di rappresentazione diversi, è necessario usare un oggetto CimSessionOptions nella chiamata a CimSession.Create.

    CimSessionOptions è una classe base per WSManSessionOptions e DComSessionOptions. È possibile usare entrambi per impostare le opzioni rispettivamente nelle sessioni WS-Man e DCOM. Nell'esempio di codice seguente viene descritto l'utilizzo di un oggetto DComSessionOptions per impostare il livello di rappresentazione su Impersonate.

    string computer = "Computer_B"
    DComSessionOptions DComOptions = new DComSessionOptions();
    DComOptions.Impersonation = ImpersonationType.Impersonate;
    
    CimSession Session = CimSession.Create(computer, DComOptions);
    
  3. Se si desidera impostare le credenziali per la connessione, sarà necessario creare e aggiungere un oggetto CimCredentials all'oggetto CimSessionOptions.

    L'esempio di codice seguente descrive la creazione di una classe WSManSessionOptions , la compilazione con l'oggetto CimSessionOptions appropriato e l'uso in una chiamata 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);
    

    È in genere consigliabile non impostare come hardcoded una password nelle applicazioni; come indicato nell'esempio di codice precedente, quando possibile provare a eseguire una query sull'utente per la password e archiviarla in modo sicuro.

WMI è stato progettato per monitorare i componenti hardware e software dei computer remoti. Le connessioni remote per WMI v1 vengono eseguite tramite l'oggetto ManagementScope .

Per connettersi a WMI in remoto con C# (System.Management)

  1. Creare un oggetto ManagementScope usando il nome del computer e il percorso WMI e connettersi alla destinazione con una chiamata a ManagementScope.Connect().

    Se ci si connette a un computer remoto usando le stesse credenziali (dominio e nome utente) con cui si è connessi, è necessario specificare solo il percorso WMI. Dopo aver stabilito la connessione, è possibile eseguire la query 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);
    

    Per altre informazioni sull'esecuzione di query WMI con l'API System.Management in C#, vedere Recupero di dati di istanza o classe WMI.

  2. Se ci si connette a un computer remoto in un dominio diverso o si usa un nome utente e una password diversi, è necessario utilizzare un oggetto ConnectionOptions nella chiamata a ManagementScope.

    ConnectionOptions contiene le proprietà per descrivere le opzioni di autenticazione, rappresentazione, nome utente, password e altre opzioni di connessione. Nell'esempio di codice seguente viene descritto l'uso di connectionOptions per impostare Il livello di rappresentazione su Impersonate.

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

    In generale, è consigliabile impostare il livello di rappresentazione su Impersonate, a meno che non sia necessario in modo esplicito. Provare inoltre a evitare di scrivere il nome e la password nel codice C#. Se possibile, verificare se è possibile eseguire una query sull'utente per fornirle in modo dinamico in fase di esecuzione.

    Per altri esempi di impostazione di proprietà diverse in una connessione WMI remota, vedere la sezione Esempi della pagina di riferimento ConnectionOptions .

Esempio di Microsoft.Management.Infrastructure

L'esempio di codice C# seguente, basato sul post di blog seguente in TechNet, descrive come usare CimCredentials e WSManSessionOptions per impostare le credenziali in una connessione 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();
         }
     }
 }

Esempio di System.Management

L'esempio di codice C# seguente descrive una connessione remota generale, usando gli oggetti 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"]);
        }
    }
}

Connessione a WMI in un computer remoto