Hola a tots,
feia molt de temps que no tenia l'ocasió de treballar amb WMI (Windows Management Instrumentation) i com que sempre m'ha semblat un recurs excepcional, m'he decidit a dedicar-li un post.
WMI ens proporciona una manera unificada d'accedir a la informació del sistema, és extensible per les nostres aplicacions i fàcilment consultable mitjançant WQL, evitant d'aquesta manera les consultes enutjoses a les API de Windows o al registre. WMI és accessible des de .Net a través de l'espai de noms System.Management i des d’script, ja que està exposat per COM.
WMI és molt potent perquè, a més a més de consultar informació del sistema, també podem modificar-la i fins i tot realitzar un ampli ventall d'operacions que van des d’iniciar processos a habilitar adaptadors de xarxa, passant per formatar particions. Però potser, el que li atorga major versatilitat, és poder realitzar aquestes operacions en ordinadors remots, sempre que tinguem suficients privilegis, és clar.
També té inconvenients, com tot en aquesta vida. Alguns d'ells són, per exemple, que no ens lliurem d'incompatibilitats entre les diferents versions del sistema operatiu, el servei Winmgmt ha d'estar executant-se en la màquina, les consultes poden tenir un rendiment molt pobre, a l'hora de creuar informació entre taules el WQL és poc intuïtiu i bastant complicat i segur que moltes altres més que ara mateix no recordo.
Mgmtclassgen
Us recomano aquesta utilitat que ens permet generar classes .Net a partir de classes WMI, de manera que podrem accedir als atributs i operacions d'aquests objectes mitjançant mètodes i propietats fortament tipats. Les classes generades són bastant bàsiques i serà treball nostre modificar-les en el cas que vulguem realitzar consultes complexes o bé optimitzar l'accés a les dades, però ens estalvia una gran quantitat de codi que ens permet tenir una aplicació molt més llegible.
Aquí us deixo un enllaç que explica l'ús d'aquesta utilitat: http://msdn.microsoft.com/en-us/library/2wkebaxa(v=VS.100).aspx
Per exemple, si executem la comanda mgmtclassgen win32_process, se'ns generarà l'arxiu Process.cs que inclourà la classe Process,
De manera que passarem a accedir a la informació de la següent manera:
1: foreach(Process ps in Process.GetInstances())
2: {
3: Console.WriteLine(ps.Name);
4: }
En comptes del que hauríem de fer abans:
1: System.Management.ManagementScope mgmtScope = new System.Management.ManagementScope();
2: mgmtScope.Path.NamespacePath = "root\\CimV2";
3: System.Management.ManagementPath pathObj = new System.Management.ManagementPath();
4: pathObj.ClassName = "win32_process";
5: pathObj.NamespacePath = "root\\CimV2";
6: System.Management.ManagementClass clsObject = new System.Management.ManagementClass(mgmtScope, pathObj, null);
7: System.Management.EnumerationOptions enumOptions = new System.Management.EnumerationOptions();
8: enumOptions.EnsureLocatable = true;
9: foreach (System.Management.ManagementBaseObject obj in clsObject.GetInstances(enumOptions))
10: {
11: Console.WriteLine(obj["Name"].ToString());
12: }
Guanyant no només llegibilitat en el nostre codi sinó també comprovació de tipus en temps de compilació i evitem errors en temps d'execució per exemple per haver escrit malament el nom d'un atribut.
Un altre aspecte a tenir en compte és que aquesta utilitat es basa en l'esquema existent a la màquina on s'executa la utilitat, de manera que les classes generades poden variar el comportament si s'executen en altres sistemes operatius.
Early vs Late Bound
Les classes generades per aquesta utilitat intenten proporcionar-nos un enfocament early-bound en lloc del late-bound que és el que tenim per defecte utilitzant les classes sota System.Management. Això vol dir que hem de decidir entre fer servir una aproximació late-bound o un accés fortament tipat? Res més lluny de la realitat, la utilíssima propietat AutoCommit que podem establir a false en qualsevol moment ens permet treballar amb l'objecte en memòria abans d'enllaçar amb l'objecte real. A més, també disposem de la propietat LateBoundObject que ens proporciona accés a l'objecte WMI subjacent.
Treballar amb early bound és la manera recomanada per Microsoft i la que hauríem d’emprar en la majoria de les ocasions pels avantatges que he comentat prèviament. No obstant això, hi han ocasions en què és necessari utilitzar un enfocament late-bound. Per exemple, si no coneixem en temps de disseny si un mètode o atribut existirà en temps d'execució. També podem trobar-nos que hi ha operacions que són impossibles de realitzar amb una aproximació early-bound a causa del disseny del component, com ara la instal.lació d'un nou driver d'impressora. A continuació mostro un exemple d'ús de la propietat AutoCommit:
1: Printerdriver driver = Printerdriver.CreateInstance();
2: driver.AutoCommit = false;
3: driver.LateBoundObject["Name"] = "Epson AL-2600";
4: driver.SupportedPlatform = "Windows x64";
5: uint rc = Printerdriver.AddPrinterDriver(driver.LateBoundObject);
Més info a:
Hola a todos,
hacía mucho tiempo que no tenía la ocasión de trabajar con WMI (Windows Management Instrumentation) y como siempre me ha parecido un recurso excepcional, me he decidido a dedicarle un post.
WMI nos proporciona una manera unificada de acceder a la información del sistema, es extensible por nuestras aplicaciones y fácilmente consultable mediante WQL, evitando de esta forma las consultas engorrosas a las APIs de Windows o al registro. WMI es accesible desde .Net a través del espacio de nombres System.Management y desde script, ya que está expuesto por COM.
WMI es muy potente porque, además de consultar información del sistema, también podemos modificarla e incluso realizar un amplio abanico de operaciones que van desde iniciar procesos a habilitar adaptadores de red, pasando por formatear particiones. Pero quizás, lo que le otorga mayor versatilidad, es poder realizar estas operaciones en ordenadores remotos, siempre que tengamos suficientes privilegios, claro está.
También tiene inconvenientes, como todo en esta vida. Algunos de ellos son, por ejemplo, que no nos libramos de incompatibilidades entre las diferentes versiones del sistema operativo, el servicio Winmgmt debe estar ejecutándose en la máquina, las consultas pueden tener un rendimiento muy pobre, a la hora de cruzar información entre tablas el WQL es poco intuitivo y bastante complicado y seguro que muchas otras más que ahora mismo no recuerdo.
Mgmtclassgen
Os recomiendo esta utilidad que nos permite generar clases .Net a partir de clases WMI, de tal manera que podremos acceder a los atributos y operaciones de estos objetos mediante métodos y propiedades fuertemente tipados. Las clases generadas son bastante básicas y será trabajo nuestro modificarlas en el caso de que queramos realizar consultas complejas o bien optimizar el acceso a los datos, pero nos ahorra una gran cantidad de código que nos permite tener una aplicación mucho más legible.
Aquí os dejo una enlace que explica el uso de esta utilidad: http://msdn.microsoft.com/en-us/library/2wkebaxa(v=VS.100).aspx
Por ejemplo si ejecutamos el comando mgmtclassgen win32_process, se nos generará el archivo Process.cs que incluirá la clase Process,
De manera que pasaremos a acceder a la información de la siguiente manera:
1: foreach(Process ps in Process.GetInstances())
2: {
3: Console.WriteLine(ps.Name);
4: }
En lugar de lo que teníamos que hacer antes:
1: System.Management.ManagementScope mgmtScope = new System.Management.ManagementScope();
2: mgmtScope.Path.NamespacePath = "root\\CimV2";
3: System.Management.ManagementPath pathObj = new System.Management.ManagementPath();
4: pathObj.ClassName = "win32_process";
5: pathObj.NamespacePath = "root\\CimV2";
6: System.Management.ManagementClass clsObject = new System.Management.ManagementClass(mgmtScope, pathObj, null);
7: System.Management.EnumerationOptions enumOptions = new System.Management.EnumerationOptions();
8: enumOptions.EnsureLocatable = true;
9: foreach (System.Management.ManagementBaseObject obj in clsObject.GetInstances(enumOptions))
10: {
11: Console.WriteLine(obj["Name"].ToString());
12: }
Ganando no solo legibilidad en nuestro código sino también comprobación de tipos en tiempo de compilación y evitamos errores en tiempo de ejecución por ejemplo por haber escrito mal el nombre de un atributo.
Otro aspecto a tener en cuenta es que esta utilidad se basa en el esquema existente en la máquina donde se ejecuta la utilidad, con lo que las clases generadas pueden variar el comportamiento si se ejecutan en otros sistemas operativos.
Early vs Late Bound
Las clases generadas por esta utilidad intentan proporcionarnos un enfoque early-bound en lugar del late-bound que es el que tenemos por defecto utilizando las clases bajo System.Management. ¿Esto quiere decir que tenemos que decidir entre usar una aproximación late-bound o un acceso fuertemente tipado? Nada más lejos de la realidad, la utilísima propiedad AutoCommit que podemos establecer a false en cualquier momento nos permite trabajar con el objeto en memoria antes de enlazarlo con el objeto real. Además, también disponemos de la propiedad LateBoundObject que nos proporciona acceso al objeto WMI subyacente.
Trabajar con early bound es la manera recomendada por Microsoft y la que deberíamos utilizar en la mayoría de las ocasiones por las ventajas que he comentado previamente. Sin embargo, hay ocasiones en las que es necesario utilizar un enfoque late-bound. Por ejemplo, si no conocemos en tiempo de diseño si un método o atributo existirá en tiempo de ejecución. También podemos encontrarnos que hay operaciones que son imposibles de realizar con una aproximación early-bound debido al diseño del componente, como por ejemplo la instalación de un nuevo driver de impresora. A continuación muestro un ejemplo de uso de la propiedad AutoCommit:
1: Printerdriver driver = Printerdriver.CreateInstance();
2: driver.AutoCommit = false;
3: driver.LateBoundObject["Name"] = "Epson AL-2600";
4: driver.SupportedPlatform = "Windows x64";
5: uint rc = Printerdriver.AddPrinterDriver(driver.LateBoundObject);
Más info en:
http://msdn.microsoft.com/en-us/library/aa394554(v=VS.85).aspx