Ça y est, Powershell est arrivé sur Mac et Linux, et en Open Source ! La transition opérée par Microsoft en la matière depuis quelques années ne cessera de me surprendre. Quoiqu’il en soit, c’est une excellente nouvelle.

L’installation de Powershell est assez simple, il suffit de se rendre sur la page des Releases sur GitHub, et de récupérer le package qui va bien (à l’heure actuelle, il s’agit de Powershell v6 en alpha. A vos risques et périls, donc). Les instructions pour l’installer sont très simples, et comme je n’ai pas envie de faire de plagiat un samedi à l’heure de l’apéro, je vous invite à consulter cette page chez Howtogeek.

Une fois que vous l’aurez installé, il faut lancer Powershell depuis une fenêtre de terminal, en tapant la commande… powershell. Ce qui n’est pas bien compliqué.

Lire la suite de

Pas de panique, je suis informaticien professionnel, restez calme, ayez confiance M’ame Michu.

Le 29 juillet (hier) était donc la date de lancement mondial de Windows 10. Les ambitions de Microsoft sont d’avoir 1 milliard de PC équipés de Windows 10 d’ici deux à trois ans. Vaste programme, car les entreprises ont déjà souffert du passage de XP à Seven (et ça a coûté un fric monstre, en remplacement de matériel et en prestation), et ne sont pas prêt de recommencer, d’autant plus que la fin du support étendu est prévu (à ce jour) au 14 janvier 2020. Quant à Windows 8 (et 8.1), rares sont les entreprises – à part les TPE/PME qui se fournissent chez Darty – qui en sont équipées.

Cela dit, pour ceux disposant d’un PC compatible (c’est-à-dire pas trop pourri) et ayant une copie licite et activée de Windows 7 SP1 ou de Windows 8.x, la mise à jour est gratuite pendant un mois, pour peu qu’ils aient réservé leur copie de Windows 10 au préalable, via l’appli « Obtenez Windows 10 » qui s’est sournoisement installée via Windows Update.

Oui mais voilà. Les Mme Michu sont légion, et bien qu’elles pardonnent et oublient, ce sont bien souvent des quiches en informatique (ça vaut aussi pour les M. Michu, pas de sexisme ici), et la mise à jour vers Windows 10, censée se passer comme une lettre à la Poste, risque de leur poser quelques soucis (à moins que Microsoft trouve une solution fiable entre temps).

La méthode officielle pour passer à Windows 10 est… d’attendre. Et oui. En fait, Windows 10 est déjà plus ou moins téléchargé sur votre PC depuis quelques jours. A compter du 29 juillet, vous êtes censé recevoir une notification de l’appli « Obtenir Win 10 » vous disant que c’est prêt, vous pouvez lancer la mise à jour etc. Je suis un garçon trèèèèèèès patient sauf lorsqu’il s’agit d’ordinateurs. J’ai donc décidé de gagner un peu de temps hier soir, sauf que j’en ai perdu (et j’en avais déjà perdu en prenant la ligne 1 du métro dans le mauvais sens… à ma décharge, j’avais quelques préoccupations en tête et le nez sur l’écran de mon téléphone, et ce n’est qu’une fois arrivé à Bastille que je me suis rendu compte de ma bourde).

Si vous me suivez sur Twitter (@delateuranonyme), vous avez peut-être lu mes quelques tweets relatant mon expérience hier soir et cette nuit. Je me devais d’apporter quelques précisions.

J’avais donc conseillé pour les plus impatients (conseil que je m’étais appliqué à moi-même) d’ouvrir une fenêtre de ligne de commande en tant qu’administrateur (sous Windows 8.1 : clic droit sur le « menu Démarrer » puis Ligne de commande (admin), ça c’est pratique), puis de taper la commande :

wuauclt.exe /updatenow

Cela permet de forcer Windows Update, et donc de télécharger les 2,7 Go (dans mon cas, visiblement la taille varie en fonction de votre PC) de Windows 10. La patience étant une vertu (c’est mon fils qui dit ça, lui qui ne l’est pas du tout !), vous allez devenir extrêmement vertueux grâce à Microsoft…

Déjà le téléchargement prend un certain temps (en fonction de votre connexion à Internet bien sûr, mais aussi de la charge des serveurs de Microsoft), mais la phase « Préparation pour l’installation » aussi. A un certain stade, ça n’avance plus du tout. Soyez patient. Très patient. Ca finira par aller jusqu’au bout. Et jusqu’à une belle erreur comme sait si bien les faire Microsoft.

Un coup d’oeil dans l’historique de Windows Update, et c’est l’erreur 0x80240020 qui apparaît. Si vous faites un tour sur les divers sites, forums, Twitter et j’en passe, ils vous conseilleront tous d’aller dans le répertoire C:WindowsSoftwareDistributionDownload et de supprimer tout ce qui s’y trouve (ou des variantes du genre supprimer aussi le contenu du répertoire
C:WindowsSoftwareDistributionDataStore, ou de renommer
C:WindowsSoftwareDistribution, d’arrêter/relancer le service Windows Update (net stop wuauserv puis net start wuauserv..).

Sur le principe ce n’est pas idiot du tout, ça permet de relancer le téléchargement de la mise et… bah au final, il y a de fortes chances que l’erreur  0x80240020 revienne. Et au bout de la troisième fois, on trouve ça pénible.

Donc ne perdez pas votre temps. Si vous tenez absolument à mettre à jour votre PC, utilisez l’utilitaire mis à disposition par Microsoft. Mais au préalable, faites ces manipulations :

  1. Lancez Windows Update et mettez à jour votre PC avec tous les patches proposés (je ne parle pas de l’installation de Windows 10, mais les bons vieux KB habituels)
  2. Redémarrez (ça ne fait jamais de mal et vous verrez que certains patches ne s’installent qu’au reboot)
  3. Téléchargez l’outil de création de média là, en prenant la version correspondant à votre système (32 ou 64 bits) : https://www.microsoft.com/fr-fr/software-download/windows10
  4. Lancez-le
  5.  Au choix, créez un média (clé USB ou DVD) ou faites carrément la mise à jour (ce que j’ai fait)

L’outil va télécharger Windows 10 (et c’est reparti pour un temps indéfini d’attente). Hier soir, en regardant le débit Ethernet de ma Freebox, le téléchargement tournait en moyenne à 180 ko/s, avec parfois des pointes à 1 Mo… Bon c’était hier soir cette nuit et je ne devais pas être tout seul à télécharger…

Mais finalement, tout s’est bien passé et l’installation a commencé. Pour cette partie, vous n’avez quasiment rien à faire, Microsoft vous conseille même de vous caler dans votre fauteuil et de vous détendre. Prenez un bon bouquin et attendez que ça se passe. Votre PC va rebooter deux-trois fois, parfois ne va rien afficher pendant de longues secondes… pas d’inquiétude, c’est normal, là encore soyez patient. Sur mon PC, équipé d’un SSD, cela a pris une bonne demi-heure, comptez un peu plus si vous avez un disque dur.

Profitez du temps d’installation pour lire et relire cet article sur Next INpact si vous avez une tablette ou un autre ordinateur, car à la fin de l’installation, lors de la phase de configuration, vous aurez quelques choix particulièrement importants en matière de vie privée.

Une fois tout ceci terminé, vous découvrirez le nouvel écran de connexion de Windows 10. Je passe sur l’évolution de l’interface, c’est similaire à Windows 8.1 mais en mieux (mais pas forcément beaucoup plus joli à mon avis), le menu Démarrer est de retour, etc etc.

Même si vous aviez une version licite et activée de Windows, sachez que la clé d’enregistrement (la Product Key) a changé lors de la mise à jour. Résultat, vous devez réactiver votre licence. Pour cela, cliquez sur le menu Démarrer, allez dans Paramètres, puis dans Mise à jour et sécurité. Enfin, cliquez sur Activation. Cliquez pour finir sur le bouton Activer.

Et là, patatras, il y a de fortes chances que ça ne marche pas, car là aussi vous n’êtes pas tout seul à tenter d’activer Windows, et donc les serveurs sont encombrés. Si vous obtenez un message comme quoi vous devez vous connecter à internet, et si en regardant dans les détails le code d’erreur 0xC004F034, voici une astuce bizarre MAIS efficace. Testée et approuvée par votre serviteur et plusieurs autres personnes… Cela peut paraître étonnant (et ça l’est), mais il faut cliquer comme un fou, en continu, sans interruption, sur le bouton Activer, même lorsque le bouton est grisé et que l’animation « tourne ». Miraculeusement, et malgré plusieurs tentatives préalables lamentablement ratées, votre copie va s’activer. Ça a l’air dingue, mais ça marche !

La preuve !

Voilà, j’espère que ces quelques lignes vous permettront de faire la mise à jour sans trop galérer. Rappel des points importants :

  1. mettez à jour votre PC avec Windows Update et rebootez. Prévoyez 30 à 40 Go d’espace libre sur votre disque C: (donc faites un peu de ménage)
  2. gagnez du temps, utilisez directement la méthode de l’outil de création de médias
  3. faites attention à votre vie privée, relisez l’article de Next INpact indiqué plus haut
  4. allez faire un tour dehors, il fait beau

 

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 https://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 https://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 https://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 !