RSS

WMI avec C#

05 Juin

WMI permet d’accéder aux ressources d’un ordinateur sous Windows, les configurer, les gérer et les interroger.

Présentation et historique de WMI.

WMI (Windows Management Instrumentation) est issu d’une initiative de normalisation d’un groupe appelé DMTF (Distributed Management Task Force) auquel Microsoft appartient.

L’objectif étant que tous les systèmes soient gérables via une même interface normalisée.

De ce groupe est née la norme CIM (Common Information Model). CIM est un schéma orienté objet pour la gestion des systèmes, des réseaux, des applications, des bases de données et des périphériques.

C’est Windows qui a le plus mis en ouvre WMI dans son système d’exploitation. Il est apparu pour la première fois en 1998 dans le service Pack 4 de Windows NT 4.0.Depuis il est présent dans Windows 2000, ME, XP et .NET Server.Pour les versions 95/98/NT on peut télécharger le Kit WMI sur le site de Microsoft.

Fonction de WMI.

WMI permet d’accéder aux ressources d’un ordinateur sous Windows, les configurer, les gérer et les interroger.

Ce qui sous entend la possibilité de gérer une machine, y faire exécuter un programme, arrêter un service, la rebooter ou l’arrêter, voir les ressources system, vous abonner à un événement et recevoir une alerte, interroger le service WMI d’une application (vous pouvez aussi écrire une application offrant un serveur WMI) etc.

Avec WMI vous accédez à tout ceci sans passer par les API, ainsi les développeurs n’ont pas besoin de connaître plusieurs API pour créer des applications puissantes ou interroger les composants de la machine hôte de leur application.

Combien de fois avez-vous vu sur les news group la question :  » Comment connaître le numéro de série d’un disque dur  » ?

De plus l’accès ne se limite pas à la machine où s’exécute le logiciel ou le script. On peut aussi interroger un ordinateur situé sur le réseau ou tous les ordinateurs d’un même groupe de travail.

Pratique pour un administrateur réseau pour suivre son parc machine, le surveiller, recevoir des alertes, diagnostiquer, rebooter une machine distante ou même la stopper etc..

Mise en oeuvre en C#.

Les Classes WMI peuvent être instanciés et les objets être interrogés via WMI Query Language (WQL). L’utilisation de WQL est similaire à la façon dont les requêtes SQL sont utilisées sur les bases de données. Cette section exposera clairement toutes les étapes pour interroger une machine et en récupérer les propriétés de Win32_OperatingSystem.

Architecture de WMI

L’architecture WMI se compose de trois couches principales:

  • Les consommateurs – c’est essentiellement la couche qui utilise les classes exposées et récupère le résultat du travail accompli. Cela peut inclure des scripts et des exécutables afin d’interroger les classes WMI et obtenir des informations d’une machine spécifique.
  • WMI Infrastructure – Il s’agit essentiellement des éléments qui recoivent les appels de consommateurs et interrogent les périphériques gérés. La principale composante de cette couche est le gestionnaire d’objets CIM (CIMOM) et l’espace de noms CIM. Le CIMOM aide dans la prestation de la connectivité entre les clients et les dispositifs.
  • Ressources gérées – Ceci inclut les dispositifs, services ou toute autre entité qui fournit des informations par le biais d’un fournisseur. Cette information est disponible sous la forme de classes, méthodes et attributs. Les fournisseurs WMI sont essentiellement une couche entre les ressources gérées et leurs interfaces natives au modèle objet CIM.

Le diagramme ci-dessous montre l’architecture de l’architecture détaillée de WMI.

wmi_architecture

wmi architecture (Source MSDN)

Codage en C#.

L’extrait ci-dessous montre la définition de la classe Win32_OperatingSystem à partir de MSDN.

class Win32_OperatingSystem : CIM_OperatingSystem
{
  string   BootDevice;
  string   BuildNumber;
  string   BuildType;
  string   Caption;
  string   CodeSet;
  string   CountryCode;
  string   CreationClassName;
  string   CSCreationClassName;
  string   CSDVersion;
  string   CSName;
  sint16   CurrentTimeZone;
  boolean  DataExecutionPrevention_Available;
  boolean  DataExecutionPrevention_32BitApplications;
  boolean  DataExecutionPrevention_Drivers;
  uint8    DataExecutionPrevention_SupportPolicy;
  boolean  Debug;
  string   Description;
  boolean  Distributed;
  uint32   EncryptionLevel;
  uint8    ForegroundApplicationBoost;
  uint64   FreePhysicalMemory;
  uint64   FreeSpaceInPagingFiles;
  uint64   FreeVirtualMemory;
  datetime InstallDate;
  uint32   LargeSystemCache;
  datetime LastBootUpTime;
  datetime LocalDateTime;
  string   Locale;
  string   Manufacturer;
  uint32   MaxNumberOfProcesses;
  uint64   MaxProcessMemorySize;
  string   MUILanguages[];
  string   Name;
  uint32   NumberOfLicensedUsers;
  uint32   NumberOfProcesses;
  uint32   NumberOfUsers;
  uint32   OperatingSystemSKU;
  string   Organization;
  string   OSArchitecture;
  uint32   OSLanguage;
  uint32   OSProductSuite;
  uint16   OSType;
  string   OtherTypeDescription;
  Boolean  PAEEnabled;
  string   PlusProductID;
  string   PlusVersionNumber;
  boolean  Primary;
  uint32   ProductType;
  string   RegisteredUser;
  string   SerialNumber;
  uint16   ServicePackMajorVersion;
  uint16   ServicePackMinorVersion;
  uint64   SizeStoredInPagingFiles;
  string   Status;
  uint32   SuiteMask;
  string   SystemDevice;
  string   SystemDirectory;
  string   SystemDrive;
  uint64   TotalSwapSpaceSize;
  uint64   TotalVirtualMemorySize;
  uint64   TotalVisibleMemorySize;
  string   Version;
  string   WindowsDirectory;
};

WmiClass est une classe qui expose des constantes avec le nom des classes WMI.

    public  class  WmiClass
    {
        public const string WIN32_SERVICE = "Win32_Service";
        public const string WIN32_PROCESS = "Win32_Process";
        public const string WIN32_PROCESSOR = "Win32_Processor";
        public const string WIN32_BIOS = "Win32_Bios";
        public const string WIN32_VIDEO = "Win32_VideoController";
        public const string WIN32_MEMORY = "Win32_MemoryDevice";
        public const string WIN32_SOUND = "Win32_SoundDevice";
        public const string WIN32_OPERATING_SYSTEM = "Win32_OperatingSystem";
        public const string WIN_32_PROGRAMMES = "Win32_Product";
        public const string WIN_32_RESEAU = "Win32_NetworkAdapter";
        public const string WIN_32_INTERFACES_RESEAU = "SNMP_RFC1213_MIB_ifTable";
        public const string WIN_32_IP_RESEAU = "SNMP_RFC1213_MIB_ipAddrTable";
        public const string WIN_32_DISQUES = "Win32_LogicalDisk";
    }

WmiTypesProperties est une classe qui expose des constantes avec les propriétés des classes WMI.

    public class WmiTypesProperties
    {
 /// WIN32_OPERATING_SYSTEM
        public const string WIN32_OS_CIBLE_MANUFACTURER = "Manufacturer";
        public const string WIN32_OS_CIBLE_CAPTION = "Caption";
        public const string WIN32_OS_CIBLE_SERIAL = "SerialNumber";
        public const string WIN32_OS_CIBLE_CSNAME = "CSName";
    }

OperatingSystemDTO est une classe qui explose les propriétés de la classe WMI Win32_OperatingSystem. C’est un objet de ce type qui contiendra les valeurs.

 /// Win32_OperatingSystem
 /// DTO for OperatingSystem, containing Win32_OperatingSystem data.
    public class OperatingSystemDTO
    {
        [System.ComponentModel.DataAnnotations.Key]
        public int ID { get; set; }
        public string Manufacturer { get; set; }
        public string Caption { get; set; }
        public string SerialNumber { get; set; }
        public string CSName { get; set; }
    }

Les champs privés ci-dessous sont utilisés pour interroger une machine.

        private ObjectQuery _ObjectQuery =
              default(ObjectQuery);
        private ManagementObjectSearcher _ObjectSearcher =
              default(ManagementObjectSearcher);
        private ManagementObjectCollection _ObjectCollection =
              default(ManagementObjectCollection);

GetTargetOperatingSystem est la méthode à appeler et qui retournera sous forme d’un objet de type ObservableCollection les données.

        public ObservableCollection GetTargetOperatingSystem
           (string servername, string wmiuser, string wmipassword, string snmpcommunity)
        {
            ObservableCollection operatingsystems =
               new ObservableCollection();
            GetWmiCollection
              (WmiClass.WIN32_OPERATING_SYSTEM, servername, wmiuser, wmipassword);
            int i = 1;
            foreach (ManagementObject mo in _ObjectCollection)
            {
                OperatingSystemDTO operatingsystem = new OperatingSystemDTO();
                operatingsystem.ID = i++;
                operatingsystem.Caption =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_CAPTION].ToString();
                operatingsystem.Manufacturer =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_MANUFACTURER].ToString();
                operatingsystem.SerialNumber =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_SERIAL].ToString();
                operatingsystem.CSName =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_NAME].ToString();
                operatingsystems.Add(operatingsystem);
            }
            FreeObjects();
            return operatingsystems;
        }

GetWmiCollection est la méthode qui accède aux données et les stocke dans l’objet _ObjectCollection.

         private void GetWmiCollection(string wmiclass, string machinename,
            [Optional, DefaultParameterValue("")] string wmiuser,
            [Optional, DefaultParameterValue("")] string wmipassword)
        {
            ConnectionOptions co = new ConnectionOptions();
            ManagementScope ms = default(ManagementScope);

            if (IsDistant(machinename))
            {
                co.Username = wmiuser;
                co.Password = wmipassword;
            }
            else
            {
                machinename = "localhost";
            }
            ms = new ManagementScope("\\\\" + machinename + "\\root\\cimv2", co);
            _ObjectQuery = new ObjectQuery("SELECT * FROM " + wmiclass);
            _ObjectSearcher = new ManagementObjectSearcher(ms, _ObjectQuery);

            _ObjectCollection = _ObjectSearcher.Get();

        }

IsDistant cette méthode retourne True ou False selon que le code s’exécute sur une machine distante ou pas.

        private static bool IsDistant(string server)
        {
            if (!string.IsNullOrEmpty(server.Trim()) & (server.Trim().ToLower()) != "localhost"
               &&
               (server.Trim().ToLower()) != Environment.MachineName.ToLower())
            {
                return true;
            }
            else
            {
                return false;
            }
        }

FreeObjects cette méthode libère les objets.

        private void FreeObjects()
        {
            if (_ObjectSearcher != null)
            {
                _ObjectSearcher.Dispose();
            }

            if (_ObjectCollection != null)
            {
                _ObjectCollection.Dispose();
            }
        }

Etape 1 – Importer « System.Management » dans votre code. Vous aurez besoin de toutes les méthodes exposées dans cette classe afin de manipuler et instancier des classes WMI. Les objets suivants seront nécessaires pour effectuer toutes les opérations liées WMI dans votre code client:

ConnectionOptions
ManagementScope
ObjectQuery
ManagementObjectSearcher
ManagementObjectCollection
ManagementObject

Etape .2 – Si on interroge une machine distante, l’objet ConnectionOptions contient le Username et le Password d’un utilisateur ayant les droits appropriés sur cette machine distante. Si on interroge la machine sur laquelle s’exécute l’application on n’a pas besoin de l’objet ConnectionOptions.

            ConnectionOptions co = new ConnectionOptions();

            if (IsDistant(machinename))
            {
                co.Username = wmiuser;
                co.Password = wmipassword;
            }
            else
            {
                machinename = "localhost";
            }

Etape .3 – Maintenant, nous devons définir un espace de noms dans lequel nous voulons exécuter notre opération. L’espace de noms est l’endroit où les classes WMI et CIM sont enregistrés. Toutes les opérations suivantes se produisent dans le cadre de cet espace de noms. L’extrait ci-dessous montre comment créer et définir la portée de la gestion. \root\cimv2 est le chemin d’accès à l’espace de noms dans lequel Win32_OperatingSystem est définie.

            ManagementScope ms = default(ManagementScope);
            ms = new ManagementScope("\\\\" + machinename + "\\root\\cimv2", co);

Etape .4 – Une fois connecté à notre espace de noms, nous devons maintenant créer une requête que nous pouvons exécuter sur notre classe WMI. Comme je l’ai mentionné plus tôt, WQL est similaire à SQL et est utilisé pour interroger et sélectionner les valeurs requises. L’extrait ci-dessous montre comment former une requête et instancier un objet de requête.

            _ObjectQuery = new ObjectQuery("SELECT * FROM " + wmiclass);

Etape .5 – Une fois que nous avons créé l’objet de requête, nous avons besoin pour l’exécuter dans le cadre de gestion (ManagementScope) que nous avons déjà créé.

            _ObjectSearcher = new ManagementObjectSearcher(ms, _ObjectQuery);

Etape .6 – On exécute la requête en utilisant la méthode Get de l’objet ManagementObjectSearcher, on stocke le résultat dans un objet ManagementCollection.

            _ObjectCollection = _ObjectSearcher.Get();

Etape .7 – On peut alors parcourir la collection pour la stocker dans une collection générique ObservableCollection de type OperatingSystemDTO.

            ObservableCollection operatingsystems =
               new ObservableCollection();

            foreach (ManagementObject mo in _ObjectCollection)
            {
                OperatingSystemDTO operatingsystem = new OperatingSystemDTO();
                operatingsystem.ID = i++;
                operatingsystem.Caption =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_CAPTION].ToString();
                operatingsystem.Manufacturer =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_MANUFACTURER].ToString();
                operatingsystem.SerialNumber =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_SERIAL].ToString();
                operatingsystem.CSName =
                  mo[WmiTypesProperties.WIN32_OS_CIBLE_NAME].ToString();
                operatingsystems.Add(operatingsystem);
            }

Remarque.

Classe ObservableCollection (Of  T)
Représente une collection de données dynamiques qui fournit des notifications lorsque des éléments sont ajoutés, supprimés ou lorsque la liste entière est actualisée.

Dans de nombreux cas, les données que vous utilisez sont une collection d’objets.Par exemple, un scénario courant de liaison de données consiste à utiliser un ItemsControl tel que ListBox, ListView ou TreeView pour afficher une collection d’enregistrements.

Vous pouvez énumérer toute collection qui implémente l’interface IEnumerable. Toutefois, pour paramétrer des liaisons dynamiques afin que les insertions ou suppressions dans la collection mettent automatiquement à jour l’interface utilisateur, la collection doit implémenter l’interface INotifyCollectionChanged. Cette interface expose l’événement CollectionChanged qui doit être déclenché à chaque fois que la collection sous-jacente est modifiée.

WPF fournit la classe ObservableCollection <(Of  T)>, qui est une implémentation intégrée d’une collection de données qui implémente l’interface INotifyCollectionChanged.

De plus cette classe est sérialisable (dispose de l’attribut SerializableAttribute) elle implémente l’interface ISerializable pour contrôler le processus de sérialisation.

La sérialisation est un processus qui consiste à convertir un ensemble d’instances de classe en une suite d’octets. Cela permet de sauvegarder des instances de classe dans un  fichier et/ou de les faire transiter sur un réseau. L’opération inverse, qui consiste à récupérer ces octets, s’appelle la désérialisation. Il est bien évidemment possible de créer son propre mécanisme de sérialisation.

Liens:

Publicités
 
Poster un commentaire

Publié par le 5 juin 2011 dans Développement, Système

 

Étiquettes : ,

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

 
%d blogueurs aiment cette page :