Sunday 24 July 2011

Utilidades WMI

Hola a todos,
Siguiendo la temática del post anterior, me gustaría profundizar un poco más en como podemos explotar WMI desde nuestras aplicaciones. Desde el área de sistemas siempre ha sido más habitual utilizar WMI que no desde el área de desarrollo, por ello podemos encontrar más herramientas enfocadas a sistemas para explotar sus posibilidades. Sin embargo, estas herramientas también pueden ser muy útiles para el programador, entre ellas me gustaría destacar WMI Code Creator, Script-o-matic, wmic y PowerShell.
 

WMI Code Creator

Como su propio nombre indica, esta herramienta permite generar código para acceder a WMI. Genera código tanto en VB.Net y C# como en VBScript. Su objetivo principal era ayudar a el personal de IT y desarrolladores a generar scripts para consultar WMI pero, además de esto, también nos permite ejecutar métodos de clases WMI, recibir eventos y navegar por todas las clases WMI que tengamos instaladas en nuestro ordenador. Aunque el código generado no sea muy complejo ni nos permita acceder a la información mediante propiedades fuertemente tipadas, como hace la utilidad mgmtclassgen que ya comenté en mi post anterior, es una utilidad muy práctica para explorar la información que podemos extraer de WMI y para generar código de ejemplo para realizar tareas básicas.
WMICodeCreator
Sin embargo, uno de los aspectos que más me atrae de esta utilidad es que está escrita en C#. No es una aplicación que tengamos que tomar como ejemplo a la hora de nuestros desarrollos, incluso diría que se podrían haber esforzado un poco en separar el acceso a la información de la interfaz gráfica. No obstante, leer el código ajeno es una de las mejores maneras de aprender, y, en un solo archivo cs descargable, podemos aprender un montón acerca de como está estructurado WMI y de como podemos acceder tanto a su esquema como a sus valores. Además, si utilizamos a menudo WMI o tenemos que generar scripts con asiduidad, siempre podemos modificar el código para que se adapte a nuestras necesidades.
WMI Code Creator puede descargarse del Microsoft Download Center aquí.
 

Scriptomatic 2.0

Esta utilidad es ampliamente conocida en el mundo del scripting. Es un archivo HTA (es decir HTML y VB Script), no genera código .Net sino VBScript, JScript, Perl y Python. Es bastante más limitada que WMI Code Creator desde el punto de vista del desarrollador pero aún así útil para enseñarnos los entresijos de escribir scripts para WMI. También está disponible en el Microsoft Download Center aquí.
 

WMIC

WMIC es sencillamente una utilidad de línea de comandos que nos permite acceder a WMI, es la utilidad más básica de las que he comentado pero es imprescindible conocerla si vas a trabajar extrayendo información del sistema por una u otra razón, ya que es la manera más sencilla de hacerlo y en algún momento tendrás la necesidad de corroborar de manera rápida los valores que retorna WMI. La desventaja es que hay que aprender a utilizarlo ya que, por una razón que escapa a mi conocimiento, utiliza alias para las clases y verbos para las acciones que son ligeramente distintos a los nombres de las clases WMI. Esta utilidad viene con el sistema operativo desde Windows XP, aquí os dejo el enlace que explica su sintaxis.
 

PowerShell Get-WmiObject

Para los que tengan la suerte de tener disponible PowerShell, existe el comando Get-WmiObject que nos da acceso a las clases de WMI desde la línea de comandos. Está claro que PowerShell es un gran avance para los administradores de sistemas pero como está basado en .Net también tiene una gran utilidad para los desarrolladores que sin apenas curva de aprendizaje podemos realizar scripts realmente complejos. Por ejemplo, con esta línea podemos recuperar todos los adaptadores de red
   1:  $NetworkAdapters = Get-WmiObject -Class Win32_NetworkAdapter 

y en la linea siguiente deshabilitar uno de ellos:

   2:  $NetworkAdapters[0].Disable() 

Aquí tenéis el enlace con la documentación de este método.

Sunday 17 July 2011

WMI fuertemente tipado


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

Friday 1 July 2011

Migrando aplicaciones .Net de 32 a 64 bits

Hola a todos,
ya sé que no es un tema novedoso pero esta semana he estado migrando unas aplicaciones a 64 bits, y esto a hecho que me encuentre con algunas cosas interesantes que me gustaría compartir.
Lo primero que pensé cuando me asignaron la tarea fue ¿por qué tengo que revisar una aplicación .Net para que funcione en 64 bits si solamente generamos ensamblados que están en IL, no en código nativo? Bueno, en seguida me respondí a mi mismo, ya que, salvo que se haya compilado la aplicación con la opción, /clr:safe no seria realista pensar que cualquier aplicación se ejecutará de igual manera en arquitecturas de 64 o de 32 bits. Microsoft dice que se deben revisar las aplicaciones sobre todo si en nuestro código hacemos alguna de estas cosas: invocar APIs de la plataforma via p/invoke, invocar objetos COM, utilizar código no seguro, utilizar marshaling como mecanismo de intercambio de información o utilizar la serialización como una manera de persistir el estado.  Las dos primeras están a la orden del día así que será bastante difícil que no tengamos que hacer al menos una pequeña revisión en nuestro código.

Framework64

La principal restricción que nos encontramos cuando trabajamos con .Net Framework en un sistema operativo de 64 bits es que desde una aplicación  cargada en el entorno de 32 bits no se pueden cargar componentes de 64  bits y viceversa, si lo intentamos nos encontraremos con un  FileNotFoundException o BadImageFormatException dependiendo del tipo de  componente a cargar. Esto es así porque en los sistemas de 64 bits tenemos dos entornos de  ejecución desde la versión 2.0, el entorno que se ejecuta en 64 bits y  que se encuentra en el directorio %windir%\Microsoft.Net\Framework64 y  el de 32 bits que se ejecuta bajo el wow64 (Windows on windows) y está  en  %windir%\Microsoft.Net\Framework .

Ldr64

Para habilitar el entorno de 64 bits,  .Net Framework  crea la clave Enable64bits en el registro  de Windows que indica, si tiene el valor 1, que se utilizará este entorno y que, por lo tanto, los ensamblados sin marca, se intentarán cargar como  ensamblados de 64 bits. A la inversa, si lo que queremos es forzar que  los ensamblados compilados con "Any CPU" se ejecuten bajo el WoW,  podemos establecer este valor a 0. Para modificar este valor, mejor que  hacerlo a mano, podemos utilizar la utilidad ldr64.exe que se encuentra  en el directorio Framework64. Con esto conseguimos además que se aplique inmediatamente la configuración  seleccionada y que los ensamblados del .Net Framework que se utilicen sean los de la plataforma indicada.
La utilidad ldr64 tiene una sintaxis muy sencilla, ya que  solo se le pueden indicar los parámetros query, setwow o set64, que son  autoexplicativos. No he encontrado en la Web mucha documentación de esta utilidad y no sé  de su robustez más allá de para ser usada por programadores pero podría ser interesante utilizarla en entornos de producción que dispongan de un sistema operativo de 64 bits pero con muchos ensamblados con dependencias en 32 bits, de esta manera no sería necesario recompilarlos.

CorFlags

 Una vez instalados ambos frameworks, cuando se ejecuta una aplicación, el CLR debe decidir en
cual de estos  dos entornos se cargará el proceso y para eso utiliza unos flags que se establecen en el PE del ejecutable (portable execution header). Para  poder ver estos flags sobre un ensamblado e incluso modificarlos sin tener que recompilar, aunque  Microsoft no lo recomienda, tenemos la utilidad corflags.exe,  disponible con el Visual Studio. Cuidado con los ensamblados firmados con un strong name, porque si cambiamos los flags con esta utilidad tendremos que volverlos a firmar.

Hay que tener en cuenta que  cuando seleccionamos el tipo de plataforma  en Visual Studio, principalmente estamos definiendo el valor de algunos de estos flags, concretamente el flag 32BIT. Este flag funciona de una manera un tanto peculiar ya que  establecerlo indica que, en un SO de 64 bits, se ejecutará bajo el  wow64, mientras que no establecerlo indica que el CLR podrá cargarlo como ensamblado de 64 bits si así lo desea.


Aquí muestro los flags que se establecen con cada configuración:
Plataforma
PE
32BIT
anycpu
PE32
0
x86
PE32
1
x64
PE32+
0

 Para quien no lo sepa, podemos descubrir que procesos se ejecutan en 32 bits simplemente mirando en la pestaña Procesos del administrador de tareas, los procesos que se ejecutan bajo el wow64 tienen añadido *32 al final del nombre. También podemos utilizar el método Module.GetPEKind para comprobar programáticamente la configuración de un ensamblado. Mientras que en tiempo de ejecución podemos consultar la propiedad IntPtr.Size (4 en 32 bits, 8 en 64). Precisamente, uno de los problemas habituales al migrar código a 64 bits que hace llamadas código nativo es utilizar el tipo de datos int en lugar de la clase IntPtr cuando se hace referencia a punteros, claro que si realizamos este tipo de prácticas deberíamos usar la clase SafeHandle, pero este tema se merece un Post entero así que ya lo comentaremos en otra ocasión.

GAC_64

Al principio del Post comenté que podríamos encontrarnos con una FileNotFoundException, esta excepción puede  lanzarse a causa del algoritmo de búsqueda del ensamblado ya que al instalar  el framework de 64 bits, igual que se crea una carpeta Framework64, también  se crea una nueva carpeta gac_64 bajo el directorio  c:\windows\assembly. Esta carpeta, que contendrá los ensamblados  específicos de 64 bits, se añade a las ya existentes: gac (para  frameworks 1.0 y 1.1), gac_32 y gac_msil (para ensamblados "platform  agnostic"). Dentro de c:\windows\assembly también observaremos que, si hemos generado imágenes nativas para nuestro ensamblados mediante la utilidad ngen, éstas estarán instaladas en carpetas del tipo NativeImages_%framework_version%_%platform%, es decir, por ejemplo, NativeImages_v2.0.50727_64.

Así pues, cuando el CLR busque un ensamblado, primero  buscará en el directorio propio de la plataforma y luego en gac_msil.  Esto puede ocasionar que no se encuentre el ensamblado en el caso de que  la aplicación se esté ejecutando bajo el contexto de 64 bits y el  ensamblado necesario se encuentre en el directorio gac_32 o a la  inversa.  Esta casuística se puede ver muy claramente gracias a utilidades como Process Monitor o Fuslogvw, que nos muestra los archivos que nuestra aplicación ha intentado abrir sin éxito.
Mas info en los siguientes enlaces:
Corflags.exe
How to switch between the 32-bit versions of ASP.NET 1.1 and the 64-bit version  of ASP.NET 2.0

on a 64-bit version of Windows
Migrating 32-bit Managed Code to 64-bit
64-bit Applications
Run 32 bit .NET applications on 64 bit machines
Moving from 32-bit to 64-bit application development on .NET Framework
Hablan del ldr64 pero para ponerlo en set64