WMI (Windows Management Instrumentation) è un insieme di interfacce che permettono di interagire con le informazioni di sistema, e modificarle. Le
WMI si possono utilizzare in applicazioni di controllo e gestione dei sistemi, come ad esempio il controllo delle risore di un server, in questo esempio vedremo come interagire con le schede di rete per cambiare gli indirizzi IP.
Dal punto di vista .NET con
WMI non c'è bisogno di alcuna installazione visto che tutto è compreso nel sistema operativo inoltre a livello di classi bisogna dire che è già tutto compreso nell'apposito namespace
System.Management, ma Microsoft comunque ci offre dei tool per lo sviluppo che ci possono aiutare, primo fra tutti i
WMI Tools che possono essere scaricati qui:
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=6430F853-1120-48DB-8CC5-F2ABDC3ED314 ">Download WMI Tools
Questo Tool ci permette di navigare tra le informazioni di sistema come l'esplora risorse, inoltre mostra per ogni oggetto le dipendenze con altri oggetti. Inoltre è possibile installare un modulo per Visual Studio .NET che permette la navigazione e l?utilizzo degli oggetti direttamente da visual studio, ecco uno screenshot del modulo nel Server Explorer. Questo lo poete scaricare qui:
http://www.microsoft.com/downloads/details.aspx?FamilyID=62d91a63-1253-4ea6-8599-68fb3ef77de1&displaylang=it ">Estensioni WMI per Esplora server di Visual Studio .NET 2003
Le estensioni per VS.NET2003 in funzione
Architettura di WMILa tecnologia
WMI è costituita da due componenti principali:
? Struttura di gestione: La struttura di gestione include il
CIM (Common Information Model) Object Manager, che permette l?accesso univoco alle informazioni di sistema contenute nel CIM Repository
? Provider di accesso: Funzionano come intermediari tra il CIM e gli oggetti controllati, attraverso le API possono gestire il flusso di informazioni dal WMI fino agli oggetti di sistema. Inoltre gestiscono gli eventi e associano le informazioni alle classi di oggetti presenti nel CIM.
Ecco la tabella con l?elenco dei provider:
Tutte le informazioni salvate nel
WMI sono descritte utilizzando il
CIM (Common Information Model), che è stato studiato dalla
Distributed Management Task Force (
http://www.dmtf.org ">
http://www.dmtf.org ), ed è uno standard unificato che per fornire un framework comune definisce tutto in base a set di classi, proprietà e associazioni.
Il
CIM fornisce:
? La possibilità di gestire gli oggetti come classi astratte, per poter interagire con una periferica o con un processo.
? Proprietà e Metodi per gestire le classi, ad esempio la classe Hard Disk avrà la proprietà "Spazio disponibile", e un metodo per formattare il disco.
? Namespace per gestire le classi di oggetti.
Tutto questo ci permette di utilizzare facilmente ogni nostra periferica come se stessimo utilizzando oggetti di un qualsiasi linguaggio ad oggetti.
Dalla teoria alla pratica. Al lavoro!Bene dopo questa veloce introduzione sull?architettura, passiamo alla pratica, e come esempio pratico abbiamo scelto un?applicazione che ci permette di visualizzare l?elenco delle nostre interfacce di rete, per ognuna di queste visualizzare gli indirizzi IP e poterli modificare a nostro piacimento.
Iniziamo con il ricavare l?elenco delle nostre interfacce di rete, per fare questo, dovremo interagire con il provider Win32 ed utilizzare il namespace root\cimv2 (vedi tabella namespace), e creare un oggetto
ManagementObjectSearcher, e come parametro in ingresso chiede una query al database, in questo caso gli passiamo un oggetto
SelectQuery che rappresenta una query su una classe specifica, in questo caso la classe
Win32_NetworkAdapter che identifica le interfacce di rete.
//creo l'oggetto query
SelectQuery oq = new SelectQuery("Win32_NetworkAdapter");
//Creo il searcher per elencare le interfaccie
ManagementObjectSearcher searcher = new ManagementObjectSearcher(oq);
L?ggetto searcher ci mette a disposizione il metodo
get() che crea una collection di oggetti, quindi noi cicliamo per ricavare un oggetto
ManagementObject, che rappresenta la nostra interfaccia con la periferica. Nel ciclo ricaviamo il codice univoco della periferica, che ci servirà per interrogare la classe
Win32_NetworkAdapterConfiguration che permette di recuperare i dati di configurazione della singola scheda, e una volta recuperato il nostro oggetto lo inseriremo in una collection:
//ciclo sulla collection del searcher
foreach(ManagementObject obj in searcher.Get())
{
//ricavo l'id della periferica e interrogo la Win32_NetworkAdapterConfiguration
objectManagement objManage = new objectManagement((string)obj["DeviceID"]);
//aggiungo l'oggetto alla collection
adapterCollection.Add(new adapter(objManage.objWMI));
}
In queste righe di codice abbiamo utilizzato ben tre oggetti personalizzati, un oggetto
ObjectManagement che ci restituisce tramite query l?oggetto che punta alle caratteristiche della scheda, ecco il costruttore:
public objectManagement(string strDeviceID)
{
string strPath;
strPath = ("ROOT\\CIMV2:Win32_NetworkAdapterConfiguration" + (".Index=" + strDeviceID));
myObj = new ManagementObject(strPath);
}
Ricavato l?oggetto lo passiamo alla classe Adapter che ricaverà le informazioni di cui abbiamo bisogno, ad esempio l'IP e la descrizione della nostra scheda:
//costruttore classe adapter
public adapter(ManagementBaseObject objWMI)
{
//ricavo l?IP
if(objWMI["IPAddress"] != null){
IPAddress = (string[])objWMI.Properties["IPAddress"].Value;
}
//ricavo la descrizione
if(objWMI["Description"] != null){
Description = objWMI["Description"].ToString();
}
//Salviamo anche l?ID della periferica
if(objWMI["Index"] != null){
DeviceID = Convert.ToUInt32(objWMI["Index"]);
}
}
Oltre al
MACAddress possiamo memorizzare tutte le proprietà della nostra scheda, un elenco completo potete vederlo utilizzando il
WMI Object Browser che avete installato con i
WMI Tools. Ricavati tutti i dati inseriamo il nostro oggetto nella nostra collection personalizzata, che eredita dalla classe
CollectionBase, questo ci permette un accesso molto più comodo e veloce rispetto agli array, ecco il codice della collection:
// classe collection oggetti adapter
public class adaptersCollection : CollectionBase
{
//metodo aggiunta oggetto adapter
public void Add(adapter adapterItem)
{
List.Add(adapterItem);
}
}
Ora che abbiamo creato la nostra collection, non dobbiamo far altro che creare un groupBox che elenchi i nostri oggetti:
// Ciclo su tutti gli oggetti adapter contenuti nella mia collection
foreach(wmiClassesSharp.adapter obj in objAdapt.adapterCollection)
{
// Aggiungo la scheda
dropAdapters.Items.Add(obj.Description);
}
ed ecco il nostro primo risultato:
Ora che abbiamo l?elenco delle nostre schede vogliamo visualizzare l?IP di una singola interfaccia, quindi creiamo una funzione che intercetta il cambiamento di indice del nostro dropBox, recupera l?oggetto dalla collection e visualizza in una serie di quattro textbox l?IP:
// fuzione che intercetta il cambiamento di indice
private void dropAdapters_SelectedIndexChanged(object sender, System.EventArgs e)
{
// cerco l?oggetto nella collection
wmiClassesSharp.adapter myAdapt = objAdapt.adapterCollection.findByDeviceID(Convert.ToString(dropAdapters.SelectedIndex + 1));
// imposto l?ip nei textbox, facendo uno split per dividere l?ip
if(myAdapt.IPAddress != null){
string[] myIp = myAdapt.IPAddress[0].Split(".".ToCharArray());
txtIP0.Text = myIp[0];
txtIP1.Text = myIp[1];
txtIP2.Text = myIp[2];
txtIP3.Text = myIp[3];
}
}
come vedete per ricavare l?oggetto dalla collection viene utilizzato un metodo personalizzato findByDeviceID, che non fa altro che ciclare e restituire l?oggetto con l?ID specificato.
// metodo che restituisce un oggetto dalla collection
public adapter findByDeviceID(string strDeviceID)
{
adapter myAdapt = null;
// ciclo sulla collection
foreach(adapter objAdapt in List)
{
// controllo che l?oggetto abbia l?id cercato
if(objAdapt.DeviceID == strDeviceID)
{
// imposto l?oggetto e esco dal ciclo
myAdapt = objAdapt;
break;
}
}
// ritorno il mio oggetto
return myAdapt;
}
ed ecco il risultato:
Modifica dei valoriDopo esser riusciti a ricavare le proprietà della nostra scheda vediamo come andare a modificarne I valori. Per poter modificare un valore nelle
WMI dobbiamo invocare uno dei metodi supportati dalla classe tramite il metodo
InvokeMethod, questo metodo richiede come parametri il nome del metodo, l?array con i parametri e una serie di opzioni, e ci restituirà un array con i parametri in uscita. Quindi creo una funzione che accetta come parametri in ingrasso l?oggetto management che punta alla scheda, il nuovo indirizzo, la subnet e il gateway e prima di invocare il metodo creiamo l?array dei parametri in ingresso e in uscita.
public void setIP(adapter myObj, string address, string subnet, string gateway)
{
ManagementBaseObject myParamsIn;
ManagementBaseObject myParamsOut;
. . .
}
Dopo di che inizializziamo l?array con i parametri necessari, utilizzando il metodo
GetMethodParameters che non fa altro che interrogare il metodo.
// Interrogo il metodo
myParamsIn = myObj.GetMethodParameters("EnableStatic");
// Imposto i parametri necessari
myParamsIn["IPAddress"] = new string[] {address};
myParamsIn["SubnetMask"] = new string[] {subnet};
A questo punto invoco il metodo EnableStatic che mi imposta i valori della scheda di rete
// Modifico gli indirizzi
myParamsOut = myObj.InvokeMethod("EnableStatic", myParamsIn, null);
Lo stesso metodo lo usiamo per impostare il gateway della nostra scheda
// Interrogo il metodo
myParamsIn = myObj.GetMethodParameters("SetGateways");
// Imposto i parametri necessari
myParamsIn["DefaultIPGateway"] = new string[] {gateway};
myParamsIn["GatewayCostMetric"] = new int[] {1};
// Modifico gli indirizzi
myParamsOut = myObj.InvokeMethod("SetGateways", myParamsIn, null);
Se invece vogliamo impostare la nostra scheda in modalità DHCP, non dobbiamo far altro che richiamare il metodo
EnableDHCP
myParamsIn = myObj.GetMethodParameters("EnableDHCP");
myParamsOut = myObj.InvokeMethod("EnableDHCP", myParamsIn, null);
ConclusioniNel seguente articolo abbiamo esplorato l?architettura
WMI e capito come interagire con quest?ultima, implementando un semplice programma per cambiare gli IP della nostra scheda di rete, ma potremmo anche sviluppare applicazioni per il controllo di qualsiasi periferica, oppure applicazioni web per il controllo dei nostri server. Inoltre I più curiosi possono esplorare soluzioni altrernative, infatti sono disponibili vari metodi di accesso al repository
WMI, tra cui anche ODBC per facilitare il lavoro a noi poveri sviluppatori, quindi buon lavoro!