Archive

Posts Tagged ‘WMI’

Cómo obtener la dirección MAC


Hace algunas lunas publiqué cómo obtener el número serial del disco duro usando C# y WMI. Como una especie de continuación, ahora toca explicar cómo obtener la dirección MAC (MAC Address), igual utilizando C# y WMI.

La dirección MAC: Media Access Control, es un identificador único asignado a prácticamente cualquier adaptador o tarjeta de red, por parte del fabricante.

Para obtener este número MAC, usamos WMI, y para ello primero referenciamos el ensamblado System.Management.dll. Luego nos creamos un ManagementClass que apunte a la configuración de adaptadores de red. Y finalmente, iteramos sobre los objetos hasta encontrarlo. Nota que antes debemos saber si la tarjeta de red está habilitada, por lo que revisamos la propiedad IPEnabled para asegurarnos que así sea.

using System;
using System.Collections.Generic;
using System.Management;

namespace Fermasmas.Wordpress.Com
{
  class Program
  {
    static void Main(string[] args)
    {
      ManagementClass management =
           new ManagementClass("Win32_NetworkAdapterConfiguration");
      ManagementObjectCollection adapters = management.GetInstances();

      List<string> macs = new List<string>();
      foreach (ManagementObject adapter in adapters)
      {
        bool isIpEnabled = (bool)(adapter["IPEnabled"] ?? false);
        if (isIpEnabled)
          macs.Add(adapter["MacAddress"] as string);
        adapter.Dispose();
      }

      foreach (string mac in macs)
        Console.WriteLine(mac);

      Console.ReadKey(true);
    }
  }
}

En la línea 11 creamos un objeto WMI que apunte hacia la configuración de adaptadores de red. Línea 13, obtenemos todos los adaptadores. Comenzamos a iterar sobre cada uno de estos. En la línea 18, obtenemos la propiedad IPEnabled del adaptador para saber si ese adaptador de red tiene la IP habilitada (i.e. está en uso). Si sí, obtenemos la propiedad MacAddress, que como habrás supuesto, es nuestra dirección MAC para ese adaptador. Y lixto. No olvides hacer un Dispose del objeto ManagementObject.

Y dado que actualmente estoy escribiendo el tutorial de Pininos con LINQ, pues cambiemos el código anterior por una consulta, ¿por qué no?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

namespace Fermasmas.Wordpress.Com
{
  class Program
  {
    static void Main(string[] args)
    {
      ManagementClass mgmt
          = new ManagementClass("Win32_NetworkAdapterConfiguration");
      ManagementObjectCollection adapters = mgmt.GetInstances();

      IEnumerable<string> macs = from ManagementObject adapter in adapters
                     where (bool)(adapter["IPEnabled"] ?? false)
                     select adapter["MacAddress"] as string;

      foreach (string mac in macs)
        Console.WriteLine(mac);

      Console.ReadKey(true);
    }
  }
}

Hasta la próxima.

Categorías:.NET Framework, C#, Cómo hacer Etiquetas:

Obtener información de una unidad de disco


.NET Framework pone a nuestra disposición una clase útil que nos servirá para obtener información relacionada con una unidad de disco. Estamos hablando de DriveInfo, ubicada en el espacio de nombres System.IO.

Comencemos con el constructor. Éste toma una cadena de texto como único parámetro, que representa la unidad de disco a la que se refiere. Ojo, porque lanza una excepción (ArgumentException) si se pasa un nombre de unidad inválido. Tradicionalmente usaríamos algo así:

 

try
{
    DriveInfo drive = new DriveInfo("C");
    ...hacer algo...
}
catch (ArgumentException e)
{
    Console.WriteLine("Formato inválido de unidad.");
}

 

Una alternativa, claro está, es listar las unidades de disco duro existentes. Para ello contamos con el método estático DriveInfo.GetDrives, que nos devuelve un array de objetos DriveInfo. Algo así:

DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo drive in drives)
{
    ...hacer algo...
}

 

Fuera del método estático GetDrives, y de los métodos estándares que hereda de Object y el ISerializable.GetObjectData que implementa (en efecto la clase hereda de ISerializable), no expone método alguno (quizás solo mencionar que la sobrecarga de ToString devuelve el nombre de la unidad). Pero sí tiene un conjunto de propiedades interesantes.

En primer lugar tenemos la propiedad DriveFormat. Esta nos devuelve el valor con el nombre del formato que tiene la unidad. Posibles valores son NTFS y el FAT32. Adicionalmente, tenemos la propiedad DriveType, que nos devuelve una enumeración de tipo DriveType con los siguientes posibles valores: Unknown (no se pudo determinar el tipo), NoRootDirectory (no he podido averiguar para qué sirve), Removable (la unidad es un dispositivo extraíble como un USB o un Flash), Fixed (lo contrario a Removable), Network (se trata de una unidad mapeada a un directorio en la red), CDRom (la unidad es un dispositivo óptico como una unidad de CD o de DVD) y finalmente Ram (indicando que la unidad se utiliza para memoria volátil).

Tenemos también las propiedades Name, RootDirectory y VolumeLabel, que nos devuelven el nombre de la unidad (por ejemplo, C:\, D:\, E:\, etc.), el directorio raíz (que como hablamos de una unidad de disco que por definición es raíz, prácticamente hablamos del mismo valor que la propiedad Name) y finalmente la etiqueta con la que hemos designado a nuestra unidad (los nombres son editables y pueden tener frases como “Disco personal”, “Disco de respaldo”, “CD-ROM”, etc.), respectivamente.

Con respecto al espacio y tamaño del disco, tenemos las siguientes propiedades. TotalSize devuelve el tamaño total de la unidad, en bytes. Por su parte TotalFreeSpace devuelve el espacio libre, mientras que AvailableFreeSpace devuelve el espacio libre disponible. La diferencia entre estas dos últimas es porque, por ejemplo, un disco duro puede tener 1 terabyte de espacio total, pero se comerá alrededor de 70 gigabytes para la tabla de direcciones por lo que solo estará disponible alrededor de 930 gigas. Usualmente utilizaremos AvailableFreeSpace cuando queramos ver si un archivo cabe o no en una unidad determinada.

Hay que tener un poco de cuidado, ya que las propiedades AvailableFreeSpace, DriveFormat, DriveType, TotalFreeSpace, TotalSize y VolumeLabel pueden generar una excepción de tipo IOException si la unidad produce algún error inesperado, usualmente que todavía no está disponible (por ejemplo si es un dispositivo extraíble). Para ello, siempre hay que revisar que la propiedad IsReady es true antes de llamar a estas otras propiedades, y en sistemas críticos deberíamos poner un bloque try-catch alrededor de estas llamadas.

El siguiente ejemplo muestra el empleo básico de la clase DriveInfo.

using System;
using System.IO;

...

try
{
    DriveInfo drive = new DriveInfo("C");
    if (drive.IsReady)
    {
        Console.WriteLine("Espacio disponible: {0}\n", drive.AvailableFreeSpace);
        Console.WriteLine("Formato: {0}\n", drive.DriveFormat);
        Console.WriteLine("Tipo: {0}\n", drive.DriveType);
        Console.WriteLine("Nombre: {0}\n", drive.Name);
        Console.WriteLine("Raíz: {0}\n", drive.RootDirectory);
        Console.WriteLine("Espacio total disponible: {0}\n", drive.TotalFreeSpace);
        Console.WriteLine("Tamaño total: {0}\n", drive.TotalSize);
        Console.WriteLine("Etiqueta: {0}\n", drive.VolumeLabel);
    }
    else
    {
        Console.WriteLine("La unidad \"C\" no está disponible en este momento.")
    }
} 
catch (ArgumentException e)
{
    Console.WriteLine("La unidad \"C\" no existe o es inválida. {0}", e.Message);
}
catch (IOException e)
{
    Console.WriteLine("Se ha producido un error en el sistema de entrada/salida. {0}", e.Message);
}
Categorías:.NET Framework, Apunte, C# Etiquetas:

Cómo obtener el número serial del disco duro (y más)


En ocasiones tenemos que obtener cierta información del sistema que parecería imposible a primera vista. El jefe nos dice: “necesitamos que obtengas el número de disco duro sobre el que corre la aplicación para poderlo usar al generar la licencia al cliente”. Entonces nos quedamos con cara de ¿¡¿what?!? y empezamos a dar vueltas en nuestro cubículo. Y al final resulta que es muy fácil obtener dicha información.

Microsoft cuenta con una herramienta para acceder a informacón de administración en un ambiente empresarial (redes, servidores, etc). Ésta recibe el nombre de WMI: Windows Management Instrumentation [1]. WMI es una implementación de Web-Based Enterprise Management, el cual es una iniciativa de la industria, y que utiliza el estándar Common Information Model para representar sistemas y aplicaciones, redes y dispositivos, de forma local o incluso de forma remota.

Para el caso que nos ocupa, WMI nos es de utilidad. Ya lo habrás adivinado, si no, no lo hubiera mencionado, ¿verdad?

En el caso de C# y el .NET Framework, la funcionalidad de WMI se encuentra contenida en el espacio de nombres System.Management, y hay que referenciar a la librería System.Management.dll. La mecánica para consultar información es sencilla:

  1. Crear un objeto de tipo ManagementObject pasándole como parámetro la consulta a realizar.
  2. Descargar la información desde WMI ejecutando el método Get.
  3. Recorrer la colección Properties del objeto para obtener los resultados.
    A continuación te presento un programita que hace exactamente lo anterior.
    
    using System;
    using System.IO;
    using System.Management;
    
    namespace Fermasmas.Wordpress.Com
    {
      class Program
      {
        static void Main(string[] args)
        {
          int count = 0;
    
          DirectoryInfo currentDir = new DirectoryInfo(Environment.CurrentDirectory);
          string path = string.Format("win32_logicaldisk.deviceid=\"{0}\"",
            currentDir.Root.Name.Replace("\\", ""));
          ManagementObject disk = new ManagementObject(path);
          disk.Get();
    
          foreach (PropertyData property in disk.Properties)
          {
            string name = property.Name.PadRight(25);
            string value = (property.Value ?? string.Empty)
              .ToString().PadRight(25);
            Console.WriteLine("Nombre: {0} Valor: {1}", name, value);
            if ((++count % 10) == 0)
            {
              Console.WriteLine("Presione una tecla para continuar o [ESC] para cancelar... ");
              ConsoleKeyInfo key = Console.ReadKey(true);
              if (key.Key == ConsoleKey.Escape)
                break;
            }
          }
    
          Console.WriteLine("Presione una tecla para terminar... ");
          Console.ReadKey(true);
        }
      }
    }
    
    

La cadena de texto que le paso al constructor representa una clase WMI, y el ya mencionado método Get descarga los datos desde WMI. De ahí, todo es pan comido: solo es cuestión de iterar sobre las propiedades y obtener la que nos interesa. De hecho, si ya sabes cual es el nombre de la propiedad que buscas, basta con invocar al indexador del ManagementObject. Por ejemplo, para ver el número serial del disco, basta con ejecutar este código:

DirectoryInfo currentDir = new DirectoryInfo(Environment.CurrentDirectory);
string path = string.Format("win32_logicaldisk.deviceid=\"{0}\"", 
    currentDir.Root.Name.Replace("\\", ""));
ManagementObject disk = new ManagementObject(path);
disk.Get();

string serial = disk["VolumeSerialNumber"].ToString();

Algunas referencias a continuación.

Referencias
  1. Acerca de WMI
  2. Cómo utilizar WMI
  3. Algunos ejemplos de WMI
Categorías:.NET Framework, C#, Cómo hacer Etiquetas: