Usare WMI/CIM da C# e PowerShell — Guida pratica a lettura hardware, monitoraggio processi e interrogazioni remote
· Go Komura · 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).
flowchart TB
accTitle: Richieste tipiche e WMI/CIM
accDescr: La 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 è CIM
r1["Numero di serie e modello"] --> ans["WMI(nome standard: CIM)"]
r2["Monitoraggio spazio disco"] --> ans
r3["Rilevamento avvio processi"] --> ans
r4["Interrogazione PC remoti"] --> ans
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
-ComputerNamesi 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_ProcessStartTraceva eseguita con privilegi di amministratore.78 - Non usate
SELECT *per abitudine. Restringere i dati trasferiti con-Filter/-Property/-KeyOnlypreviene 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 |
flowchart TB
accTitle: Relazione tra lo standard CIM e l'implementazione WMI
accDescr: Lo 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 WMI
dmtf["Definito e mantenuto dal DMTF"] --> cim["CIM(modello standard di settore)"]
wbem["WBEM(iniziativa di settore)"] --> wmi["WMI(implementazione Microsoft)"]
cim --> wmi
wmi -.-> mi["MI(generazione successiva, compatibile)"]
api["API CIM(PowerShell / C#)"] --> wmi
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) oWin32_Process(un processo). Le classi specifiche di Windows che ereditano dalle classi dello standard CIM (comeCIM_LogicalDisk) portano il prefissoWin32_.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.
flowchart TB
accTitle: Struttura di un'interrogazione WMI
accDescr: L'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 risultato
wql["Interrogazione in WQL"] --> ns["Spazio dei nomi root/CIMV2"]
ns --> cls["Classi Win32_*"]
cls --> prov["Provider"]
prov --> osq["Interroga il SO sul momento"]
osq --> res["Restituisce 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.
flowchart TB
accTitle: Chiamata ai metodi di CimInstance
accDescr: Il 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-CimMethod
gci["Get-CimInstance"] --> inst["Oggetto CimInstance"]
inst -.-> dt["Date già convertite in DateTime"]
inst -.-> nom["Non espone metodi direttamente"]
inst --> icm["Si passa a Invoke-CimMethod"]
icm --> call["Chiamata 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».
flowchart TB
accTitle: Perché scrivere i nuovi script con CIM
accDescr: Uno 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 migrazione
new["Script nuovo da scrivere"] --> q1{"Con quale famiglia?"}
q1 -->|Cmdlet WMI| old["Funziona su 5.1"]
q1 -->|Cmdlet CIM| cur["Usabile anche su 5.1"]
old --> del["Rimosso in PowerShell 7"]
del --> rew["Da riscrivere in migrazione"]
cur --> norew["Nessun 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
flowchart TB
accTitle: Scelta del modo di connessione CIM
accDescr: Senza 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 DCOM
exec["Esecuzione cmdlet CIM"] --> q1{"ComputerName indicato?"}
q1 -->|No| local["Connessione COM a WMI locale"]
q1 -->|Sì| q2{"Più operazioni sullo stesso target?"}
q2 -->|Una tantum| temp["Sessione temporanea WSMan"]
q2 -->|Più volte| sess["Riutilizzare New-CimSession"]
temp -.-> cost["Creata a ogni interrogazione"]
nowinrm["Target senza WinRM"] -.-> dcom["Opzione 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 quickconfigimposta 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 conwinrm 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
TrustedHostssul 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.
flowchart TB
accTitle: Verifica dei prerequisiti per le interrogazioni remote
accDescr: Sul 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 TrustedHosts
qc["winrm quickconfig"] --> svc["Avvio automatico del servizio"]
qc --> lis["Creazione listener HTTP(5985)"]
qc --> fw["Eccezione firewall"]
lis ~~~ https["Listener HTTPS(5986)"]
https -.-> cert["Certificato e configurazione a parte"]
fw ~~~ wg["Ambiente di gruppo di lavoro"]
wg -.-> th["Registrazione 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 / CimSession — gli 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.
flowchart TB
accTitle: Insidia di lettura proprietà e cast
accDescr: Le 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 InvalidCastException
idx["Lettura via indicizzatore"] --> obj["Tornano come object"]
obj --> chk["Verifica del tipo CIM in documentazione"]
chk --> cast["Cast al tipo corretto"]
obj -.-> wrong["Cast ipotizzando int"]
wrong -.-> ex["InvalidCastException"]
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».
flowchart TB
accTitle: Dal prototipo in PowerShell alla trascrizione in C#
accDescr: 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 naturale
trial["Prototipo in PowerShell"] --> gci["Cmdlet CIM"]
impl["Implementazione in C#"] --> mi["MI API"]
gci --> ci["Stesso tipo CimInstance"]
mi --> ci
ci -.-> flow["La 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.
flowchart TB
accTitle: La base del monitoraggio disco senza agente
accDescr: Il 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 agente
scr["Script spazio libero"] --> flt["Filtro DriveType = 3"]
flt -.-> exc["Esclude rimovibili, ecc."]
scr --> ses["Via sessione CIM"]
ses --> srvs["Su ciascun server"]
srvs --> mon["Monitoraggio 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
sequenceDiagram
accTitle: Flusso della sottoscrizione all'evento di avvio processo
accDescr: In 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-Event
participant ps as Sessione PowerShell
participant wmi as WMI
ps->>wmi: Registrazione con Register-CimIndicationEvent
Note over ps: Esecuzione con privilegi di amministratore
wmi-->>ps: Evento a ogni avvio di processo
ps->>ps: Esegue -Action
ps->>wmi: Rimozione 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.
flowchart TB
accTitle: Due modi di sottoscrizione per rilevare l'avvio dei processi
accDescr: Win32_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 voi
goal["Rilevamento avvio processi"] --> t1["Win32_ProcessStartTrace"]
goal --> t2["__InstanceCreationEvent"]
t1 -.-> k1["Sottoscrizione al kernel trace"]
t2 -.-> w1["Polling con intervallo WITHIN"]
w1 -.-> tr["Trade-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».
stateDiagram-v2
accTitle: Ciclo di vita della sottoscrizione nel monitoraggio permanente
accDescr: Nel 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 sottoscritto
s1: Sottoscritto
s2: Sottoscrizione caduta
s3: Ri-registrazione
[*] --> s1
s1 --> s2: Riavvio servizio / errore
s2 --> s3
s3 --> s1
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 diWin32_Processgonfia di conseguenza il lavoro del provider e il trasferimento di rete (quando è remoto). Restringete le righe con-Filter, le colonne con-Property, e usate-KeyOnlyse 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_Processogni 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
flowchart TB
accTitle: Antipattern di prestazioni e dove sostituirli
accDescr: L'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 CIM
a1["Uso pigro di SELECT *"] --> f1["Filtrare con Filter e Property"]
f1 -.-> f2["Solo chiavi: KeyOnly"]
a2["Polling a ciclo breve"] --> f3["Sostituire con sottoscrizione eventi"]
a3["ComputerName macchina per macchina"] --> f4["Riutilizzare 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.
flowchart TB
accTitle: Configurazione del monitoraggio in un ambiente utente standard
accDescr: La 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 processi
svcm["Servizio Windows di monitoraggio"] --> subm["Sottoscrive il trace di avvio"]
svcm -.-> lsm["Gira come LocalSystem, ecc."]
appm["App principale(utente standard)"] ---|Comunicazione tra processi| svcm
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».
flowchart TB
accTitle: Scelta del provider in un ambiente a 64 bit
accDescr: Per 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 opposta
q1{"Quanti bit ha il chiamante?"} -->|32bit| p32["Risponde il provider a 32 bit"]
q1 -->|64bit| p64["Risponde il provider a 64 bit"]
p32 -.-> wow["Il registro è il lato Wow6432Node"]
ctx["Specificare __ProviderArchitecture"] -.-> ov["Richiede 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.
flowchart TB
accTitle: Procedura di diagnosi per un'incoerenza del repository WMI
accDescr: Se 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 repository
sym["Errori tipo classe non trovata"] --> verify["winmgmt /verifyrepository"]
verify --> q1{"Risultato inconsistent?"}
q1 -->|Sì| salvage["winmgmt /salvagerepository"]
q1 -->|No| other["Sospettare un'altra parte del SO"]
salvage -.-> merge["Il contenuto leggibile viene unito"]
del["Cancellazione o reset del repository"] -.-> ng["Non 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):
ManagementDateTimeConverteroffre la conversione reciproca tra il formato DMTF eDateTime/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).LastBootUpTimesi può usare direttamente comeDateTimenei calcoli.
flowchart TB
accTitle: Trattamento del formato data DMTF
accDescr: Le 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 mano
dmtf["Stringa in formato DMTF"] --> q1{"Con quale API si ottiene?"}
q1 -->|System.Management| conv["ManagementDateTimeConverter"]
q1 -->|API della famiglia CIM| done["Già convertito in DateTime"]
conv --> dtv["Conversione in DateTime / TimeSpan"]
cut["Taglia-e-incolla della stringa"] -.-> ng["Non 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».
flowchart TB
accTitle: L'asse di decisione sugli strumenti
accDescr: L'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 direttamente
q1{"Esiste un meccanismo dedicato?"} -->|Sì| ded["Usare il meccanismo dedicato"]
q1 -->|No| wmi["Usare WMI / CIM"]
wmi -.-> use["Interrogazioni trasversali e remote"]
cmd["Cmdlet dedicati basati su CIM"] -.-> ben["Solo i benefici, senza toccarli"]
Figura 19: Dove esiste un meccanismo dedicato, usatelo; per interrogazioni trasversali e remote usate WMI/CIM.
9. Riepilogo
- 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
- Come eseguire PowerShell da C# (CSharp) e ricevere i risultati come oggetti
- Ricette pratiche di comandi PowerShell — Far crescere i piccoli strumenti di tutti i giorni
- Le differenze tra Windows PowerShell 5.1 e PowerShell 7 — Guida pratica alla migrazione degli script interni
- Best practice per controllare e visualizzare lo stato di dispositivi esterni - Progettare oltre un singolo ‘Connesso’
- Chiamare in sicurezza le API Win32 da C# — Guida pratica a P/Invoke (DllImport / LibraryImport / CsWin32)
- Che cos’è il TPM in Windows — Guida illustrata alla «cassaforte che non fa uscire le chiavi» e al measured boot
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#.
- Sviluppo di applicazioni Windows
- Analisi dei bug e delle cause
- Consulenza tecnica e revisione del progetto
- Contattaci
Riferimenti
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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
-
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 correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
Best practice pratiche sul multithreading: edizione .NET — Cosa decidere prima di aggiungere altri thread
Le regole di progettazione per .NET/C# che impediscono che, dopo aver avviato un thread, l'app «crashi o si blocchi di tanto in tanto». L...
Era giapponese, festività e date di chiusura nelle applicazioni aziendali — progettazione resiliente ai cambi di era, JapaneseCalendar e calcolo dei giorni lavorativi nella pratica
Mostrare «Reiwa 8» su un documento, calcolare i giorni lavorativi escludendo le festività, pagare entro la fine del mese successivo dopo ...
Named pipe in pratica — L'IPC standard di Windows, dalla progettazione alla sicurezza
Guida pratica alle named pipe, il meccanismo standard di comunicazione tra processi su Windows. L'articolo organizza, a partire dalle fon...
App che si rompono alla ripresa dalla sospensione — Come funzionano gli eventi di alimentazione di Windows e come costruire app aziendali che li sopravvivono
Aprite il portatile e le connessioni dell'app aziendale sono morte — la causa è un progetto che non ha mai tenuto conto della sospensione...
Icone nella system tray e notifiche toast nelle app Windows — le insidie di NotifyIcon e come scegliere l'AppNotification giusta
Una guida pratica per mantenere un'applicazione Windows aziendale residente nella system tray (area di notifica) e avvisare l'utente tram...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
Applicazioni aziendali, integrazione di dispositivi e strumenti di comunicazione, dai requisiti allo sviluppo.
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.