Identifier un moniteur en WMI avec PowerShell (et PHP si le coeur vous en dit)

J’ai cherché un bon bout de temps avant de le trouver, celui-là. Mais mon abnégation étant sans limite (hmm…), je n’ai pas lâché l’affaire jusqu’à ce que je trouve LA requête WMI qui va bien. Faisons ça en Powershell (vous pourrez facilement adapter ça en PHP si vous avez lu mes autres articles sur WMI).

Jusqu’à présent, pour savoir quel(s) moniteur(s) est/sont connecté(s) à un PC, j’utilisais la requête WQL suivante :

Select * from Win32_DesktopMonitor

Traduit en Powershell :

$Computer = "Nova"
$ColItems = Get-WmiObject -Class Win32_DesktopMonitor -Namespace "root\cimv2" -Computer $Computer
$ColItems

Ce qui me donne quelque chose dans ce genre, pour chaque écran :

DeviceID            : DesktopMonitor1
DisplayType         :
MonitorManufacturer : (Types d’écrans standard)
Name                : Moniteur Plug-and-Play générique
ScreenHeight        :
ScreenWidth         :

DeviceID            : DesktopMonitor2
DisplayType         :
MonitorManufacturer :
Name                : Écran par défaut
ScreenHeight        :
ScreenWidth         :

Ah bah super, je vais aller loin avec ça moi. Alors d’une, le PC sur lequel j’écris cet article n’a qu’un moniteur, puisqu’il s’agit de la dalle LCD de mon laptop. Le deuxième doit être une réminiscence d’une ancienne connexion à un second moniteur…

Comme vous le savez, on peut se connecter à un PC distant, d’où la variable $Computer. Mettez-y le nom de la machine sur laquelle vous souhaitez obtenir des informations.

Avec cette commande, vous POUVEZ avoir la résolution de l’écran. Ça marche quand ça veut cela dit, je m’attendais à obtenir une valeur de 900 pour la propriété ScreenHeight, et 1600 pour ScreenWidth, puisque ma dalle affiche du 1600×900 pixels. Sur certains PC, j’ai les bonnes valeurs, sur d’autres rien, nada.

Et je n’ai de toutes façons JAMAIS la marque et le modèle du moniteur.

J’ai donc été voir ailleurs si je trouvais plus d’infos :

$Computer = "Nova"
$ColItems = Get-WmiObject -Class Win32_PnPEntity -Namespace "root\cimv2" -Computer $Computer -filter "Service like '%monitor%'"
$ColItems

(J’ai mis le filtre « Service like « %monitor% » parce que c’est justement ce qui m’intéresse, et je n’ai pas envie de tout voir. Dédéastuce du jour : retirez le filtre pour voir TOUS les périphériques connectés au PC).

L’exécution de ces quelques lignes me sort ceci :

__GENUS                     : 2
__CLASS                     : Win32_PnPEntity
__SUPERCLASS                : CIM_LogicalDevice
__DYNASTY                   : CIM_ManagedSystemElement
__RELPATH                   : Win32_PnPEntity.DeviceID= »DISPLAY\CMN1728\4&28D17A0&0&UID265988″
__PROPERTY_COUNT            : 26
__DERIVATION                : {CIM_LogicalDevice, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                    : NOVA
__NAMESPACE                 : rootcimv2
__PATH                      : \NOVArootcimv2:Win32_PnPEntity.DeviceID= »DISPLAY\CMN1728\4&28D17A0&0&UID265988″
Availability                :
Caption                     : Moniteur Plug-and-Play générique
ClassGuid                   : {4d36e96e-e325-11ce-bfc1-08002be10318}
CompatibleID                : {*PNP09FF}
ConfigManagerErrorCode      : 0
ConfigManagerUserConfig     : False
CreationClassName           : Win32_PnPEntity
Description                 : Moniteur Plug-and-Play générique
DeviceID                    : DISPLAYCMN17284&28D17A0&0&UID265988
ErrorCleared                :
ErrorDescription            :
HardwareID                  : {MONITORCMN1728}
InstallDate                 :
LastErrorCode               :
Manufacturer                : (Types d’écrans standard)
Name                        : Moniteur Plug-and-Play générique
PNPClass                    : Monitor
PNPDeviceID                 : DISPLAYCMN17284&28D17A0&0&UID265988
PowerManagementCapabilities :
PowerManagementSupported    :
Present                     : True
Service                     : monitor
Status                      : OK
StatusInfo                  :
SystemCreationClassName     : Win32_ComputerSystem
SystemName                  : NOVA
PSComputerName              : NOVA

Ah c’est déjà plus intéressant tout ça. J’aime particulièrement la ligne HardwareID : {MONITORCMN1728}, même si CMN1728 ça ne me dit trop rien. Et il y a PNPDeviceID : DISPLAYCMN17284&28D17A0&0&UID265988 qui a l’air prometteur aussi…

Le problème, c’est que testé avec d’autres moniteurs, les codes ne me disent pas grand chose. Je vois du LEN ou du DEL à la place de CMN, évidemment ça évoque Lenovo et Dell, mais sans plus de précisions, ça ne m’avance guère.

Je farfouille, je passe des heures sur le technet, et puis soudain apparaît un namespace évocateur : root/WMI. Je continue de farfouiller et tombe sur la classe WmiMonitorID. Comme ça me plaît bien, je modifie un peu mon script :

$Computer = "Nova"
$ColItems = Get-WmiObject -Namespace "ROOT\WMI" -ComputerName $computer -Query "SELECT * FROM WmiMonitorID"
$ColItems

Et là, paf :

__GENUS                : 2
__CLASS                : WmiMonitorID
__SUPERCLASS           : MSMonitorClass
__DYNASTY              : MSMonitorClass
__RELPATH              : WmiMonitorID.InstanceName= »DISPLAY\CMN1728\4&28d17a0&0&UID265988_0″
__PROPERTY_COUNT       : 9
__DERIVATION           : {MSMonitorClass}
__SERVER               : NOVA
__NAMESPACE            : ROOTWMI
__PATH                 : \NOVAROOTWMI:WmiMonitorID.InstanceName= »DISPLAY\CMN1728\4&28d17a0&0&UID265988_0″
Active                 : True
InstanceName           : DISPLAYCMN17284&28d17a0&0&UID265988_0
ManufacturerName       : {67, 77, 78, 0…}
ProductCodeID          : {49, 55, 50, 56…}
SerialNumberID         : {48, 0, 0, 0…}
UserFriendlyName       :
UserFriendlyNameLength : 0
WeekOfManufacture      : 50
YearOfManufacture      : 2011
PSComputerName         : NOVA

Tiens tiens, cet InstanceName : DISPLAYCMN17284&28d17a0&0&UID265988_0 me rappelle furieusement le (PnP)DeviceID de Win32_PnpEntity, avec _0 en plus cela dit…

Bon par contre, ManufacturerName ne m’afficherait pas un peu de la merde, là ? Je m’attendais à voir quelque chose de lisible, et pour UserFriendlyName aussi (bon là c’est vide, mais avec d’autres moniteurs, on voit aussi les tableaux de nombres du style {67, 77, 78, 0…}…). Je me creuse la tête, et je me dis que ça ne m’étonnerais pas que chaque nombre = le code ASCII d’un caractère. Je tente donc une petite conversion : 67, c’est C majuscule, 77 c’est M majuscule, 78 c’est évidemment N… (oui je parle ASCII couramment… nan, en vrai, je sais seulement que le code ASCII de A c’est 65, que 32 c’est un espace, et deux-trois autres codes. Ensuite, je déduis en descendant l’alphabet, c’est aussi simple que ça). Sur d’autres ManufacturerName je me rends compte que les codes 00 ne servent à rien, je décide donc des les supprimer, mais comme il s’agit de tableaux et non de chaîne, pas de bol, on ne peut pas se servir de la méthode Trim(), snif. Je bricole donc ceci :

foreach($ch in $ColItems.ManufacturerName) {
           if($ch -ne '00') {
                    $manufacturer += [char]$ch
                }
            }

Pour résumer en langage humain : pour chaque code ASCII du tableau contenu dans $ColItems.ManufacturerName, si le code n’est PAS 00, j’ajoute le CARACTERE ayant le code ASCII $ch à ma variable chaîne $manufacturer.

Ce qui me donne comme prévu « CMN ». Youpi. J’ai une dalle fabriquée par CMN.

Je fais pareil pour la propriété UserFriendlyName et là paf : CMN1728. J’ai donc une dalle CMN1728 (de 17 »), utilisée par beaucoup de fabricants de laptop (Lenovo, Dell, Sony, Asus, Toshiba et la liste est probablement incomplète).

Evidemment, pour d’autres moniteurs, ça devient carrément plus sympa puisqu’ENFIN, j’ai le modèle du moniteur. Pour la marque par contre, je n’ai toujours que les trois premières lettres : LEN et DEL par exemple… Bon pas grave, je devrais réussir à me débrouiller pour faire la correspondance.

Notez que pour l’instant, le script se contrefous de savoir si vous avez plusieurs écrans. Il suffit de faire une petite boucle pour chaque objet dans $ColItems, dans ce style :

foreach ($item in $ColItems)
    {
        foreach($ch in $item.ManufacturerName) {
           if($ch -ne '00') {
                    $Manufacturer += [char]$ch
                }
            }
        # faire pareil pour les autres propriétés contenant des tableaux de codes ASCII

        # récupérer les valeurs des autres propriétés sans traitement, comme par exemple
        $YearOfManufacture = $item.YearOfManufacture

        # et afficher le tout tant qu'à faire
       $Manufacturer
       $YearOfManufacture
} #et on recommence tant qu'il y a des écrans

Voilà. Vous pouvez ainsi identifier les moniteurs connecté à n’importe quel PC de votre réseau. Pour ce qui est d’adapter ça en PHP, il suffit de se connecter au bon namespace (root/WMI), d’exécuter la requête WQL SELECT * FROM WmiMonitorID et de récupérer les valeurs de chaque propriété. Pour convertir le code ASCII en caractère, c’est évidemment chr($ch) que vous utiliserez.

Montre ton amour pour Dédé en partageant cet article !

Laisser un commentaire