Windows management instrumentation

Fournisseurs

Il existe différents fournisseurs d'accès à la base WMI. Certains utilisent l'arborescence de classe de la base CIM, d'autres requièrent l'intervention de provider annexes permettant de gérer des éléments d'une autre nature.

Instances


Le fournisseur d'instance est celui donnant accès à la base CIM. Il offre la possibilité de consulter les propriétés mais d’appeler aussi les méthodes sur les instances. Le script suivant permet de tuer une instance de la classe Win32_Process si son nom est "firefox.exe" :

'root\cimv2 est le namespace par défaut, pas besoin ici de le rajouter
Set wbemService = GetObject("winmgmts:\\.")

'on récupère les instances de la classe Win32_Process représentants les processus courants
Set wbemObjectSet = wbemService.InstanceOf("Win32_Process")
For Each objItem in wbemObjectSet
'si le nom est "firefox.exe" alors on le kill
if objItem.caption ="firefox.exe" then objItem.terminate()
Next

Le fournisseur d'instance peut également fournir les classes, pour cela on accédera directement au nom de la classe, cela permettra d'accéder aux méthodes et aux champs de classes, plus connues sous le nom de méthodes et champs statiques. Le script suivant utilise la méthode Create() de la classe Win32_Process, cela créera le processus désiré (ici sur la machine locale) :

'on récupère la classe Win32_Process
Set wbemClass = GetObject("winmgmts:\\.\root\cimv2:Win32_Process")

'pour obtenir le chemin on utilise la classe Win32_Product
Error = wbemClass.Create(c:\program files\winamp\winamp.exe", null , null, intProcessID)
If Error = 0 then
wscript.echo "winamp démarré avec le pid " & intProcessID
Else
wscript.echo "winamp n'a pas pu démarrer, erreur code : "& Error
End If

En guise de démonstration voici une application développée au format HTA, démontrant les principales applications de WMI. Celle-ci a été réalisée en peu de temps, pèse 10 ko, se lance et se connecte en moins d'une seconde.

Finger

Ce programme se connecte sur une machine (pour une machine distante, exécuter le programme sous son identité). Elle permet de :
Cette application a été développée à mon initiative pour surveiller les serveurs. Il est évident que l'utiliser en ciblant des machines clientes est déconseillé. (code moche et non commenté, vous êtes prévenus).

Compteurs de performances


D'autres objets ont été placés dans la base WMI par Microsoft ce sont des classes héritant de la classe CIM_StatisticalInformation. On trouve plus d'une centaine de classes différentes. Ces classes ne possèdent pas de méthodes et stockent une dizaine d'informations chacune. Ces informations évoluent avec le temps et son la base du système de compteur utilisé sont Windows.

Pour vérifier, lancer perfmon, clic droit sur le diagramme, ajouter un compteur, vous obtenez la liste des classes WMI ainsi que la possibilité de récupérer les compteurs d'autres machines.


moniteur de performance

Voici un exemple de script utilisant les compteurs de performances pour récupérer l'uptime de la machine locale :

Set wbemService = GetObject("winmgmts:\\.\root\cimv2")

Set wbemSet = wbemService.ExecQuery("Select * from Win32_PerfRawData_PerfOf_System",,48)
For Each objItem in wbemSet
wscript.echo "uptime "& objItem.SystemUptime
Next

On utilisera ces classes pour effectuer des mesures, ou gérer l'activité des machines. (débits réseaux, nombre de tentative de logon échouées...)

Événements


La base CIM permet également aux applications d'interagir entre elles, pour cela, WMI supporte les événements. Une application pourra poster un événement qu'une autre pourra interpréter. Le fait de passer par WMI permet de définir une norme de communication inter-application.

Voici un exemple de code Javascript surveillant les événements de création de processus sur une machine :

var service = locator.ConnectServer();
#on retient tous les événements de créations
szQuery = "SELECT * FROM __InstanceCreationEvent ";
#on demande ceux qui sont apparu depuis la dernière seconde
szQuery += "WITHIN 1 ";
#on match uniquement les Win32_Process représentant un processus classique
szQuery += "WHERE TargetInstance ISA 'Win32_Process'";
#on exécute la requête
service.ExecNotificationQueryAsync(mysink,szQuery);

C'est une simple requête que ce programme (d'un autre auteur) utilise pour afficher la liste des processus créé dans une page web. Lancez simplement cette application (à partir de votre bureau) et lancez d'autres programmes. Notre application est bien à l'écoute des événements de création du système.

Le WITHIN 1 définit la période de "polling" de la base CIM, malheureusement si une instance est crée puis détruite entre deux requêtes, alors l'événement ne sera pas capté.

Fournisseurs additionnels

Certains objets n'ont aucune représentation dans la base CIM mais y possède un point d'entré. C'est à dire qu'à partir d'une certaine classe, toute l'arborescence de classe qui en découle sera en fait gérée par un provider externe. Ci-dessous, on constate que l'accès aux objets Win32_NTEventLogFile se fera à travers d'un fournisseur additionnel.

provider

Quand le gestionnaire WMI détecte une tentative d'accès à de telles classes, il charge le provider correspondant et lui transmet la requête. Dans le cas du provider logfile, celui-ci va analyser les fichiers présents sur le disque et créer des instances à la volée permettant leur manipulation en WMI.

Ces fournisseurs peuvent être placé à tout endroit de l'arborescence WMI :
Voici un exemple de script WMI au format vbscript utilisant la classe Win32_NTEventLogFile pour sauvegarder le journal dévénement dans un fichier puis le vider.

strComputer = InputBox("Entrer le nom ou l'ip de la machine")
if strComputer <> "" then
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate,(Backup)}!\\" & strComputer & "\root\cimv2")
Set colLogFiles = objWMIService.ExecQuery ("Select * from Win32_NTEventLogFile where LogFileName='System'")
For Each objLogfile in colLogFiles
errBackupLog = objLogFile.BackupEventLog("c:\temp\System.evt")
If errBackupLog <> 0 Then
Wscript.Echo "The Application event log could not be backed up."
Else
objLogFile.ClearEventLog()
End If
Next
End if

Enfin voici un exemple de connection au provider SNMP présent dans root\snmp. Ce provider permet de récupérer des informations et également de créer des lignes dans des agents ou extensions d'agent (si cela respecte snmpV2-TC).

strTargetSnmpDevice = "."

Set objWmiLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWmiServices = objWmiLocator.ConnectServer("", "root\snmp\localhost")

Set objWmiNamedValueSet = CreateObject("WbemScripting.SWbemNamedValueSet")
objWmiNamedValueSet.Add "AgentAddress", strTargetSnmpDevice
objWmiNamedValueSet.Add "AgentReadCommunityName", "public"

Set colSystem = objWmiServices.InstancesOf("SNMP_RFC1213_MIB_system", , _
objWmiNamedValueSet)

For Each objSystem In colSystem
WScript.Echo "sysContact: " & objSystem.sysContact & vbCrLf & _
"sysDescr: " & objSystem.sysDescr & vbCrLf & _
"sysLocation: " & objSystem.sysLocation & vbCrLf & _
"sysName: " & objSystem.sysName & vbCrLf & _
"sysObjectID: " & objSystem.sysObjectID & vbCrLf & _
"sysServices: " & objSystem.sysServices & vbCrLf & _
"sysUpTime: " & objSystem.sysUpTime
Next

Il est également possible de développer son propre provider, mais cela ne sera pas abordé dans cet exposé, le processus étant bien trop complexe. Des liens son disponibles en référence pour ceux qui le souhaitent.