Mais pourquoi n’y avais-je pas pensé avant ? Pourquoi ?

3615 malife

Comme tout un chacun, j’ai un (en fait, deux…) compte Facebook. Ce n’est pas que j’y raconte énormément ma vie trépidante (au contraire, je parie que beaucoup de monde m’a « muté » tellement mes posts sont chiants en général !), mais surtout pour garder le contact avec mes amis (des vrais, des plus ou moins vrais, et puis un peu de famille aussi). Je pourrais très bien m’en passer, je sais très bien ce que fait Facebook de mes données personnelles, de mes interactions avec les uns et les autres (un #PJLRenseignement avant l’heure), mais n’empêche, je trouve Facebook pratique. Et j’avoue une flemme over 9000 pour ce qui est de passer des coups de fil pour prendre des nouvelles.

Le problème, c’est qu’à chaque fois que je vais sur la version web, j’ai droit à quantité de pubs plus ou moins bien ciblées : des milliers femmes célibataires en rut en bas de chez moi ? Tss, ça sent tellement l’attrape-couillon que je prends ça pour une insulte. Tant pis si c’est vrai, ça me gonfle, et me gonfler est une des pires idées qui soient.

Il y a quelques semaines, quand je me suis attelé à SponsoKilla, je me suis dit que ma prochaine victime serait Facebook. Et puis de l’eau a coulé sous les ponts, parfois par dessus même, le temps a passé, j’ai aussi un métier accessoirement, et… bon ok, assez de prétexte, j’avais la flemme de me pencher sur le sujet.

Ce n’est qu’après avoir mis le point final à ma série à succès sur WMI et PHP que cette histoire de pubs Facebook est revenue au premier plan. Pour être précis, c’était même dans le RER il y a quelques dizaines de minutes.

A peine arrivé, j’ai lancé Firefox, et suis allé sur Facebook, voir comment je pourrais m’y prendre. Et là, j’ai ris, mais j’ai ris, tellement c’était simple. Deux lignes. Oui, deux (2) lignes de code. Et encore, histoire de faire les choses proprement. Une seule aurait suffit, en réalité.

Extensions du domaine de la lutte

Comme vous avez peut-être remarqué sur des captures d’écrans dans d’autres articles, j’ai quelques extensions installées avec Firefox, et notamment GreaseMonkey, puisque c’est lui qui fait fonctionner SponsoKilla, NoScript (qui bloque l’exécution de JavaScript sur certaines pages et/ou domaines, bien pratique aussi), AdBlock Edge (un fork non-sponsorisé d’AdBlock Plus) et j’en passe.

Mais celle qui me sert le plus, notamment lorsque je programme pour moi ou au boulot, c’est Web Developper. C’est encore mieux qu’un couteau Suisse, c’est dire. Si vous programmez des sites ou applis Web ou juste par curiosité pour voir comment tout cela fonctionne, c’est l’extension qu’il vous faut.

Parmi ces nombreuses fonctionnalités géniales, celle qui me sert le plus est probablement Examiner l’élément. C’est simple, vous faites un clic droit sur l’endroit de la page qui vous intéresse (ça peut être du texte, une image, un formulaire, un div, n’importe quoi) et bim, Web Developper ouvre un panneau en pointant vers cet élément dans le code de la page, tout en respectant la hiérarchie du DOM (Document Object Model). Et ça, c’est top, croyez-moi.

Toi mon gaillard, il ne te reste pas longtemps à vivre…

Ainsi, rien qu’en faisant un clic droit sur le bloc de pubs de Facebook, et avec un chouilla de logique tout de même, je savais comment me débarrasser de celles-ci.

Identification de la victime

A la différence de Twitter, Facebook a un contenu assez peu dynamique, et surtout les programmeurs ont eu l’excellente idée d’identifier la plupart des éléments, et en particulier les divs (qui sont en gros des blocs pouvant contenir tout et n’importe quoi). Un div (c’est le nom de la balise HTML) n’est pas forcément visible, même si son contenu l’est. Il peut avoir des bordures, un fond, et plein d’autres propriétés, ou pas. Mais quoiqu’il en soit, dans le DOM, le div est le parent de objets qu’il contient (s’il en contient, ce n’est pas toujours le cas) et auquel cas, ceux-ci peuvent hériter ses propriétés (ou avoir les leurs propres).

Comme je l’indiquais, Facebook identifie ses divs, c’est-à-dire que chaque div a une propriété id et donc un nom (théoriquement) unique. Je dis théoriquement car j’ai vu des sites où des objets ont le même id, c’est qui est une très mauvaise idée (et va à l’encontre des normes du W3C soit dit en passant).

L’avantage de ces id, c’est qu’en programmation, on va pouvoir cibler un objet particulier (et là vous avez compris qu’on allait cibler un div) grâce à cet id, justement. Et le langage roi pour accéder au DOM d’une page web n’est autre que JavaScript.

Si vous avez de bons yeux, vous pouvez voir sur la capture d’écran ci-dessus que je me suis focalisé sur un div dont l’id est tout simplement « rightCol ». C’est ma victime. Maintenant que je sais qui c’est, je vais pouvoir créer un nouveau script pour GreaseMonkey (et vous aussi).

L’arme du crime

Comme vous avez installé Greasemonkey depuis mon premier article sur ce blog, vous vous doutez qu’on va cliquer sur la flèche à droite de son icône, mais cette fois-ci, dans le menu déroulant, nous allons choisir Nouveau script.

Et la première chose que fait Greasemonkey, c’est de nous poser des questions embarrassantes : qu’est-ce que je mets là-dedans ? C’est quoi un espace de nom ? Inclus quoi ?

  1. Nom : bon ben, facile, on va appeler ça Faceblock, donc on tape Faceblock et on passe au champ suivant.
  2. Espace de nom : ah, là déjà, c’est plus vicieux… En fait, cet espace de nom va simplement servir à distinguer notre Faceblock d’un éventuel autre script Greasemonkey qui s’appellerait aussi Faceblock et qui aurait été écrit par un mandchou manchot exilé en Terre Adélie. Personnellement, j’ai mis l’adresse de ce blog, vous pouvez mettre l’adresse de votre site ou de votre profil Twitter, l’idée c’est que ça reste assez unique et surtout que vous ayez plus ou moins la maîtrise de cette unicité si je puis dire. Evitez de mettre votre adresse complète, email et téléphone inclus, ou votre numéro de CB, toutefois.
  3. Description : ben on va dire ce que fait notre Faceblock, donc notamment qu’il supprime les pubs ciblées de Facebook, tiens.
  4. Inclus (un par ligne) : et bien ici, on va indiquer à Greasemonkey sur quel(s) site(s) – à raison d’un par ligne – Faceblock doit être activé. J’ai donc mis https://www.facebook.com/. Vous pouvez très bien utiliser des jokers (le * notamment) pour être plus ou moins précis. Par exemple, si je mets https://*.facebook.com/*, Faceblock sera activé sur tous les sous-domaines de Facebook, quelque soit l’adresse après le .com.
  5. Exclus : le principe est le même que pour Inclus, cela indique à Greasemonkey sur quels sites/pages Faceblock ne doit PAS être activé (ici on ne met rien, puisque Faceblock cible spécifiquement Facebook).

 Une fois que vous aurez cliqué sur OK, vous obtiendrez une fenêtre avec ça dedans :

// ==UserScript==
// @name Faceblock
// @namespace http://dedelateur.blogspot.com
// @description Vire les pubs ciblées de Facebook
// @include https://www.facebook.com/
// @version 1
// @grant none
// ==/UserScript==

Oui bon ce n’est pas très folichon à première vue, ce sont que des commentaires, et on retrouve en gros ce qu’on vient d’entrer dans le formulaire. Et puis des machins avec des @ devant, c’est quoi ça encore ?

Il s’agit d’un bloc de métadonnées qui va servir à indiquer deux-trois choses à Greasemonkey, comme le nom de votre script, la description, l’espace de nom, la version etc. Les trucs avec des @ devant sont appelés des clés.

Si vous regardez le code source de SponsoKilla, vous verrez le même bloc, avec quelques clés supplémentaires, que j’ai rajouté en l’écrivant. Je n’en parlerai pas dans cet article, car il faudrait entrer dans des détails du fonctionnement de Greasemonkey dans lesquels je risquerai de vous perdre. Vous êtes libre de modifier ce bloc, si Greasemonkey ne reconnaît pas une clé que vous aurez inventé, c’est simple, il l’ignorera.

Le problème des métadonnées, c’est que ça ne fait rien d’autre que de décrire quelque chose. Il manque le code qui va faire quelque chose, lui.

Et comme je l’ai annoncé dans le titre, il tient en deux lignes (les accolades, ça ne compte pas), que voici :

  if(document.getElementById("rightCol"))
{
document.getElementById("rightCol").style.display="none";
}

Et oui, c’est tout. C’est le code source COMPLET de Faceblock. Vous collez ça à la suite du bloc de métadonnées, vous enregistrez le tout, vous allez sur Facebook et hop, plus de pub.

Comme je le disais, on aurait très bien pu mettre tout sur une ligne, mais pour des raisons de clarté et de pédagogie, c’est un peu plus pratique d’avoir séparé tout ça.

Autopsie

En pseudo-code, voici la traduction : Si l’élément dont l’id est « rightCol » existe dans le document, alors modifie la propriété display de cet élément pour qu’il ne soit plus affiché.

Décortiquons tout ça : le if veut dire si, bon ça c’est pas compliqué, on va donc tester une condition, jusque là, ça vaaaaa…

Vient document.getElementById(« rightCol »). On sait que notre élément (le fameux div qui correspond à la colonne de droite où se trouvent les pubs) s’appelle « rightCol », puisqu’on l’a vu grâce à Web Developper. La méthode getElementById va permettre de fouiller le DOM et de trouver ce fameux « rightCol ». Et on applique la méthode à quoi ? Au document. Autrement dit, à la page web affichée par le navigateur.

Donc en gros, notre première ligne peut en réalité se traduire par « si tu trouves rightCol dans le document ». La réponse est très simple : soit c’est oui (et aura en retour le booléen True, vrai), soit c’est non (et auquel la réponse est False, faux). Or dans notre exemple, on ne s’embête même de savoir si c’est true ou false, car après le if (si) il y a un then (alors) implicite : « si tu trouves… alors ». Et de même, le else (sinon) est implicite. Tellement qu’on ne le précise même pas : si tu ne trouves pas rightCol, tu ne fais rien. Fin de l’histoire.

En réalité, la méthode getElementById retourne en interne (dans la tête de JavaScript si j’ose dire) une sorte de numéro d’objet, celui de rightCol en l’occurence. C’est bien pratique car ce numéro d’objet vous nous servir à la ligne suivante :

document.getElementById("rightCol").style.display="none";



On aurait très bien pu stocker ce numéro d’objet dans une variable, et s’en resservir, ce qui nous aurait donné un truc du genre :

var rightcol=document.getElementById("rightcol");
if(rightcol)
{
rightcol.style.display="none";
}

Mais bon, vu que qu’elle ne sert que deux fois et que le script s’arrête juste après, pourquoi faire compliqué…

Comme vous le savez, un objet a des propriétés, et même des sous-propriétés (ouhla j’entends hurler au loin). Je vulgarise à mort. Ici, on va jouer sur la propriété style de rightCol, et plus précisément sur la sous-propriété display (de style, pas directement de rightCol, sinon on aurait écrit document.getElementById(« rightCol »).display= »none » or ce n’est pas le cas et ce pour une excellente raison : rightCol n’a PAS de propriété display).

Cette propriété est spéciale, car elle ne peut prendre que quelques valeurs bien définies. Je ne vais pas citer toute la liste, les trois valeurs les plus fréquentes sont « block », « none » ou encore « inline ». Je vais simplifier encore plus (amis puristes, détournez le regard) en disant qu’en gros, « block » et « inline » affichent un élément, et « none » ne l’affiche plus (il ne le détruit pas, l’objet est TOUJOURS dans le DOM, ce qui permet de le réafficher si besoin).

Version longue (et vaguement procédurale) de cette ligne de code : farfouille le document à la recherche de l’objet dont l’id est « rightCol » puis modifie la propriété display à none. Et au passage tu en profites pour avertir le moteur de rendu du navigateur pour qu’il n’affiche plus ce « rightCol » à l’écran et donc qu’il rafraîchisse tout ça. Ah et tu mettras le DOM à jour, tu seras chou. Merci, bisous.

Version courte (et vaguement orientée objet) : n’affiche plus « rightCol ».

Enterrement

C’est tout de même rigolo ces histoires de propriétés et de valeurs, notamment « block », « inline » et même « none »… Comme une impression de déjà vu… Hmm… Bon sang mais c’est bien sûr : dans une feuille de style CSS !

Et oui jeune padawan, tout est lié en informatique. Le DOM, JavaScript, CSS, HTML… Mais nous verrons ça une prochaine fois ! En attendant, profitez-en pour améliorer Faceblock : plutôt que de ne plus afficher toute la colonne, pourquoi ne pas se contenter de retirer les pubs, en laissant par exemple les blocs d’invitations, de suggestions de groupes, ce genre de choses ? Pour ça, bonne chasse aux divs avec Web Developper !

Vendredi, c’est raviolis et WMI, quatrième partie !

To boldly go where no man has gone before

Dans la partie précédente, nous avons vu comment faire des requêtes (en langage WQL) WMI sur le PC local. Comme je vous l’ai dit, la connexion à un PC distant change un peu, on ne se contentera pas d’une seule ligne cette fois-ci. Voyons déjà à quoi ça ressemble :

<?php

$ip="192.168.0.2";
$WMIadmin="administrateur";
$WMIpwd="motdepasseenclairouhlala";

$WbemLocator = new COM ("WbemScripting.SWbemLocator");
$WbemServices = $WbemLocator->ConnectServer($ip, 'root\cimv2', $WMIadmin, $WMIpwd);
$WbemServices->Security_->ImpersonationLevel = 3;

?>

Décortiquons un peu tout ça. Au début du script, nous définissons trois variables :

  1.  $ip contient l’adresse IP de la machine distante que nous allons interroger (vous pouvez aussi mettre son nom, du moment que la résolution de noms fonctionne, par DNS ou hosts)
  2. $WMIadmin contient le nom d’un compte disposant des droits d’administration sur la machine distante. Si vous ne précisez rien, c’est un compte local (de la machine distante). Si vous voulez spécifier un nom de domaine, il suffit de l’indiquer sous cette forme : « domaineadministrateur ». Du très classique sous Windows.
  3. $WMIadmin contient le mot de passe (en clair…) de ce compte. Oui, coller un mot de passe en dur dans un script est rarement une bonne idée, car il suffit d’avoir accès au système de fichiers du serveur pour accéder au script sans qu’il soit exécuté…

Ensuite, nous établissons la connexion d’une manière différente :

  1. On crée une instance d’objet COM de type « WbemScripting.SWbemLocator »
  2. On se connecte au PC distant en appelant la méthode ConnectServer, et en spécifiant dans l’ordre l’adresse IP/le nom de la machine distante, le namespace qui nous intéresse (c’est le même qu’en local), le compte et le mot de passe.
  3. Enfin, on indique le niveau de sécurité souhaité. Ici, le serveur s’authentifie sur le contexte local de la machine distante (le client). Les différents niveaux sont détaillés ici mais en général, vous vous contenterez du niveau 3 (« Impersonation »).

Nous sommes désormais connectés, on peut lancer nos requêtes et récupérer les propriétés qui nous intéressent comme on l’a vu dans la troisième partie.

J’ai la requête qui colle

Je vous livre ici quelques classes et propriétés qui peuvent trouver leur utilité (c’est mal parce que ça vous évite de chercher, mais c’est bien parce que partager mes informations me rend beaucoup plus sympathique, non ?).

  • Connaître la version de Windows et le Service Pack installé

$system = $WbemServices->ExecQuery("Select * from Win32_OperatingSystem");
foreach($system as $os)
{
echo $os->Caption." ".$os->Version." (SP".$os->ServicePackMajorVersion.".".$os->ServicePackMinorVersion.")";
}

Ici, on peut se passer de la propriété ServicePackMinorVersion, cela évite d’afficher SP1.0 au lieu de SP1, mais sait-on jamais, peut-être que Microsoft sortira un jour un SP1.1… donc méfiance.

  • Informations sur le processeur

(oui, c’est le corrigé de l’exercice de l’autre fois).

$proc = $WbemServices->ExecQuery("Select * from Win32_Processor");
foreach ($proc as $p)
{
$proc_deviceid=$p->DeviceID;
$proc_manufacturer=$p->Manufacturer;
$proc_maxclockspeed=$p->MaxClockSpeed;
$proc_currentclockspeed=$p->CurrentClockSpeed;
$proc_name=$p->Name;
$proc_nbcores=$p->NumberOfCores;
$proc_nbvcores=$p->NumberOfLogicalProcessors;
$proc_socket=$p->SocketDesignation;
$proc_version=$p->Version;
}

Je vous laisse en faire un joli tableau comme celui-ci (tiré d’une de mes applis), les variables sont réutilisées dans cet ordre.

Oui je sais, c’est un vieux clou.

N’oubliez pas qu’on peut avoir plusieurs processeurs sur une carte mère, que la boucle foreach va regarder chaque « ligne » de résultat de la requête.  Il faut donc qu’avant la fin de la boucle vous affichiez les valeurs retournées. Si vous ne le faites qu’après la boucle, vous n’aurez les informations que pour le deuxième processeur…

Une astuce au passage : si $proc_nbvcores est égal au double de $proc_nbcores, c’est que l’HyperThreading est activé sur ce processeur. La valeur de la propriété SocketDesignation est assez spéciale : parfois on a le numéro du socket, parfois il s’agit du format de socket (LGA775 par exemple, ou U3E1 assez régulièrement pour des PC portables). Malheureusement, d’un système à l’autre (et donc d’un constructeur à l’autre), les valeurs ne sont toujours pas consistantes. Il ne faut donc pas estimer que si la valeur est correcte sur votre PC, elle le sera sur un autre.

  • Informations sur la RAM

Un exemple typique de classe où les valeurs des propriétés varient énormément d’un PC à un autre…

$memorytype=array(0=>"Unknown",1=>"Other",2=>"DRAM",3=>"Synchronous DRAM",4=>"Cache DRAM",5=>"EDO",6=>"EDRAM",7=>"VRAM",8=>"SRAM",9=>"RAM",10=>"ROM",11=>"Flash",
12=>"EEPROM",13=>"FEPROM",14=>"EPROM",15=>"CDRAM",16=>"3DRAM",17=>"SDRAM",18=>"SGRAM",19=>"RDRAM",20=>"DDR",21=>"DDR2",22=>"DDR2 FB-DIMM",24=>"DDR3",25=>"FBD2");

$ram = $WbemServices->ExecQuery("Select * from Win32_PhysicalMemory");

foreach($ram as $r)
{
$ram_capacity=$r->Capacity;
$ram_manufacturer=$r->Manufacturer;
$ram_model=$r->Model;
$ram_name=$r->Name;
$ram_speed=$r->Speed;
$ram_sn=$r->SerialNumber;
$ram_version=$r->Version;
$ram_bank=$r->BankLabel;
$ram_dl=$r->DeviceLocator;
$ram_type=$memorytype[$r->MemoryType];
}

Si vous regardez la doc de la classe Win32_PhysicalMemory, la propriété MemoryType peut avoir une valeur de 0 à 23. Comme un bête nombre n’est pas toujours compréhensible pour un humain non-mutant, j’ai ajouté le tableau $memorytype dans lequel on ira chercher, pour la valeur de MemoryType, la signification « en clair » (enfin, faut s’y connaître un peu en technologie de mémoire, sinon ce n’est pas si clair que ça…). C’est ce que fait la dernière ligne. De nombreuses autres propriétés nécessiteront ce genre de tableau de correspondance, un peu pénible à saisir, hélas.

Comme pour les processeurs, il peut y avoir plusieurs barrettes de mémoire sur la carte mère, donc pensez à faire votre affichage dans la boucle foreach.

La requête du Graal

Jusqu’à présent, nous avons vu des requêtes très simples (Select * from Win32_bidule), qui serviront la plupart du temps. Cela dit, WQL est un langage de requête un peu plus évolué que ça. Ainsi, au lieu de récupérer TOUTES les propriétés d’une classe (l’astérisque), vous pouvez définir une clause where pour être un peu plus spécifique.

Par exemple, dans l’exemple précédent, imaginons que vous ayez une barrette fabriquée par Micron, et une autre par Hynix/Hyundai (oui oui, Hyundai, comme pour les voitures… vous voyez que les comparaisons informatique/automobile tiennent la route !). Vous pouvez très bien construire votre requête pour n’avoir QUE la barrette (en réalité, les puces… même si vous avez une barrette avec un logo Kingston, vous verrez le nom du fabricant des puces mémoire) Micron, et même, n’avoir QUE les propriétés Manufacturer et Speed (vitesse du bus en MHz) :

SELECT Manufacturer, Speed FROM Win32_PhysicalMemory WHERE Manufacturer= »Micron »

J’ai volontairement mis SELECT, FROM et WHERE en majuscules, afin que vous vous rendiez bien compte à quel point WQL est proche du langage SQL. De fait, vous pouvez jouer avec des AND, des OR, des LIKE, TRUE, FALSE, NULL et j’en passe. La référence de WQL sur le MSDN se trouve ici.

Je n’irai pas volontairement plus loin dans l’utilisation de WQL et passe sous silence un certain nombres de points de WMI. Vous aurez par contre constaté en lisant les docs Microsoft que bien souvent, les classes Win32_machin héritent des propriétés d’autres classes (souvent des CIM_truc). Par exemple, pour la propriété Capacity de Win32_PhysicalMemory, on peut lire ceci :

Capacity
Data type: uint64
Access type: Read-only

Total capacity of the physical memory—in bytes. This property is inherited from CIM_PhysicalMemory.

Si vous suivez le lien, vous verrez que la classe CIM_PhysicalMemory possède des propriétés qu’on ne retrouve pas dans Win32_PhysicalMemory : c’est particulièrement intéressant car vous aurez ainsi plus d’informations sur un matériel. Après, tout dépend de ce que vous compter en faire, évidemment.

Team Requête ! Plus rapide que la lumière !

Rendez-vous, ou ce sera la guerre !

Jusqu’à présent, nous n’avons fait des requêtes que sur un seul namespace, rootcimv2. C’est déjà pas mal, on a accès à énormément d’infos. Mais à force de jouer avec WMI et à découvrir des classes et propriétés intéressantes, j’ai me suis mis dans l’idée qu’il devait être possible de savoir quelles applications étaient installées sur un PC donné.

Et là, malgré des heures de recherche dans wbemtest, j’ai fait chou blanc.

Et pour une raison toute simple, il faut aller voir dans un autre namespace. Car oui, il y en a plusieurs.
Celui qui nous intéresse s’appelle rootcimv2sms, et là bas, les classes ont tendance à s’appeler SMS_quelquechose.

Si dans votre programme vous voulez interroger deux namespaces, il faudra pour chacun faire une connexion différente (c’est exactement le même principe qu’avec les bases de données : une connexion par base. Là c’est une connexion par namespace).

$WbemLocator = new COM ("WbemScripting.SWbemLocator");
$SMS = $WbemLocator->ConnectServer($ip, 'root\cimv2\sms', $WMIadmin, $WMIpwd);
$SMS->Security_->ImpersonationLevel = 3;

$sms_soft = $SMS->ExecQuery("Select * from SMS_InstalledSoftware");
foreach($sms_soft as $ss)
{
$sms_pub=$ss->Publisher;
$sms_pn=$ss->ProductName;
$sms_pv=$ss->ProductVersion;
$sms_id=$ss->InstallDate
}

Voilà le genre de résultat que vous pouvez obtenir (il faut penser à reformater la valeur de la propriété InstallDate à votre convenance) :

J’en ai tellement qu’on ne voit sur la capture d’écran qu’Office. Mais tout ce qui est dans Ajout/Suppression de programme (pardon : Programmes et fonctionnalités depuis Windows 7) remonte dans ma liste.

Un petit avertissement : cette requête prend du temps (à fortiori sur une machine distante) à être exécutée, et il m’est arrivé plus d’une fois qu’une machine dépasse les 30 secondes réglementaires pour répondre à ma requête. Résultat, mon script se terminait tristement en Fatal error: Maximum execution time of 30 seconds exceeded… Il suffit dans ce cas de prévoir un peu plus de temps grâce à la fonction set_time_limit de PHP.

 
N’oubliez pas que vous pouvez utiliser la clause Where dans vos requêtes ! Par exemple, vous pourriez très bien ne rechercher que les applis de tel éditeur, ou tout ce qui a été installé depuis telle date, etc etc… Là encore, expérimentez !

This is the end, my friend

Les bonnes choses ont toujours une fin et nous arrivons au terme de cette série d’articles. J’espère qu’elle vous a plu et donné envie d’en savoir un peu plus sur les possibilités offertes par WMI, et sur son exploitation en PHP. Si vous êtes fan d’un autre langage, vous pouvez tout à fait faire du WMI avec celui-ci. Vous trouverez de nombreux exemples en PowerShell (ce qui ravira les sysadmins), VB ou C++ sur Internet.

Si vous avez des questions, n’hésitez pas à les poser en commentaire, j’essaierai d’y répondre du mieux possible. De même, si vous voulez partager votre code avec le monde entier, c’est l’occasion ou jamais ! Sur ce, je file à la sieste ! Ciao !

Déjà la troisième partie, et toujours pas la moindre ligne de PHP jusqu’à présent…

De la théorie à la pratique 

Réjouissez-vous, car le purgatoire est bientôt fini, vous allez pouvoir dégainer votre PHPEdit, votre Notepad++, bref votre IDE préféré et taper quelques lignes de PHP. Comme certains d’entre vous n’en ont peut-être jamais écrit, on va faire très simple : un script PHP est un simple fichier texte, au même titre qu’une page HTML, mais dans lequel nous allons demander au pré-processeur PHP d’exécuter des commandes.

Pour éviter qu’il se mélange les pinceaux (et surtout que vous n’obteniez des résultats étonnants), il faut lui indiquer où se trouve le code PHP. Ceci se fait tout simplement grâce à deux balises. Elles sont indispensables, immuables, obligatoires, et en rouge ci-dessous :

1
2
3
<?php
// Le code PHP sera ici
?>

Il suffit d’enregistrer le fichier avec l’extension .php dans le répertoire spécifié dans la configuration d’Apache, puis d’appeler le script depuis votre navigateur préféré, en général en accédant à l’adresse http://127.0.0.1/toto.php (oui, vous pouvez appeler votre script toto.php, ce n’est pas interdit).

Note : par défaut, le répertoire où stocker vos fichiers .php est <répertoire où Apache est installé>htdocs. Si vous utilisez EasyPHP, c’est un peu plus tordu car cela dépend de la version installée… Il suffit cependant de faire un clic droit sur l’icône d’EasyPHP dans le Systray, de choisir Administration, puis dans la page qui s’ouvre, regarder la section Web local : vous verrez alors le répertoire racine de votre serveur Web, par exemple C:UsersDédéDocumentsEasyPHP-DevServer-14.1VC9datalocalweb. C’est dans ce répertoire (ou dans un sous-répertoire) que vous devrez mettre votre fichier .php. Lorsque vous appellerez l’adresse http://127.0.0.1/, Apache lira le contenu du répertoire localweb sur le disque.

Il existe tout un tas de tutoriels du plus ou moins bonne qualité sur PHP. Si vous en trouvez un bourré de fautes, fuyez-le comme la peste. Il aura souvent été écrit par un ado boutonneux l’ayant largement pompé sur le site d’un camarade, en conservant les mêmes erreurs.

Allez on y va

Après ce petit rappel (ou cette découverte fabuleuse, au choix), nous allons enfin écrire un vrai script PHP, qui lancera une requête WMI et affichera les valeurs obtenues. Magnifique, non ? Allez, créez une nouveau fichier texte, et faites un copier-coller de ceci (j’ai retiré les numéros de ligne pour que ce soit plus pratique pour vous) :

<?php

if(!extension_loaded("com_dotnet"))
{
echo "Il faut l'extension php_com_net.dll dans le php.ini !";
exit;
}

?>

C’est tout ? Oui. mais on va décortiquer un petit peu tout ça. Ici, on indique à PHP : « Si l’extension com_dotnet – autrement dit php_com_dotnet.dll – n’est PAS chargée (le ! devant extension_loaded est une négation), alors affiche (echo) le message, puis arrête d’exécuter le script (exit). » Vous aurez noté que certaines lignes – pas toutes – se terminent par un point-virgule. En gros, les lignes qui ne définissent pas une structure (des conditions if, des boucles for ou while…) doivent avoir ce point-virgule final, sous peine de générer une erreur. Faites le test et retirant celui de la ligne qui commence par echo, et vous verrez. Pour les débutants, c’est une habitude à prendre.

Lors de l’exécution de ce script, si vous avez bien chargé l’extension com_dotnet, il ne se passera rien. Ecran vide. Que d’chi. Nada. Et c’est normal, puisqu’on n’a pas indiqué quoi faire à PHP. Donc il ne fait rien. Le script s’arrête, Apache envoie la page (vide !) au navigateur et c’est tout. Est-ce que l’exit est obligatoire ? Non, techniquement le script se serait terminé juste après l’echo. Mais comme on va ajouter des instructions ensuite (si l’extension est bien chargée), cet exit évitera d’exécuter le reste du script après avoir affiché le message, ce qui provoquerait forcément des erreurs.

Les choses sérieuses commencent

Comme je vous l’ai dit dans les parties précédentes, WMI permet d’interroger le PC local (celui sur lequel vous exécutez PHP) ou un PC distant (pour peu qu’il soit démarré, accessible via le réseau et que le service WMI soit démarré). N’espérez pas pouvoir interroger un PC via internet, il y a de fortes chances que ça coince quelque part. Sur votre réseau local par contre, en théorie aucun problème (à moins d’avoir un firewall logiciel qui bloque. Si vous rencontrez un problème, parlez-en commentaire, on cherchera une solution).

Pour l’instant, nous nous contenterons d’interroger le PC local, nous verrons comment se connecter à distance ensuite. En local, nul besoin d’indiquer l’adresse IP, un simple point (.) suffit. Nous allons donc nous connecter au namespace root/cimv2 local via COM en PHP. Pour ça, ajoutez simplement la ligne suivante, juste avant la balise ?>  :

$WbemServices=new COM ("winmgmts:\\.\root\cimv2");

Voilà, c’est tout. On crée un nouvelle instance COM nommée $WebmServices qui va utiliser le protocole winmgtms pour se connecter au namespace \.rootcimv2. Les backslashes sont doublés car comme vous le savez peut-être, le backslash est un caractère d’échappement. Et lorsqu’on veut qu’il apparaisse depuis une chaîne, il faut le doubler.

(Amis puristes, oui je sais, il n’y a pas de récupération en cas d’exception, chaque chose en son temps. On va dire que $WebmServices est bien créé systématiquement).

Etape suivante, on va se servir de cette connexion pour exécuter une requête WQL (elle va vous rappeler des souvenirs), afficher les valeurs des propriétés Vendor et Version de la classe Win32_ComputerSystemProduct (comme précédemment, ajoutez ces lignes avant la balise ?>) :

$compsysprod = $WbemServices->ExecQuery("Select * from Win32_ComputerSystemProduct");

foreach($compsysprod as $csp)
{
$cspvendor=$csp->Vendor;
$cspversion=$csp->Version;

echo "Constructeur : ".$cspvendor."<br />";
echo "Modèle : ".$cspversion."<br />";
}

Enregistrez le fichier, retournez sur votre navigateur, et si tout va bien, vous devriez obtenir quelque chose de ce genre :

Si vous voyez autre chose que LENOVO et ThinkPad T440, c’est bien aussi, hein

Félicitations, vous venez pour la première fois d’interroger votre PC en utilisant WMI ! Revenons un peu plus en détails sur le code :

$compsysprod = $WbemServices->ExecQuery("Select * from Win32_ComputerSystemProduct");

Ici, nous appelons la méthode ExecQuery (qui permet d’exécuter la requête fournie en paramètre) de l’instance $WbemServices, et allons stocker tout ça dans la variable $compsysprod (un objet de type variant. Pour ceux qui seraient tentés par faire un var_dump dessus, sachez que ça ne vous appendra hélas pas grand chose).

Ensuite, nous faisons une boucle foreach parmi LES résultats (ici il n’y en a qu’un, mais il peut y en avoir plusieurs) enfin plus exactement chaque itération (que nous appelons $csp) de $compsysprod :

foreach($compsysprod as $csp)
 

Puis, nous récupérons les valeurs des propriétés Vendor et Version de chaque itération (objet) $csp, puis nous les affichons (echo):

{
$cspvendor=$csp->Vendor;
$cspversion=$csp->Version;

echo "Constructeur : ".$cspvendor."<br />";
echo "Modèle : ".$cspversion."<br />";
}

 

Vous voyez, rien de bien compliqué comme je me tue à vous le dire ! Variez un peu les plaisirs en sélectionnant parmi les classes Win32_quelquechose les propriétés qui vous intéressent, et affichez-les. Utilisez wbemtest comme indiqué dans la deuxième partie de cette série d’articles pour cela.

Comme parfois le nom d’une propriété peut porter à confusion, une petite astuce toute simple pour trouver des informations : ouvrez un nouvel onglet, allez sur Google, et tapez le nom de la classe qui vous intéresse. Allez sur le lien (en général le premier) qui arrive et qui ressemble à celui-ci :

Win32_ComputerSystemProduct class (Windows) – MSDN

Vous arrivez directement sur la page du MSDN, où sont listées et expliquées les différentes propriétés de la classe. Des heures de lecture en perspective…

Une fois n’est pas coutume, je vous remets le code source complet de notre exercice du jour. N’hésitez pas à jouer avec, à améliorer le résultat (par exemple, faites un joli tableau HTML), etc. Nous nous arrêterons ici pour cette partie, la prochaine vous montrera comment interroger un PC distant, car au niveau du code, cela change un peu.

<?php

if(!extension_loaded("com_dotnet"))
{
echo "Il faut l'extension php_com_net.dll dans le php.ini !";
exit;
}

$WbemServices=new COM ("winmgmts:\\.\root\cimv2");
$compsysprod = $WbemServices->ExecQuery("Select * from Win32_ComputerSystemProduct");

foreach($compsysprod as $csp)
{
$cspvendor=$csp->Vendor;
$cspversion=$csp->Version;

echo "Constructeur : ".$cspvendor."<br />";
echo "Modèle : ".$cspversion."<br />";
}
?>

A bientôt !

Avant de lire cette deuxième partie, (re)lisez la première, merci. Je prends la responsabilité de l’infinite loop qui en résultera.

Des problèmes apportés par la délocalisation dans un PVD de la traduction des noms de services chez Microsoft

Avant de jouer avec wbemtest, il y a un tout petit truc à savoir : WMI est activé par défaut sur les versions de Windows postérieures à XP. Donc si c’est votre cas, vous n’allez pas avoir à faire grand chose de ce chapitre. Par contre, si vous avez XP, il va falloir vérifier qu’un service est bien démarré.
En anglais, ce service est judicieusement appelé Windows Management Instrumentation (oh bah dites donc, en abrégé ça donne l’acronyme WMI, c’est pratique). Mais en français, patatras, le traducteur olmèque embauché à un salaire dérisoire a décidé que ce serait Infrastructure de gestion Windows et pas autre chose. Quel fourbe, ce patatras.

Donc cher lecteur, il ne te reste plus qu’à aller dans ton menu Démarrer préféré (si tu n’es pas sous Windows 8. Si c’est le cas, passe en 8.1 avec l’update de 3 Go qui suit, ça te simplifiera la vie, crois-moi), de cliquer sur Exécuter, et de taper dans la joie et l’allégresse services.msc tout en écrasant délicatement la touche Entrée de ton clavier pour finir.

Et sous tes yeux ébahis, tu verras apparaître une fenêtre similaire à ceci :

La console services.msc
Sinon blogger, tu la centres quand tu veux et avec la taille que j’ai demandé, la capture d’écran, hein.

Si le service est démarré, tout va bien, sinon tu le démarres et on n’en parle plus. Et en plus, tu gagnes un process svchost.exe à l’affaire, tu vois que tu n’es pas venu ici pour rien. Et si tu préfères la ligne de commande, tu peux aussi taper net start winmgmt et le tour est joué.

Tu peux pas test

Enfin si, et c’est justement ce que nous allons faire de ce pas, car je vous sens piaffer d’impatience depuis la fin de la première partie. Nous entrons désormais dans les choses sérieuses du vif du sujet, et pour cela, retournons d’une manière extatique dans le menu Démarrer, recliquons sur Exécuter, puis tapons de toutes nos forces webmtest avant de martyriser amoureusement la touche Entrée.

Et là bim, je dois faire une autre capture d’écran alors que ça ne sert à rien vu que vous allez avoir à peu de choses près la même chose que moi, c’est-à-dire ça :

Oui c’est moche mais c’est la beauté intérieure qui compte, voyons !

Inutile d’appeler GDF-Suez Engie ou les pompiers, car même si wbemtest ressemble à une usine à gaz, l’utilisation que nous allons en faire est des plus simplissimes qui soient. A tel point que vous vous en voudrez d’avoir cru que c’était compliqué.

Sans même vous poser de question, cliquez sur le bouton Connexion en haut à droite, la boîte de dialogue suivante apparaîtra comme par magie (mais en fait, c’est de la programmation tout ça, enfin j’espère que ce n’est pas un scoop pour vous) :

Ce n’est guère plus joli que la capture précédente, je sais.

On se détend, et on ne touche à rien pour l’instant. On regarde seulement en haut de la fenêtre, l’encadré Espace de noms (toi-même, hé). Ce petit « rootcimv2 » a une certaine importance comme je vous le montrerai plus tard. Si vous avez bien vu et retenu, c’est bon, vous pouvez cliquer sur le bouton Connexion (oui encore, mais ce n’est pas le même bouton en fait).

Mais… il ne s’est rien passé !

Tu n’es pas très très observateur, jeune disciple. Regarde bien la première capture d’écran de wbemtest que je t’ai généreusement offert précédemment, puis ton wbemtest à toi. Tu ne vois rien de changé ? Non ? Toujours pas ? Regarde tous les boutons… ils ne sont plus grisés !

Maintenant que nous sommes connecté à l’espace de nom (ou namespace chez nos amis d’Outre-Rhin, qui parlent en général mieux anglais que nous) rootcimv2, nous allons pouvoir regarder un peu tout ce qui se cache là-dedans. Mais plutôt que d’y aller à l’aveuglette et de recourir aux arts divinatoires qui sont tout de même un peu foireux (hein, @levraihoroscope), nous allons demander gentiment mais fermement à wbemtest d’énumérer toutes les classes qu’il a à nous montrer. Et pour cela, rien de tel que de cliquer sur le bouton Énumérer les classes (quelle surprise).

Sauf qu’il ne va pas le faire tout de suite le bougre. Il va falloir faire des trucs mystérieux sur la boîte de dialogue qui surgit du fond de la nuit :

N’espérez pas voir de truc joli ici, allez dehors si c’est ce que vous recherchez

Enfer et damnation ! Que faire ? Comme je n’arrête pas de vous seriner que WMI, c’est SIMPLE, je vais vous le prouver une fois de plus : sélectionnez l’option Récursive, puis cliquez sur OK. Allez vous préparer un café instantané au micro-ondes et revenez vite fait devant votre PC, car même wbemtest a besoin d’un peu de temps pour énumérer toutes les classes du namespace, ça ne prend tout de même pas des heures. Attendez simplement qu’il affiche Terminé là où était écrit Opération en cours… quelques instant auparavant (et que vous n’aviez pas vu car vous étiez occupé à faire votre café).

En forçant un peu sur la bouteille, vous trouverez cette boîte de dialogue sexy. Si, si !

Mais qu’est-ce que c’est que ce truc encore…

Décidément, vous et moi faisons les mêmes réflexions, à quelques semaines d’intervalle cela dit. Ceci est une liste. De classes WMI. Et oui, il y en a beaucoup. 1078 chez moi, sur le PC sur lequel j’écris fiévreusement cet article, peut-être plus ou moins chez vous… Aucune importance.

Vous vous souvenez certainement de la classe Win32_ComputerSystem que j’avais évoqué dans la première partie. Et bien nous allons la chercher à la mano souris en faisant défiler la liste des classes grâce à l’ascenseur latéral. Comme elles sont classées (la classe pour des classes) dans l’ordre alphabétique, les Win32_quelquechose sont plutôt vers la fin. Donc allez-y franco, lâchez-vous, allez tout en bas, puis remontez la liste jusqu’à trouver la classe qui nous intéresse. Ne tenez pas compte (pour l’instant) des trucs entre parenthèses.

Ah tiens chez moi elle est plutôt vers le milieu en fait…

Et là je pousse un cri d’alarme retentissant (et pour une fois je ne déconne pas) : ne cliquez pas, JAMAIS, NEVER, sur le bouton Supprimer. Ni même sur Ajouter. Vraiment.

Bon ça ne cassera pas grand chose vu qu’au prochain reboot vous retrouverez tout, mais de manière règle, quand on ne sait pas, on ne fait pas, ou alors on se renseigne d’abord (proverbe d’informaticien du paléolithique, mais toujours valable de nos jours).

 Par contre, ce que vous pouvez faire (et ça vous aidera dans la suite de cet article), c’est de double-cliquer sur la classe Win32_ComputerSystem (avec du blabla entre parenthèses après). Et là, nul doute que les plus impressionnables d’entre vous s’agenouilleront devant le miracle qui s’accomplit :

Tadaaaaaaa ! (non ce n’est pas le son de WinXP mais les trompettes des anges, m’enfin !)

Oui, là ça devient magnifique. Moi-même je n’ai plus de mots pour décrire ça. Mais n’oubliez pas que WMI est la quintessence de la simplicité absolue, et regardez plus attentivement en plein milieu de la boîte de dialogue… Vous le voyez l’encadré Propriétés avec des machins (bah, des propriétés hein) dedans ?

Et bien figurez-vous que c’est dans ce fouillis qu’on va trouver ce qui nous intéresse, notamment Manufacturer et Model… Là, une petite explication s’impose. Le CIM_STRING après le nom de la propriété indique simplement son type (en l’occurrence, une chaîne, et pas le slip rabougri du cul que portent les filles). Ensuite vient la valeur de la propriétés. Si vous regardez attentivement, vous verrez des <null> partout.

Ta propriété en string !

C’est <null> ton truc !

Vu comme ça, oui, car ce que je vous ai fait faire jusqu’à présent ne permet que de lister les classes et leurs propriétés (ce qui évite le recours à la boule de cristal, assez peu efficace en la matière). L’idée est juste de vérifier qu’une propriété existe et son nom. Si vous voulez voir les valeurs, il va falloir jouer du WQL ! Oui, Microsoft aurait pu tout afficher du premier coup, on aurait tous gagné du temps, mais n’oubliez pas que les gens qui y travaillent sont un peu… spéciaux. Mais j’ai dans l’idée qu’afficher les valeurs de toutes les propriétés de toutes les classes pourrait prendre du temps, et même si ce n’est pas toujours de l’argent, c’est aussi le meilleur moyen de gaspiller de la RAM et de planter Windows (qui comme les grands féodaux, est fragile. Comprenne qui pourra.).

Je sais que vous mourrez d’impatience (ou d’ennui) et que vous rêvez (ou pas) de vous mettre tout de suite au WQL. Et bien c’est parti mon kiki.

Déjà, on va fermer les fenêtres (mais non, pas celle-là voyons, vous voyez bien qu’il fait chaud !) et revenir à la toute première de wbemtest, là où les boutons se sont dégrisés plus vite qu’au comico du coin. Cherchez bien et vous verrez un bouton Requête… (troisième colonne, deuxième ligne. Faut tout vous dire, hein). Cliquez dessus.

Dans le champ principal, tapez la seule requête que je vous ai appris jusqu’à présent :

Select * from Win32_ComputerSystem

Séquence émotion : votre première requête WQL

Puis cliquez sur Appliquer. Un court instant plus tard, cette fenêtre apparaît :

Et ben ? Tout ça pour ça ?

Un peu décevant, non ? Double cliquez sur la ligne Win32_ComputerSystem.Name= »lenomdevotrePC ». Rien ne se passe. Pendant que rien ne se passe, notez tout de même ce .Name= »lenomdevotrePC ». Si je vous dis que Name est une propriété de la classe Win32_ComputerSystem et que sa valeur est « lenomdevotrePC », ça vous épate hein ? Attendez encore un peu, car au moment où vous y attendrez le moins, wbemtest va ouvrir une troisième fenêtre sans crier gare… (et d’ailleurs sans crier tout court) :

C’est un Lenovo !

Voilà, on retrouve la même fenêtre que tout à l’heure mais cette fois-ci, plus de <null> (enfin beaucoup moins) et surtout je sais désormais que j’ai un Lenovo, et même que c’est un 20B7S3BR0T et… mais c’est quoi ce nom pourri ?!

Du respect des traditions informatiques

C’est là qu’arrive la sempiternelle comparaison avec une bagnole. Vous vous rappelez de la Renault 18 TL de votre papa ? (ou tonton, ou voisin, peu importe, ce n’est qu’un exemple. Mes parents avaient une 1510 GLS, mais vous vous en foutez je parie).

Bon ben là, Manufacturer c’est Renault, ok, mais si vous voyez par exemple 13400 dans Model, pas d’inquiétude, c’est ce qu’on appelle le type. Il y en a plusieurs (plein, même) pour des R18 qui se ressemblent pourtant comme deux gouttes d’eau.

Pour savoir que votre type 13400 est une R18 TL, il va falloir chercher ça ailleurs. Traduit en informatique, pour mon Lenovo 20B7quelquechose, il faut chercher la bonne propriété dans une autre classe. Et c’est là qu’on rigole.

Parce que soit vous avez de l’intuition, soit vous n’en avez pas, et donc il va falloir farfouiller dans les classes. Comme je suis sympa, je vais vous épargner ça, et vous indiquer qu’il s’agit de la propriété Version (oui bon, même avec de l’intuition c’est pas super intuitif, je vous l’accorde) de la classe Win32_ComputerSystemProduct !

On vérifie tout ça ? Allez zou, retour à la case départ, Requête, et on tape ça :

Select * from Win32_ComputerSystemProduct

On a la fenêtre de résultat, double-clic comme tout à l’heure, on attend pas deux plombes ce coup-ci et…

C’était donc un ThinkPad T440 ! Et dire que si j’avais regardé sous l’écran…

Les plus perspicaces d’entre vous auront remarqué  :

  1. Qu’on retrouve mon type 20B7trucmuche mais cette fois-ci la propriété s’appelle Name ?!
  2. Que Win32_ComputerSystem.Manufacturer ou Win32.ComputerSystemProduct.Vendor c’est kif-kif au niveau valeur mais le nom de la propriété n’a rien à voir ?!
  3. Que j’ai flouté, pixellisé et barré certaines informations sur mes captures d’écran. Et oui, la vie privée c’est important, et un simple numéro de série peut en dire tellement long sur vous… Pensez-y…

WMI a beau être la simplicitude absolue, il ne fallait pas vous attendre à trouver facilement une classe et une propriété avec le nom qui correspond au truc exact qu’on cherche intuitivement, hein ! C’est une chose à la fois frustrante mais satisfaisante, vous allez voir. Frustrante parce que vous passerez forcément des heures à chercher LA classe et LA propriété que vous vouliez. Mais satisfaisante car quand vous la trouverez, vous serez bien content !

Cela dit, avec l’habitude, on devine rapidement ce genre de piège et le temps de recherche diminue drastiquement, à tel point qu’on finit par se dire « Hé, franchement, Microsoft, trop simple, là, tu me sous-estime… ».

Conclusion

Vous savez désormais faire des requêtes WQL toutes simples. Entraînez-vous, farfouillez dans les classes à l’aide de wbemtest, et notez les classes et les propriétés qui vous intéressent, vous serez étonné de voir ce qu’on peut récupérer comme informations.

En guise de devoirs pour la prochaine fois, trouvez la classe (ou les classes) et les propriétés qui permettent d’afficher le fabricant, le modèle, le nombre de cores et la vitesse maximale du processeur de votre PC… Je corrigerai en commentaires.


Ce n’est que le deuxième article, et bam, deux acronymes dans le titre. Ça commence fort…

Acronymes et.. ah zut j’ai pas de rime

Bon, PHP, je ne vous ferai pas l’affront de dire ce que c’est. Si vous êtes venus dans ce trou perdu du web ici, c’est que vous en avez déjà entendu parler. WMI, par contre, même si vous programmez en PHP, il se peut que cela ne vous évoque rien, à fortiori si vous êtes sur Mac ou Linux.

Et oui, le W de WMI signifie Windows, et le reste (MI, donc) Management Instrumentation. En gros, il s’agit de l’implémentation à la sauce Microsoft du WBEM (rhololo, encore un acronyme à la c…), ou Web-Based Enterprise Management, sous Windows, donc. Ce qui a quelques implications du coup :

  1. Il va nous falloir une implémentation récente de PHP fonctionnant sous Windows (ça va, c’est pas trop dur à trouver)
  2. Comme je n’ai pas envie de m’emmerder avec IIS, je ne vous parlerai (très peu) d’Apache. Sous Windows.
  3. Nous aurons besoin d’une extension de PHP qui ne se trouve que… sur Windows. Et sous la forme d’une DLL
  4. Autrement dit, si vous êtes sur Mac, Linux ou autre que Windows, à part pour votre culture personnelle, cet article ne vous servira à pas grand chose.
  5. Hé tu oublies Wine ! Oui je l’oublie, car je n’ai pas la moindre idée si on peut faire du WMI avec Wine, et j’ai la flemme de chercher.
  6. Vous avez vu, j’ai encore collé deux acronymes dans les lignes précédentes, hihi !
  7. Et le mot de passe admin local de chaque PC, ou du domaine.

Le principe du WBEM (et donc de WMI) est de pouvoir accéder à des informations sur le matériel/logiciel local ou distant, pour peu que Windows soit installé dessus (mais pas n’importe quelle version de Windows : WMI est apparu avec (excusez-moi si je rigole, ce truc-là m’a toujours fait marrer) Windows Me, et n’existe donc pas sous Win95 et 98, ce qui n’est pas bien grave, vous en conviendrez).

C’est bien beau tout ça mais ça sert à quoi ?

Mettez-vous dans la peau d’un gestionnaire de parc (informatique, pas zoologique). Ce genre de personne rêve toutes les nuits (et la journée aussi) de savoir exactement et à tout moment ce qu’il possède. Pas juste le nombre de PC, non, ça il le sait, et au pire la compta a une trace des factures qu’il aura signé et oublié depuis. Non, lui, son kif c’est de savoir quels PC il a, avec quel processeur, combien de RAM, la taille des disques, la marque, le modèle, la température, les imprimantes connectées, bref il veut tout savoir. Parce que le gestionnaire de parc, c’est un peu un geek (enfin, un geek d’un genre un peu particulier cela dit).

Et bien WMI va permettre de bien l’aider (vous verrez, et cela ne se fera pas sans larmes de désespoir, je sais, je suis passé par là) mais pas totalement. Car malheureusement, vous découvrirez que même si WMI n’a rien de sorcier, il y a quelques pièges, des documentations foireuses, des propriétés manquantes et donc la désillusion n’est jamais loin. Mais dans l’ensemble, ça reste assez cool de jouer avec.

Avec WMI, on peut lire des informations sur un PC mais aussi en écrire (autrement dit, modifier les propriétés d’un objet). Je n’aborderai pas ce sujet (j’ai essayé, j’ai failli avoir des problèmes, hein). Quoi, toi, Dédé, parler d’objets ? Mais je croyais que tu haïssais la POO ?! Ben oui, mais c’est comme ça, tu peux faire de la programmation procédurale d’objets hein, ça coûte rien ! Et puis, comme vous verrez dans les exemples plus bas, on va faire dans le simple, dans le code de porc mais qui est compréhensible, bref le genre de truc qui va faire hurler les ayatollahs mais tant pis.

Certains me reprocheront peut-être de ne pas faire un cours magistral sur WMI des origines à nos jours, d’éluder certains aspects, d’ajouter de ci de là des approximations, ou d’omettre carrément des choses : je sais, j’assume. Le but de cette article est juste de vous donner envie de vous y mettre, pas de recopier tout ce qu’on trouve sur le MSDN

Bon, assez d’acronymes, on s’y met quand ?

Pas tout de suite, il y a deux-trois choses à faire avant. D’abord, vous allez vous débrouiller pour avoir un Apache et un PHP qui tournent correctement sous Windows. Prenez ce que vous voulez, personnellement je ne me casse pas la tête, un EasyPHP fait très bien l’affaire. Ça s’installe tout seul, pensez juste à avoir des droits d’admin pour le faire, ça peut servir…

Une fois que tout ça fonctionne, il va falloir éditer le fichier de configuration de PHP (notre ami php.ini), et AJOUTER la ligne suivante (tant qu’à faire, juste après les lignes similaires) :

extension=php_com_dotnet.dll

Ensuite on enregistre, on arrête/redémarre Apache et le tour est joué. J’en vois déjà qui soulèvent leur sourcil droit en lisant « com » et « dotnet » dans le nom de la DLL… Et oui, on va utiliser COM (Component Object Model), mais pas .NET (qui le remplace de fait), mais le but de cette extension est de pouvoir faire discuter PHP avec ces deux-là. Je passe les détails pénibles, sachez juste qu’on va utiliser COM, et c’est tout.

Précisons toutefois qu’il existait une classe COM dans PHP, mais que ce n’est plus le cas depuis la version 5.4 quelque chose, et qu’il faut donc charger l’extension COM/.NET. J’avais bien dit au début d’utiliser un PHP récent, hein, et pis c’est mieux, d’abord. Mais pas d’inquiétude : sur la machine sur laquelle je tape cet article, j’ai une version 5.4.24, et ça marche très bien (les autres sont en 5.6 et ça marche très bien aussi).

C’est bon là ? (et y’a plus d’acronymes ?)

Non ce n’est pas bon, encore un dernier point à voir, et si, un acronyme supplémentaire (en fait, à la réflexion, deux) : WQL. Et SQL.

Commençons par le deuxième : vous le connaissez probablement, je ne parle pas du SQLServer de Microsoft, mais bien du langage SQL, langage fort amusant s’il en est, puisqu’étant un standard, chaque éditeur de base de données a son propre dialecte, sinon ce n’est pas drôle. Si vous programmez en PHP, il y a de fortes chances que vous ayez joué avec MySQL (ou MariaDB), et vous allez voir que WQL est vraiment très proche du SQL de MySQL. Ou de SQLServer. Mais peu importe, vous allez voir c’est très simple.

Au même titre de WMI est du WBEM sauce MS, et bien WQL est du CQL goût Billou. Ce qui nous fait donc trois acronymes, qui se terminent tous par QL : Query Language. C’est ça l’important. Oui, on va faire des requêtes (queries) à WMI dans un langage qui ressemble à s’y méprendre à du SQL.

Rhaaa

Oui, ça m’a aussi fait ça la première fois. Mais c’est réellement très très simple, promis. En gros, nous allons nous connecter à WMI comme on le fait à une base de données MySQL (sauf qu’on passe par une connexion COM), et on indique dans la requête la table (en réalité, une classe) qui nous intéresse et ce qu’on veut faire avec elle. Voici un exemple de requête WQL :

Select * from Win32_ComputerSystem

Quand je vous disais que ça ressemble à du SQL… Ici notre « table » s’appelle Win32_ComputerSystem, et la requête consiste à demander tous les « enregistrements » de cette « table », c’est aussi simple que ça. Sauf qu’à la place d’un tableau (array), nous aurons en retour un objet (de type variant), pour autant que la requête ait bien été exécutée.

Au niveau de la syntaxe, peu importe la casse (vous pouvez ainsi écrire SELECT ou select ou Select), sauf pour le nom de la classe WMI. Là, gare aux fautes de frappe.

Comme n’importe quel objet, celui qui nous est retourné possède des propriétés, et ce sont elles qui nous intéressent particulièrement. Par exemple, dans cette classe Win32_ComputerSystem, on trouvera entre autres les propriétés Manufacturer ou Model, qui nous indiquerons respectivement le constructeur du PC (Lenovo, Dell, etc…) et son modèle (sauf que… pas toujours… et même jamais en fait, dans le cas de Lenovo !).

Et oui, joie et bonheur, il vous faudra assez souvent reconstituer les informations dont vous avez besoin en faisant plusieurs requêtes…

OK cool, mais on fait comment pour trouver les bonnes infos ? Faut deviner ?

Oui et non ! En fait, dans sa grande mansuétude, Microsoft offre aux développeurs deux ressources qui vont s’avérer salutaires dans bien des cas, et destructrices de cheveux dans bien des autres. Tout d’abord, le MSDN dont j’ai déjà parlé plus haut offre une documentation assez exhaustive de ce qu’on peut trouver dans les classes WMI fournies par Windows. Mais malheureusement, vous tomberez souvent sur des propriétés obsolètes (deprecated) ou carrément inexistantes sur les PC qui vous interrogerez, alors que c’était justement ça qu’il vous fallait. Enfin, certaines propriétés n’existent qu’à partir de telle ou telle version de Windows (donc ce n’est pas une mauvaise idée que de commencer par savoir à qui vous vous adressez, ça vous évitera de tenter d’obtenir une propriété fantôme…). Pour finir, certaines propriétés sont un tantinet pénibles à décoder, parce que vous devrez créer des tableaux de correspondances de valeur (ex : 0 ça veut dire ceci, 1 veut dire cela), ou vous amuser à faire un peu de logique avec des bitmasks (merci de vous abstenir de toute réflexion vaseuse quant à ce terme).

L’autre possibilité est d’utiliser l’outil wbemtest fourni gracieusement par Microsoft qui va vite devenir votre meilleur ami (si vous n’avez pas de vie sociale et que jouer avec WMI a fait naître chez vous une vocation insoupçonnée). Je reparlerai de lui dans la prochaine partie de cet article déjà fort long.

Having some spare time at work, I’ve managed to improve SponsoKilla quite a bit.

But, as this is my first post, let’s talk about SponsoKilla.

As a twitter.com user, I was more and more annoyed by those numerous promoted tweets, and jumped into the twitter.com sourcecode to find a way to get rid of them. I knew about Greasemonkey, the well-known Firefox extension, as I used it in the past for some professional projects. So I decided to write my own script. SponsoKilla was soon to be born.

So, what do you need to test it :

  1. Firefox (the latest version is always the best)
  2. Greasemonkey (the latest v… you know what I mean) : download and install from within Firefox itself
  3. SponsoKilla (the late.. ok ok, that’s obvious), which you can download here.
  4. JavaScript enabled (which should be the case by default)

Once Firefox and Greasemonkey are up and running, click on arrow near the Greasemonkey icon (that monkey face that just appeared on Firefox’s toolbar), then select Manage scripts.

Unzip SponsoKilla.zip somewhere on your disk, then grab and release SponsoKilla.user.js ONTO the Firefox window. That’s it, SponsoKilla is installed and ready to provide its magic. Then go to https://twitter.com and enjoy.

As I’m too lazy to write an entire user manual, please have a look at the source code and modify your settings. Everything is commented so it should be easy to understand.

This version allows :

  • Removal of promoted tweets
  • Removal of the trends panel
  • Removal of the suggestions panel
  • Blacklist (« mute ») specified users. They won’t be blocked, just muted (as long as SponsoKilla is used)
  • Add a background image of your choice to your twitter account or any specified user account, as Twitter removed them a few days ago. Please note that you will be the only person to see it.
  • Prevent yourself from using Twitter during the day ! Well, that’s a pretty stupid feature but I’m sure it may be of some use…

I’ve got a few ideas to improve it, but it the meantime, feel free to modify, enhance and distribute SponsoKilla.