Usare WMI/CIM da C# e PowerShell — Guida pratica a lettura hardware, monitoraggio processi e interrogazioni remote

· · Windows, C#, .NET, PowerShell, WMI, CIM, Applicazioni aziendali, Sviluppo Windows

«Voglio mostrare numero di serie e modello del PC nella schermata dell’applicazione aziendale.» «Voglio monitorare lo spazio libero su disco del server e lanciare un avviso.» «Voglio rilevare quando parte un processo specifico.» «Voglio interrogare in un colpo solo lo stato dei PC in un altro luogo.» — Nel sviluppo di applicazioni aziendali e strumenti di amministrazione per Windows, richieste di questo tipo sono all’ordine del giorno. E la risposta classica è WMI (Windows Management Instrumentation), o, per dirlo con il nome standard, CIM (Common Information Model).

Richieste tipiche e WMI/CIMLa risposta classica alle richieste tipiche delle applicazioni aziendali — mostrare numero di serie e modello, monitorare lo spazio disco, rilevare l'avvio dei processi, interrogare PC remoti — è WMI, il cui nome standard è CIMNumero di serie e modelloWMI(nome standard: CIM)Monitoraggio spazio discoRilevamento avvio processiInterrogazione PC remoti

Figura 1: WMI/CIM è la risposta classica alle quattro richieste tipiche delle applicazioni aziendali.

La parte scomoda è che le informazioni su WMI mescolano vecchio e nuovo. Cercate e trovate articoli di dieci anni fa con Get-WmiObject accanto ad articoli con Get-CimInstance; sul lato C# convivono due linee, System.Management e Microsoft.Management.Infrastructure. È difficile capire quale sia il modo attuale di scrivere e quale sia «funziona ancora, ma non lo scegliete per il codice nuovo». Di fatto Get-WmiObject in PowerShell 7 non esiste, e il problema affiora di colpo quando migrate uno script interno scritto per 5.1.

Questo articolo è rivolto a sviluppatori C#/PowerShell che implementano, nelle applicazioni aziendali, la lettura delle informazioni hardware, il monitoraggio dei processi e le interrogazioni sui PC remoti. Organizza, a partire da fonti primarie aggiornate ad agosto 2026, dalla comprensione minima della struttura di WMI/CIM fino ai cmdlet CIM di PowerShell, alle due API C#, alle ricette d’uso frequente, alle insidie di prestazioni, privilegi e 64 bit, e al criterio per decidere «quando WMI non va usato».

1. Prima il sodo

  • CIM è lo standard di settore per le informazioni di amministrazione definito dal DMTF, e WMI è l’implementazione Microsoft di quello standard. Le API della famiglia «CIM» in PowerShell e C# sono l’ingresso della generazione attuale allineato a quello standard, e si collegano alla stessa infrastruttura WMI.1
  • In PowerShell la generazione attuale sono i cmdlet CIM (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent). I vecchi cmdlet WMI (Get-WmiObject e altri quattro) sono stati rimossi da PowerShell 6 in poi e in PowerShell 7 non girano.2
  • Lo spazio dei nomi predefinito è root/CIMV2, e le interrogazioni di tutti i giorni consistono sostanzialmente nel filtrare con WQL le classi Win32_* che ci stanno.3
  • Le interrogazioni remote usano WSMan (WinRM) per default. Indicando -ComputerName si crea una sessione WSMan temporanea. Se interrogate lo stesso target più volte, la pratica consolidata per le prestazioni è riutilizzare una sessione CIM (New-CimSession); per i target vecchi su cui non si può configurare WinRM esiste l’opzione di protocollo DCOM.34
  • In C# ci sono due linee: System.Management (ManagementObjectSearcher) e Microsoft.Management.Infrastructure (CimSession). Entrambe sono esclusive di Windows e, sul .NET attuale, si installano da NuGet. Se dovete fare sul serio interrogazioni remote o monitoraggio, l’API MI — che condivide il sistema di tipi dei cmdlet CIM — è la più adatta.56
  • Rilevate l’avvio dei processi con una sottoscrizione a eventi, non con il polling. La sottoscrizione a Win32_ProcessStartTrace va eseguita con privilegi di amministratore.78
  • Non usate SELECT * per abitudine. Restringere i dati trasferiti con -Filter / -Property / -KeyOnly previene circa metà dei problemi di prestazioni di WMI.3
  • WMI non è una soluzione universale. Per il monitoraggio delle prestazioni ad alta frequenza, per leggere e scrivere le impostazioni della vostra applicazione, o per una chiamata puntuale a una funzione del sistema operativo, sono più adatti i contatori di prestazioni, il registro, l’API Win32 o i cmdlet dedicati (tabella di decisione del capitolo 8).

2. Che cos’è WMI/CIM — Standard e implementazione, spazi dei nomi, classi e WQL

Per prima cosa, mettiamo in ordine una volta per tutte i termini.

Termine Che cos’è
CIM (Common Information Model) Il modello standard di settore per rappresentare gli oggetti da amministrare: sistemi, applicazioni, reti, dispositivi. Definito e mantenuto dal DMTF (Distributed Management Task Force)1
WBEM (Web-Based Enterprise Management) Iniziativa di settore per creare le tecnologie standard di accesso alle informazioni di amministrazione negli ambienti aziendali1
WMI Implementazione Microsoft di WBEM. Rappresenta gli oggetti da amministrare usando lo standard CIM ed è incorporata in Windows1
MI (Windows Management Infrastructure) Generazione successiva di WMI. Completamente compatibile con il WMI tradizionale; la maggior parte dei provider nuovi è scritta in MI1
Relazione tra lo standard CIM e l'implementazione WMILo standard CIM definito e mantenuto dal DMTF si usa nel quadro dell'iniziativa WBEM, l'implementazione Microsoft è WMI, la generazione successiva MI è completamente compatibile con il WMI tradizionale, e le API della famiglia CIM si collegano alla stessa infrastruttura WMIDefinito e mantenuto dal DMTFCIM(modello standard di settore)WBEM(iniziativa di settore)WMI(implementazione Microsoft)MI(generazione successiva, compatibile)API CIM(PowerShell / C#)

Figura 2: CIM è la specifica, WMI è l’implementazione su Windows. Le API della famiglia CIM si collegano alla stessa infrastruttura WMI.

Come sviluppatori, i quattro pezzi di struttura da tenere fermi sono questi.

  • Spazio dei nomi (namespace): la gerarchia che raggruppa le classi. Per le interrogazioni di tutti i giorni userete quasi sempre root/CIMV2, che è anche il default dei cmdlet CIM.3 Altri esempi: root\default (il provider del registro, tra gli altri).
  • Classe: un tipo che rappresenta un oggetto da amministrare, come Win32_ComputerSystem (il computer stesso), Win32_LogicalDisk (un’unità logica) o Win32_Process (un processo). Le classi specifiche di Windows che ereditano dalle classi dello standard CIM (come CIM_LogicalDisk) portano il prefisso Win32_.9
  • Provider: il componente che fornisce la sostanza di una classe. Quando lo interrogate, il provider chiede al sistema operativo sul momento e costruisce i valori.
  • WQL: un linguaggio di interrogazione simile a SQL. Come in SELECT Name, State FROM Win32_Service WHERE StartMode = 'Auto', tratta una classe come una tabella e la filtra. È anche il linguaggio di interrogazione predefinito dei cmdlet CIM.3

«Leggere informazioni su sistema operativo e hardware attraverso un insieme unificato di classi e un linguaggio di query» — questo è il valore di WMI. All’inverso, scrittura e operazioni sono limitate al sottoinsieme di classi che hanno metodi invocabili con Invoke-CimMethod; non è un meccanismo che può fare qualsiasi cosa.

Struttura di un'interrogazione WMIL'interrogazione WQL è rivolta alle classi Win32_* nello spazio dei nomi root/CIMV2, il provider che dà sostanza alla classe interroga il sistema operativo sul momento, costruisce i valori e restituisce il risultatoInterrogazione in WQLSpazio dei nomi root/CIMV2Classi Win32_*ProviderInterroga il SO sul momentoRestituisce il risultato

Figura 3: L’interrogazione percorre spazio dei nomi, classe e provider; i valori vengono costruiti sul momento.

3. Uso da PowerShell — I cmdlet CIM sono attuali, i cmdlet WMI sono stati rimossi

3.1. La base: Get-CimInstance

# Per nome di classe (spazio dei nomi predefinito root/CIMV2)
Get-CimInstance -ClassName Win32_OperatingSystem

# Scrivere in -Filter solo il contenuto della clausola WHERE (senza la parola chiave WHERE)
Get-CimInstance -ClassName Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'"

# Recuperare solo le proprietà necessarie, per ridurre il volume trasferito
Get-CimInstance -ClassName Win32_Process -Property Name, ProcessId, CreationDate

# Usare -Query se volete scrivere WQL grezzo
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE 'p%'"

-Filter è esattamente la clausola WHERE di WQL, e -Property restringe le colonne recuperate.3 Il valore di ritorno è un oggetto CimInstance, e le proprietà data (come CreationDate o LastBootUpTime) tornano già convertite in DateTime. A differenza del vecchio Get-WmiObject, l’oggetto recuperato non espone i metodi direttamente, quindi le chiamate ai metodi si fanno passandolo a Invoke-CimMethod.

Chiamata ai metodi di CimInstanceIl CimInstance restituito da Get-CimInstance ha le proprietà data già convertite in DateTime ma non espone metodi direttamente, quindi le chiamate ai metodi si fanno passando l'istanza a Invoke-CimMethodGet-CimInstanceOggetto CimInstanceDate già convertite in DateTimeNon espone metodi direttamenteSi passa a Invoke-CimMethodChiamata al metodo

Figura 4: CimInstance non espone metodi direttamente, quindi le chiamate ai metodi passano da Invoke-CimMethod.

# Chiamare un metodo di istanza: ottenere il proprietario di ciascun processo
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |
    Invoke-CimMethod -MethodName GetOwner

# Chiamare un metodo statico della classe: avviare un processo
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = 'notepad.exe' }

# Ispezionare la definizione della classe (proprietà e metodi)
Get-CimClass -ClassName Win32_Process

3.2. Tabella di migrazione dai vecchi cmdlet WMI

Da PowerShell 6 in poi (incluso l’attuale PowerShell 7) i seguenti cmdlet WMI v1 sono stati rimossi. La stessa funzionalità la offre il modulo CimCmdlets (WMI v2).2

Vecchio (fino a Windows PowerShell 5.1) Attuale (cmdlet CIM) Note
Get-WmiObject Get-CimInstance I concetti -Filter / -Query sono gli stessi
Get-WmiObject -List Get-CimClass Scoprire e ispezionare le definizioni di classe
Invoke-WmiMethod Invoke-CimMethod Gli argomenti si passano come hashtable con -Arguments @{ }
Register-WmiEvent Register-CimIndicationEvent Sottoscrizione a eventi (paragrafo 6.3)
Set-WmiInstance Set-CimInstance Modificare proprietà scrivibili
Remove-WmiObject Remove-CimInstance Eliminare un’istanza

I cmdlet CIM funzionano anche in Windows PowerShell 5.1, quindi tutto ciò che scrivete da ora in poi va scritto sul lato CIM anche se girerà su 5.1 — così non vi resta un costo di migrazione. Per il quadro completo della convivenza e della migrazione tra 5.1 e 7, vedete «Le differenze tra Windows PowerShell 5.1 e PowerShell 7».

Perché scrivere i nuovi script con CIMUno script scritto con i cmdlet WMI gira su 5.1 ma è già stato rimosso da PowerShell 6 in poi quindi in migrazione va riscritto, i cmdlet CIM funzionano anche su 5.1 quindi se i nuovi script sono già sul lato CIM non resta un costo di migrazioneCmdlet WMICmdlet CIMScript nuovo da scrivereCon quale famiglia?Funziona su 5.1Usabile anche su 5.1Rimosso in PowerShell 7Da riscrivere in migrazioneNessun costo di migrazione

Figura 5: Se i nuovi script sono già scritti con i cmdlet CIM, non serve riscriverli in migrazione a PowerShell 7.

4. Interrogazioni remote — Sessioni CIM (WSMan per default) e l’opzione DCOM

Se non indicate un target, i cmdlet CIM si collegano al WMI locale via COM; se indicate -ComputerName, creano una sessione temporanea sul protocollo WSMan (WinRM) per collegarsi. Quando dovete fare più operazioni sullo stesso computer, creare una sessione CIM e riutilizzarla è meglio per le prestazioni.3

Scelta del modo di connessione CIMSenza indicazione si collega via COM al WMI locale, con ComputerName si crea una sessione temporanea WSMan a ogni interrogazione, per più operazioni sullo stesso target riutilizzare New-CimSession è conveniente per le prestazioni, e per un target senza WinRM esiste l'opzione di protocollo DCOMNoUna tantumPiù volteEsecuzione cmdlet CIMComputerName indicato?Connessione COM a WMI localePiù operazioni sullo stesso target?Sessione temporanea WSManRiutilizzare New-CimSessionCreata a ogni interrogazioneTarget senza WinRMOpzione protocollo DCOM

Figura 6: Le interrogazioni remote usano WSMan per default; per più operazioni sullo stesso target si riutilizza una sessione CIM.

# Per un'interrogazione una tantum, usare -ComputerName (si crea una sessione temporanea ogni volta)
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName Server01, Server02

# Per interrogazioni ripetute, riutilizzare una sessione CIM
$session = New-CimSession -ComputerName Server01
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $session
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" -CimSession $session
Remove-CimSession $session

Per i target che non potete raggiungere via WSMan — ad esempio macchine vecchie su cui non si può configurare WinRM — potete scegliere il protocollo DCOM.4

$dcom = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName OldServer -SessionOption $dcom

I prerequisiti di un’interrogazione remota sono i seguenti.

  • WinRM deve essere configurato sul target. winrm quickconfig imposta l’avvio automatico del servizio, crea un listener HTTP (porta predefinita 5985) e registra un’eccezione firewall, tutto in un colpo solo.10 Se volete collegarvi via HTTPS (porta predefinita 5986), questo da solo non basta: dovete preparare un certificato server e configurare a parte un listener HTTPS, ad esempio con winrm quickconfig -transport:https.10
  • Le porte pertinenti devono essere aperte sui firewall del percorso. Il lavoro pratico di progettare e registrare le regole in ingresso è trattato nell’articolo «Il firewall di Windows e le applicazioni aziendali».
  • Autenticazione. In un ambiente di dominio, Kerberos fornisce l’autenticazione reciproca. In un gruppo di lavoro Kerberos non è disponibile, quindi può servire registrare il target in TrustedHosts sul client. Tenete quell’elenco il più stretto possibile.10
  • Privilegi. Nella configurazione predefinita, interrogazioni e operazioni WMI remote si fanno di base con un account che appartiene al gruppo Administrators del target. Per aprirle a utenti standard occorre configurare i permessi sia su WinRM sia sullo spazio dei nomi WMI.10
  • Notate che DCOM non ha una porta di ascolto fissa (usa porte RPC dinamiche), il che rende più difficile progettare attraverso un confine di firewall. Per ciò che costruite da ora in poi è più prudente assumere WSMan come default.
Verifica dei prerequisiti per le interrogazioni remoteSul target winrm quickconfig imposta l'avvio automatico del servizio, crea il listener HTTP e registra l'eccezione firewall in un colpo solo, il listener HTTPS si configura a parte dopo aver preparato un certificato, e in un ambiente di gruppo di lavoro può servire la registrazione in TrustedHostswinrm quickconfigAvvio automatico del servizioCreazione listener HTTP(5985)Eccezione firewallListener HTTPS(5986)Certificato e configurazione a parteAmbiente di gruppo di lavoroRegistrazione in TrustedHosts

Figura 7: winrm quickconfig applica la configurazione predefinita in un colpo solo; listener HTTPS e autenticazione in gruppo di lavoro richiedono passi a parte.

5. Uso da C# — System.Management e Microsoft.Management.Infrastructure

Ci sono due linee di API per usare WMI da C#. Entrambe sono esclusive di Windows.

  System.Management Microsoft.Management.Infrastructure (API MI)
Come si porta Inclusa di default in .NET Framework. Sul .NET attuale, il pacchetto NuGet System.Management5 Il pacchetto NuGet Microsoft.Management.Infrastructure6
Classe di ingresso ManagementObjectSearcher (si passa WQL per interrogare)5 CimSession (Create → QueryInstances / InvokeMethod / Subscribe)6
Sistema di tipi ManagementObject / ManagementEventWatcher11 CimInstance / CimSessiongli stessi tipi dei cmdlet CIM3
Accesso remoto Basato su DCOM Basato su WSMan (sessione CIM). Varianti asincrone (*Async) disponibili6
Meglio adatta a Lettura di informazioni locali. Mantenere codice esistente Incorporare interrogazioni remote e monitoraggio. Progetti che si affiancano a PowerShell

5.1. System.Management: le basi di ManagementObjectSearcher

Passate WQL come stringa e ricevete una collezione di risultati con Get().5

// NuGet: System.Management (esclusivo di Windows)
using System.Management;

using var searcher = new ManagementObjectSearcher(
    @"root\cimv2",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (ManagementObject disk in searcher.Get())
{
    var freeGb = (ulong)disk["FreeSpace"] / 1024.0 / 1024.0 / 1024.0;
    var sizeGb = (ulong)disk["Size"] / 1024.0 / 1024.0 / 1024.0;
    Console.WriteLine($"{disk["DeviceID"]} liberi {freeGb:F1} GB / totale {sizeGb:F1} GB");
}

Le proprietà tornano come object tramite un indicizzatore, quindi dovete verificare nella documentazione della classe il tipo CIM (in questo esempio FreeSpace / Size sono uint649) e fare il cast di conseguenza. Assumere che sia int e fare il cast su quell’ipotesi, ottenendo un InvalidCastException, è il primo inciampo classico.

Insidia di lettura proprietà e castLe proprietà di System.Management tornano come object tramite l'indicizzatore, quindi occorre verificare il tipo CIM nella documentazione della classe e fare il cast, e se si assume int e si fa il cast si ottiene InvalidCastExceptionLettura via indicizzatoreTornano come objectVerifica del tipo CIM in documentazioneCast al tipo correttoCast ipotizzando intInvalidCastException

Figura 8: Le proprietà tornano come object, quindi si verifica il tipo CIM e poi si fa il cast.

5.2. API MI: le basi di CimSession

CimSession tratta locale e remoto nella stessa forma. Copre enumerazione, interrogazione, chiamata di metodi, sottoscrizione a eventi e varianti asincrone, tutto in un posto solo.6

// NuGet: Microsoft.Management.Infrastructure (esclusivo di Windows)
using Microsoft.Management.Infrastructure;

// CimSession.Create(null) per il locale, oppure un nome computer per il remoto
using CimSession session = CimSession.Create(null);

IEnumerable<CimInstance> disks = session.QueryInstances(
    @"root\cimv2", "WQL",
    "SELECT DeviceID, FreeSpace, Size FROM Win32_LogicalDisk WHERE DriveType = 3");

foreach (CimInstance disk in disks)
{
    var deviceId = (string)disk.CimInstanceProperties["DeviceID"].Value;
    var free = (ulong)disk.CimInstanceProperties["FreeSpace"].Value;
    Console.WriteLine($"{deviceId} liberi {free / 1024.0 / 1024 / 1024:F1} GB");
}

Poiché tratta lo stesso CimInstance restituito dai cmdlet CIM di PowerShell, un flusso di sviluppo «provalo prima in PowerShell, poi trascrivilo in C#» si innesta in modo naturale. Se state progettando l’integrazione stessa tra C# e PowerShell, vedete anche «Come eseguire PowerShell da C# (CSharp) e ricevere i risultati come oggetti».

Dal prototipo in PowerShell alla trascrizione in C#I cmdlet CIM di PowerShell e l'API MI di C# trattano lo stesso tipo CimInstance, quindi un flusso di sviluppo che prototipa in PowerShell e poi trascrive in C# si innesta in modo naturalePrototipo in PowerShellCmdlet CIMImplementazione in C#MI APIStesso tipo CimInstanceLa trascrizione è naturale

Figura 9: I cmdlet CIM e l’API MI condividono il tipo CimInstance, quindi dal prototipo si passa in modo naturale all’implementazione.

6. Ricette d’uso frequente

6.1. Tabella rapida delle classi comuni

Informazione che volete Classe Proprietà principali
Produttore / nome modello Win32_ComputerSystem Manufacturer, Model
Numero di serie del telaio Win32_BIOS SerialNumber
Versione del SO / ora di avvio Win32_OperatingSystem Caption, Version, LastBootUpTime
Spazio libero su disco Win32_LogicalDisk DeviceID, FreeSpace, Size, DriveType9
Stato del servizio Win32_Service Name, State, StartMode
Elenco processi Win32_Process Name, ProcessId, CommandLine

6.2. Il classico della gestione asset: numero di serie, nome modello e spazio disco

# Informazioni di modello e numero di serie (per raccordarle al registro asset dei PC)
$cs   = Get-CimInstance -ClassName Win32_ComputerSystem -Property Manufacturer, Model
$bios = Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber
[pscustomobject]@{
    Manufacturer = $cs.Manufacturer
    Model        = $cs.Model
    Serial       = $bios.SerialNumber
}

# Spazio libero sui dischi locali (DriveType = 3)
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType = 3" |
    Select-Object DeviceID,
        @{ Name = 'FreeGB'; Expression = { [math]::Round($_.FreeSpace / 1GB, 1) } },
        @{ Name = 'SizeGB'; Expression = { [math]::Round($_.Size / 1GB, 1) } }

DriveType = 3 è il valore che rappresenta «disco locale», ed esclude rimovibili (2), unità di rete (4) e CD (5).9 Per il monitoraggio, far girare questo script su ciascun server via sessione CIM vi dà già la base di un monitoraggio disco senza agente.

La base del monitoraggio disco senza agenteIl filtro DriveType 3 esclude rimovibili, unità di rete e CD lasciando solo i dischi locali, e far girare lo stesso script su ciascun server via sessione CIM dà la base di un monitoraggio disco senza agenteScript spazio liberoFiltro DriveType = 3Esclude rimovibili, ecc.Via sessione CIMSu ciascun serverMonitoraggio senza agente

Figura 10: La base del monitoraggio è far girare, via sessione CIM, uno script filtrato sui dischi locali su ciascun server.

6.3. Rilevare l’avvio dei processi — sottoscrizione a eventi

Invece di «recuperare periodicamente Win32_Process con il polling e fare il diff», usate una sottoscrizione a eventi. Il modo più semplice per cogliere l’avvio di un processo è sottoscrivere Win32_ProcessStartTrace (una classe di evento del provider di kernel trace, con proprietà come ProcessName / ProcessID / ParentProcessID8).

# Eseguire da una sessione PowerShell con privilegi di amministratore
$action = {
    $name = $Event.SourceEventArgs.NewEvent.ProcessName
    $id   = $Event.SourceEventArgs.NewEvent.ProcessID
    Write-Host "Processo avviato: $name (PID=$id)"
}
Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace `
    -SourceIdentifier ProcessStarted -Action $action

La sottoscrizione resta attiva finché vive la sessione PowerShell che l’ha registrata, e -Action gira ogni volta che parte un processo. Fate attenzione a non eseguire di seguito, nello stesso lotto, anche il comando di rimozione: la sottoscrizione sparirebbe prima ancora che il monitoraggio inizi. Eseguite la rimozione quando terminate il monitoraggio.

# Quando terminate il monitoraggio: rimuovere la sottoscrizione
Unregister-Event -SourceIdentifier ProcessStarted

Register-CimIndicationEvent registra una sottoscrizione per nome di classe o per una query di evento WQL, e il blocco script di -Action gira a ogni arrivo.7 Sottoscrivere questa classe richiede privilegi di amministratore.7 Chi può ricevere l’evento è controllato dal descrittore di sicurezza della classe di evento, e un utente standard senza elevazione riceve un accesso negato.8

Flusso della sottoscrizione all'evento di avvio processoIn una sessione PowerShell con privilegi di amministratore Register-CimIndicationEvent registra la sottoscrizione, a ogni avvio di processo arriva l'evento e si esegue Action, e quando si termina il monitoraggio si rimuove con Unregister-EventWMISessione PowerShellWMISessione PowerShellEsecuzione con privilegi di amministratoreRegistrazione con Register-CimIndicationEventEvento a ogni avvio di processoEsegue -ActionRimozione con Unregister-Event (fine monitoraggio)

Figura 11: La sottoscrizione resta attiva finché vive la sessione che l’ha registrata; la si rimuove quando si termina il monitoraggio.

Un altro metodo è l’evento generico di creazione istanza (__InstanceCreationEvent), utilizzabile con qualsiasi classe. Qui WMI fa polling all’intervallo indicato con WITHIN e trasforma il diff in eventi, quindi il trade-off tra intervallo di rilevamento e carico lo decidete voi.

Due modi di sottoscrizione per rilevare l'avvio dei processiWin32_ProcessStartTrace è il modo che sottoscrive la classe di evento del provider di kernel trace, il generico __InstanceCreationEvent fa sì che WMI faccia polling all'intervallo WITHIN e trasformi il diff in eventi quindi il trade-off tra intervallo di rilevamento e carico lo decidete voiRilevamento avvio processiWin32_ProcessStartTrace__InstanceCreationEventSottoscrizione al kernel tracePolling con intervallo WITHINTrade-off intervallo e carico

Figura 12: Sottoscrivere la classe di evento dedicata, oppure usare l’evento generico di creazione istanza con un intervallo di polling.

# Monitorare nuove istanze di Win32_Process con un polling ogni 5 secondi
$query = "SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'"
Register-CimIndicationEvent -Query $query -SourceIdentifier ProcPoll -Action {
    Write-Host "Avviato: $($Event.SourceEventArgs.NewEvent.TargetInstance.Name)"
}

In C# (System.Management), ManagementEventWatcher svolge lo stesso ruolo.11

using System.Management;

// Da un processo in esecuzione come amministratore
var watcher = new ManagementEventWatcher(
    new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
watcher.EventArrived += (_, e) =>
{
    var name = (string)e.NewEvent["ProcessName"];
    var pid  = (uint)e.NewEvent["ProcessID"];
    Console.WriteLine($"Processo avviato: {name} (PID={pid})");
};
watcher.Start();
// A fine monitoraggio non dimenticate watcher.Stop() e Dispose

Se lo incorporate in un monitoraggio permanente, includete nel progetto anche la ri-registrazione della sottoscrizione quando cade (al riavvio del servizio o in errore). La teoria di progetto di «controllo e visualizzazione dello stato», incluso il monitoraggio dei dispositivi, è trattata in «Best practice per controllare e visualizzare lo stato di dispositivi esterni».

Ciclo di vita della sottoscrizione nel monitoraggio permanenteNel monitoraggio permanente lo stato sottoscritto può cadere per un riavvio del servizio o un errore, quindi il progetto deve includere il rilevamento della caduta, la ri-registrazione e il ritorno allo stato sottoscrittoRiavvio servizio / erroreSottoscrittoSottoscrizione cadutaRi-registrazione

Figura 13: Nel monitoraggio permanente, il progetto deve includere la ri-registrazione per tornare allo stato «sottoscritto» quando la sottoscrizione cade.

7. Insidie — Prestazioni, privilegi, 64 bit, repository e date

7.1. SELECT * e il polling eccessivo

Un’interrogazione WMI è un processo in cui «il provider costruisce i valori sul momento» — non è gratis. Ci sono due antipattern classici.

  • Usare SELECT * per abitudine. Recuperare ogni proprietà di ogni riga di Win32_Process gonfia di conseguenza il lavoro del provider e il trasferimento di rete (quando è remoto). Restringete le righe con -Filter, le colonne con -Property, e usate -KeyOnly se vi servono solo le chiavi per un’operazione successiva. Tutti sono mezzi ufficiali, pensati «per ridurre la dimensione degli oggetti e il traffico di rete».3
  • Polling a ciclo breve. Un progetto come «Get-CimInstance Win32_Process ogni secondo» va sostituito con la sottoscrizione a eventi del paragrafo 6.3. Anche se dovete usare lo stile polling (WITHIN), allargate l’intervallo fino a quello davvero sufficiente per il requisito.

Inoltre, ripetere -ComputerName un target alla volta contro macchine remote è uno spreco: una sessione temporanea viene creata a ogni singola interrogazione. Per più operazioni passate a riutilizzare una sessione CIM.3

Antipattern di prestazioni e dove sostituirliL'uso pigro di SELECT asterisco si sostituisce filtrando righe e colonne con Filter e Property e usando KeyOnly se servono solo le chiavi, il polling a ciclo breve si sostituisce con la sottoscrizione a eventi, e la ripetizione di ComputerName macchina per macchina si sostituisce con il riutilizzo di una sessione CIMUso pigro di SELECT *Filtrare con Filter e PropertySolo chiavi: KeyOnlyPolling a ciclo breveSostituire con sottoscrizione eventiComputerName macchina per macchinaRiutilizzare la sessione CIM

Figura 14: Filtrare righe, colonne e chiavi, e sostituire il polling con la sottoscrizione a eventi, previene metà dei problemi di prestazioni di WMI.

7.2. Privilegi per la sottoscrizione a eventi

Come nel paragrafo 6.3, la sottoscrizione alla famiglia Win32_ProcessStartTrace presuppone privilegi di amministratore.7 «Funzionava sulla macchina di sviluppo (in esecuzione come amministratore), ma il monitoraggio non gira nell’ambiente utente standard del cliente» è un incidente classico, allo stesso livello della finestra di notifica del firewall. Se incorporate il monitoraggio in un’applicazione aziendale che gira come utente standard, considerate di isolare la parte di monitoraggio in un servizio Windows (ad esempio come LocalSystem) e di collegarla all’applicazione principale con comunicazione tra processi.

Configurazione del monitoraggio in un ambiente utente standardLa sottoscrizione che presuppone privilegi di amministratore si stacca dall'applicazione principale che gira come utente standard, isolando la parte di monitoraggio in un servizio Windows eseguito come LocalSystem o simile, e collegandola all'applicazione principale con comunicazione tra processiComunicazione tra processiServizio Windows di monitoraggioSottoscrive il trace di avvioGira come LocalSystem, ecc.App principale(utente standard)

Figura 15: Le sottoscrizioni che richiedono privilegi di amministratore si isolano nel servizio e si collegano all’applicazione principale con comunicazione tra processi.

7.3. 32 bit / 64 bit e i provider

Su Windows a 64 bit alcuni provider esistono sia in versione a 32 bit sia a 64 bit, e per default risponde il lato che coincide con i bit dell’applicazione chiamante.12 Il caso classico è il provider del registro (StdRegProv) sotto root\default: una lettura da un’applicazione a 32 bit restituisce i valori del lato Wow6432Node (la vista a 32 bit).12 Se «il valore di registro letto via WMI non coincide con quello che mostra regedit», sospettate questo per primo. Se vi serve l’altra vista, potete richiederla esplicitamente impostando __ProviderArchitecture (e, se volete forzarla, __RequiredArchitecture) nel contesto di connessione.12 Il quadro complessivo dei problemi di numero di bit è anche in «Chiamare in sicurezza le API Win32 da C# — Guida pratica a P/Invoke».

Scelta del provider in un ambiente a 64 bitPer default risponde il provider i cui bit coincidono con quelli dell'applicazione chiamante, un'interrogazione di registro da un'app a 32 bit riceve il valore del lato Wow6432Node, ma specificando __ProviderArchitecture si può richiedere esplicitamente la vista opposta32bit64bitQuanti bit ha il chiamante?Risponde il provider a 32 bitRisponde il provider a 64 bitIl registro è il lato Wow6432NodeSpecificare __ProviderArchitectureRichiede esplicitamente la vista opposta

Figura 16: Per default risponde il lato che coincide con i bit del chiamante, quindi un’app a 32 bit legge il lato Wow6432Node.

7.4. Sintomi e rimedi quando il repository WMI è corrotto

Le definizioni di classe di WMI sono memorizzate in un repository (non un singolo file: i file dentro la cartella Repository funzionano insieme come database13). Quando diventa incoerente, iniziano a comparire errori del tipo «una classe che dovrebbe esistere non si trova» o «lo spazio dei nomi non è valido», anche se sul lato applicazione non è cambiato nulla. Per diagnosticare e riparare si usa winmgmt.exe.13

rem Controllo di coerenza (il risultato "inconsistent" significa che c'è un problema)
winmgmt /verifyrepository

rem Controllo di coerenza e, se c'è un problema, ricostruzione (il contenuto leggibile viene unito)
winmgmt /salvagerepository

L’importante è non fare della cancellazione o del reset del repository la prima mossa. Gli errori che affiorano via WMI possono originare altrove nel sistema operativo, e Microsoft stessa afferma chiaramente che cancellare il repository come prima risposta «può causare danni al sistema o alle applicazioni installate».13 Rispettate l’ordine: controllo con /verifyrepository, poi riparazione con /salvagerepository.

Procedura di diagnosi per un'incoerenza del repository WMISe compaiono errori tipo classe non trovata si verifica la coerenza con winmgmt verifyrepository, se c'è incoerenza si ricostruisce con salvagerepository, e non si parte dalla cancellazione o dal reset del repositoryNoErrori tipo classe non trovatawinmgmt /verifyrepositoryRisultato inconsistent?winmgmt /salvagerepositorySospettare un'altra parte del SOIl contenuto leggibile viene unitoCancellazione o reset del repositoryNon come primo passo

Figura 17: Rispettate l’ordine verify poi salvage; non partite dalla cancellazione del repository.

7.5. Conversione del formato data DMTF

Le date WMI sono memorizzate come stringhe nel formato DMTF definito dalla specifica CIM: yyyymmddHHMMSS.mmmmmm±UUU (il valore in coda è l’offset da UTC in minuti — ad esempio 20260801100000.000000+540). Non tagliate e ricucite il valore grezzo con elaborazione di stringhe: usate l’API di conversione.

  • C# (System.Management): ManagementDateTimeConverter offre la conversione reciproca tra il formato DMTF e DateTime / TimeSpan.11
  • API della famiglia CIM (Get-CimInstance / API MI): le proprietà data tornano già convertite in DateTime, quindi questo problema non si presenta affatto. (Get-CimInstance Win32_OperatingSystem).LastBootUpTime si può usare direttamente come DateTime nei calcoli.
Trattamento del formato data DMTFLe date WMI sono memorizzate come stringhe in formato DMTF, se si legge il valore grezzo con System.Management si converte con ManagementDateTimeConverter, con un'API della famiglia CIM torna già convertito in DateTime, quindi non si taglia e ricuce la stringa a manoSystem.ManagementAPI della famiglia CIMStringa in formato DMTFCon quale API si ottiene?ManagementDateTimeConverterGià convertito in DateTimeConversione in DateTime / TimeSpanTaglia-e-incolla della stringaNon si usa

Figura 18: Lasciate la conversione della stringa DMTF all’API di conversione; con le API CIM usate direttamente il DateTime già convertito.

8. Situazioni in cui WMI non va usato — Una tabella di decisione

WMI è eccellente come «interfaccia di lettura unificata», ma non è sempre la scelta ottimale. Ecco una regola pratica per scegliere tra gli strumenti.

Cosa volete fare Lo strumento giusto Perché non WMI
Lettura di informazioni hardware e configurazione del SO, interrogazioni remote senza agente WMI/CIM Questo è il terreno naturale di WMI — più unificato che colpire una per una le API dedicate
Lettura e scrittura delle impostazioni della vostra applicazione Lettura diretta del registro (Microsoft.Win32.Registry) o file di configurazione L’accesso al registro via WMI è una via indiretta, e si porta dietro anche il problema di numero di bit del paragrafo 7.3
Monitoraggio delle prestazioni ad alta frequenza e continuo, come l’uso della CPU Contatori di prestazioni (System.Diagnostics.PerformanceCounter, ecc.) I contatori esistono proprio per questo. Il polling WMI a ciclo breve perde sia in carico sia in precisione
Una chiamata puntuale a una funzione del SO, o un’elaborazione che ha bisogno di bassa latenza L’API Win32 (P/Invoke) WMI porta l’overhead di passare da COM/un provider
Enumerare e manovrare processi locali quando bastano i privilegi del proprio processo System.Diagnostics.Process Si chiude nella libreria standard, con meno dipendenze
Configurare funzioni di amministrazione Windows come firewall o rete Cmdlet dedicati basati su CIM come Get-NetFirewallRule Un insieme di cmdlet costruito e mantenuto per uno scopo specifico è più accurato e più sicuro che cacciare classi WMI grezze
Rilevare modifiche a file o cartelle FileSystemWatcher Non portate WMI in un territorio che ha già un’API dedicata

L’asse di decisione è semplice: usate il meccanismo dedicato dove esiste, e riservate WMI/CIM alle interrogazioni trasversali e remote. L’esempio Get-NetFirewallRule dell’ultima riga è, internamente, un insieme di cmdlet costruito sopra CIM — un caso di «ottenere il beneficio di WMI/CIM senza toccarlo direttamente».

L'asse di decisione sugli strumentiL'asse di decisione è usare il meccanismo dedicato nelle aree in cui esiste, e usare WMI e CIM per le interrogazioni trasversali o remote nelle aree in cui non c'è, i cmdlet dedicati basati su CIM sono una forma di ottenere solo i benefici senza toccare WMI e CIM direttamenteNoEsiste un meccanismo dedicato?Usare il meccanismo dedicatoUsare WMI / CIMInterrogazioni trasversali e remoteCmdlet dedicati basati su CIMSolo i benefici, senza toccarli

Figura 19: Dove esiste un meccanismo dedicato, usatelo; per interrogazioni trasversali e remote usate WMI/CIM.

  • CIM è lo standard di settore del DMTF, e WMI è l’implementazione Microsoft. Sia i cmdlet CIM di PowerShell sia l’API MI di C# sono ingressi della generazione attuale allineati a quello standard.
  • In PowerShell sono attuali Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent. Get-WmiObject e gli altri cmdlet WMI non esistono in PowerShell 7, quindi gli script nuovi si scrivono sul lato CIM anche se puntano a 5.1.
  • Le interrogazioni remote usano WSMan (WinRM) per default, e più operazioni riutilizzano una sessione CIM. Per un target senza WinRM configurato, DCOM è una via di uscita disponibile.
  • In C# si sceglie tra System.Management (comoda, orientata al locale) e Microsoft.Management.Infrastructure (orientata al remoto e al monitoraggio, con lo stesso sistema di tipi dei cmdlet CIM). Entrambe sono pacchetti NuGet esclusivi di Windows.
  • Monitorate i processi con la sottoscrizione a eventi, non con il polling. La sottoscrizione a Win32_ProcessStartTrace richiede privilegi di amministratore.
  • Evitate SELECT * e il polling a ciclo breve: restringete con -Filter / -Property / -KeyOnly. Ricordate che un’interrogazione da un processo a 32 bit è servita dal provider a 32 bit, che le date DMTF vanno trattate con l’API di conversione, e che un repository corrotto si affronta nell’ordine verify → salvage, non con la cancellazione.
  • Non portate WMI nei territori che hanno già un meccanismo dedicato (impostazioni, contatori di prestazioni, chiamate API puntuali): riservate WMI/CIM alle interrogazioni trasversali e remote. Quella riga sola riassume dove sta il suo posto.

Articoli correlati

Aree di consulenza correlate

KomuraSoft LLC si occupa di incorporare in applicazioni aziendali la lettura delle informazioni hardware, il monitoraggio dei processi e le interrogazioni sui PC remoti con WMI/CIM, di migrare gli script interni basati su Get-WmiObject ai cmdlet CIM, e di indagare il tipo di problema in cui «funziona sulla macchina di sviluppo ma in sede cliente fallisce con un errore di privilegi». Possiamo accompagnarvi sull’intero percorso, dal prototipo in PowerShell all’implementazione in C#.

Riferimenti

  1. Microsoft Learn, About WMI. Sul fatto che WMI è l’implementazione Microsoft di WBEM (un’iniziativa di settore per sviluppare tecnologie standard di accesso alle informazioni di amministrazione negli ambienti aziendali), che rappresenta gli oggetti da amministrare usando lo standard di settore CIM (Common Information Model), sviluppato e mantenuto dal DMTF (Distributed Management Task Force); sul fatto che la generazione successiva MI (Windows Management Infrastructure) è completamente compatibile con il WMI tradizionale; e sul fatto che le connessioni WMI remote usano DCOM, con WinRM basato su WS-Management come alternativa.  2 3 4 5

  2. Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. Sul fatto che i cmdlet WMI v1 (Register-WmiEvent / Set-WmiInstance / Invoke-WmiMethod / Get-WmiObject / Remove-WmiObject) sono stati rimossi da PowerShell, e sul fatto che i cmdlet del modulo CimCmdlets (WMI v2) offrono la stessa funzionalità con nuove caratteristiche e una sintassi riprogettata.  2

  3. Microsoft Learn, Get-CimInstance (CimCmdlets). Sul collegarsi al WMI locale con una sessione COM quando non si indicano né ComputerName né CimSession, e sul creare una sessione temporanea sul protocollo WsMan quando si indica -ComputerName; sul fatto che collegarsi via sessione CIM è raccomandato per le prestazioni quando si fanno più operazioni sullo stesso computer; sul fatto che -Filter è una clausola where WQL/CQL che non include la parola chiave WHERE; sul fatto che -Property e -KeyOnly riducono la dimensione degli oggetti e il traffico di rete; sul fatto che lo spazio dei nomi predefinito è root/CIMV2 e il linguaggio di interrogazione predefinito (-QueryDialect) è WQL; sul fatto che l’output è Microsoft.Management.Infrastructure.CimInstance; su un esempio di chiamata a GetOwner in combinazione con Invoke-CimMethod; e sul fatto che il cmdlet è esclusivo di Windows.  2 3 4 5 6 7 8 9 10

  4. Microsoft Learn, New-CimSessionOption (CimCmdlets). Sul fatto che le opzioni di sessione CIM hanno due insiemi di parametri, per WsMan e per DCOM; sul fatto che -Protocol accetta Dcom / Default / Wsman; su un esempio di passaggio di un’opzione creata con New-CimSessionOption -Protocol Dcom a -SessionOption di New-CimSession per creare una sessione CIM DCOM; e sul fatto che il livello di impersonation predefinito di una sessione DCOM è Impersonate.  2

  5. Microsoft Learn, ManagementObjectSearcher Class (System.Management). Sul fatto che è la classe di ingresso più comune per recuperare informazioni di amministrazione, recuperando una collezione di oggetti di amministrazione in base a una query WQL indicata; sul fatto che accetta un ObjectQuery e un ManagementScope (lo spazio dei nomi WMI) e restituisce un ManagementObjectCollection via Get(); e sul fatto che System.Management.dll è fornito come pacchetto NuGet System.Management.  2 3 4

  6. Microsoft Learn, CimSession Class (Microsoft.Management.Infrastructure). Sul fatto che Microsoft.Management.Infrastructure.dll è fornito come pacchetto NuGet Microsoft.Management.Infrastructure; sulla creazione di una sessione via Create(computerName); sull’esecuzione di una query via QueryInstances(namespace, queryDialect, query); e sul fatto che offre EnumerateInstances / GetInstance / InvokeMethod / Subscribe insieme alle varianti asincrone (*Async) di ciascuno, implementando IDisposable.  2 3 4 5

  7. Microsoft Learn, Register-CimIndicationEvent (CimCmdlets). Sul sottoscrivere un’indicazione (evento) per nome di classe o espressione di query e nominare la sottoscrizione con -SourceIdentifier; su un esempio di sottoscrizione a Win32_ProcessStartTrace, con la nota che richiede di eseguire PowerShell come amministratore; su un esempio di riferimento a ProcessName / ProcessId da $Event.SourceEventArgs.NewEvent nel blocco script di -Action; sul collegarsi via sessione temporanea WsMan quando si indica -ComputerName, e in locale via COM quando non lo si indica; e sull’uso di Unregister-Event per rimuovere una sottoscrizione.  2 3 4

  8. Microsoft Learn, Win32_ProcessStartTrace class. Sul fatto che è una classe di evento che indica l’avvio di un nuovo processo, con proprietà tra cui ProcessName / ProcessID / ParentProcessID / SessionID / Sid; sul fatto che la proprietà SECURITY_DESCRIPTOR è il descrittore che il provider dell’evento usa per decidere quali utenti possono riceverlo; e sul fatto che lo spazio dei nomi è Root\CIMV2, fornito dal provider di kernel trace (Krnlprov.dll).  2 3

  9. Microsoft Learn, Win32_LogicalDisk class. Sul fatto che Win32_LogicalDisk è una classe derivata da CIM_LogicalDisk che rappresenta un dispositivo di archiviazione locale; sui valori di DriveType (2 = rimovibile, 3 = disco locale, 4 = unità di rete, 5 = CD, e così via); sul fatto che FreeSpace / Size sono valori uint64 in byte; sul fatto che DeviceID è la chiave; e su esempi di query VBScript / C# che filtrano per DriveType = 3.  2 3 4

  10. Microsoft Learn, Installation and configuration for Windows Remote Management. Sul fatto che un listener WinRM non è configurato per default, quindi i messaggi WS-Management non possono essere inviati o ricevuti; sul fatto che winrm quickconfig imposta l’avvio automatico del servizio, configura un listener HTTP/HTTPS e registra un’eccezione firewall; sul fatto che le porte predefinite di WinRM 2.0 sono HTTP 5985 / HTTPS 5986; sull’impostare TrustedHosts il più stretto possibile quando non si può stabilire l’autenticazione reciproca (Kerberos), ad esempio in un gruppo di lavoro; e sul descrittore di sicurezza predefinito (RootSDDL) che controlla l’accesso remoto al listener, più la configurazione aggiuntiva richiesta per consentire agli utenti non amministratori di usare i plug-in WMI.  2 3 4

  11. Microsoft Learn, System.Management Namespace. Sul fatto che è lo spazio dei nomi che interroga l’infrastruttura WMI tramite le classi della famiglia ManagementObjectSearcher, e gestisce la sottoscrizione a eventi tramite ManagementEventWatcher; sul fatto che WqlEventQuery rappresenta una query di evento in forma WQL; e sul fatto che ManagementDateTimeConverter offre metodi per convertire tra le rappresentazioni DMTF di data/ora e intervallo di tempo e DateTime / TimeSpan del CLR.  2 3

  12. Microsoft Learn, Requesting WMI Data on a 64-bit Platform. Sul fatto che, dove un provider esiste sia in versione a 32 bit sia a 64 bit, per default il provider a 32 bit risponde alle applicazioni a 32 bit (inclusi gli script) e il provider a 64 bit alle applicazioni a 64 bit; sul poter richiedere o forzare la versione non predefinita del provider tramite __ProviderArchitecture (32 o 64) e __RequiredArchitecture del contesto (con WBEM_E_PROVIDER_LOAD_FAILURE se si forza una versione assente); e sull’esempio del provider del registro in cui un client a 32 bit riceve i dati dal lato HKLM\SOFTWARE\Wow6432Node.  2 3

  13. Microsoft Learn, winmgmt. Sul fatto che /verifyrepository di winmgmt.exe esegue un controllo di coerenza del repository WMI; sul fatto che /salvagerepository esegue un controllo di coerenza e, se rileva incoerenza, ricostruisce il repository unendo il contenuto che si è potuto leggere; sul fatto che /resetrepository ripristina il repository allo stato dell’installazione iniziale del sistema operativo; sul fatto che il repository funziona come database composto dai file dentro la cartella Repository; e sul fatto che gli errori emersi via WMI a volte originano altrove nel sistema operativo, per cui cancellare il repository come prima risposta va evitato perché può causare danni al sistema o alle applicazioni installate.  2 3

Articoli recenti con gli stessi tag per approfondire argomenti vicini.

Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.

L’articolo è direttamente collegato ai servizi seguenti.

Domande frequenti

Domande che ricorrono nelle consulenze sull’argomento dell’articolo.

Che differenza c'è tra WMI e CIM?
CIM è il «modello standard di settore per rappresentare gli oggetti da amministrare, come sistemi e dispositivi», definito e mantenuto dal DMTF (Distributed Management Task Force). WMI è l'implementazione Microsoft di WBEM, l'iniziativa che usa quello standard, ed è incorporata in Windows. In altre parole, CIM è la specifica e WMI è l'implementazione su Windows. Get-CimInstance in PowerShell e Microsoft.Management.Infrastructure in C# si chiamano «CIM» perché sono API allineate a quello standard, ma il punto di connessione resta la stessa infrastruttura WMI. Per lo sviluppo quotidiano basta capirlo così: «si interrogano le classi WMI (Win32_* e simili) tramite le API della famiglia CIM».
Get-WmiObject non si può più usare?
In Windows PowerShell 5.1 funziona ancora, ma da PowerShell 6 in poi (incluso l'attuale PowerShell 7) i cmdlet WMI v1 — Get-WmiObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance e Remove-WmiObject — sono stati rimossi e non si possono eseguire. La stessa funzionalità la offre il modulo CimCmdlets (Get-CimInstance / Invoke-CimMethod / Register-CimIndicationEvent e così via). Per gli script nuovi è più sicuro scriverli con i cmdlet CIM anche se gireranno su 5.1. Così, quando passerete a PowerShell 7, non dovrete riscrivere la parte WMI.
Per usare WMI da C# conviene System.Management o Microsoft.Management.Infrastructure?
Entrambe sono esclusive di Windows e, dal .NET attuale, si portano come pacchetti NuGet. System.Management è l'API classica: basta passare WQL a un ManagementObjectSearcher, ed è sufficiente se il lavoro principale è leggere informazioni locali. Include anche ManagementDateTimeConverter, che converte le date DMTF. Microsoft.Management.Infrastructure (l'API MI), invece, condivide lo stesso sistema di tipi dei cmdlet CIM di PowerShell (CimSession / CimInstance) e gestisce in modo coerente interrogazioni remote su WSMan, varianti asincrone dei metodi e sottoscrizione a eventi (Subscribe). Se dovete incorporare sul serio interrogazioni e monitoraggio di PC remoti, la scelta ragionevole è l'API MI.
Get-CimInstance non si collega a un PC remoto. Cosa devo controllare?
Per prima cosa verificate se WinRM è configurato sulla macchina di destinazione. Un'operazione CIM con -ComputerName crea una sessione temporanea sul protocollo WSMan (WinRM), quindi presuppone che il servizio WinRM e un listener siano attivi sul target. winrm quickconfig applica la configurazione predefinita (avvio del servizio, creazione del listener, eccezione firewall). Le porte predefinite sono 5985 per HTTP e 5986 per HTTPS, quindi controllate anche i firewall sul percorso. In un ambiente di gruppo di lavoro l'autenticazione reciproca Kerberos non è disponibile, e può servire registrare il target in TrustedHosts sul client. Se proprio non potete configurare WinRM sul destinatario, potete collegarvi via DCOM con un'opzione creata da New-CimSessionOption -Protocol Dcom.
Perché una data WMI torna in un formato come «20260801100000.000000+540»?
Le date WMI sono memorizzate nel formato stringa definito dalla specifica CIM del DMTF (yyyymmddHHMMSS.mmmmmm±UUU, dove il suffisso è l'offset da UTC in minuti). Se leggete il valore grezzo con il vecchio Get-WmiObject o con System.Management, ottenete questa stringa così com'è. In C# (System.Management), ManagementDateTimeConverter offre metodi di conversione tra il formato DMTF e DateTime / TimeSpan: usate quelli invece di tagliare la stringa a mano. Con un'API della famiglia CIM come Get-CimInstance le proprietà data tornano già convertite in DateTime, quindi questo problema non si presenta affatto.

Profilo dell’autore

Pagina di presentazione dell’autore dell’articolo.

Go Komura

Rappresentante di KomuraSoft LLC

Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.

Torna al blog