Windows PowerShellLa boîte

Don Jones

Sommaire

Soyez l'applet de commande
La fonction de filtrage
Pensez physique
Applications pratiques
Prenez le temps de jouer

Dans un des cours Windows PowerShell que je donnais récemment, certains étudiants avaient du mal à visualiser le rôle du pipeline du shell. J'admets que le pipeline n'est pas totalement intuitif dans la conception, par conséquent cela peut être très difficile pour les étudiants d'imaginer ce qui se passe exactement. Lorsque je suis arrivé au

concept des fonctions de filtrage, qui fonctionne directement dans le pipeline, les choses obtenues vraiment permanentes, et en regardant leurs visages, je pouvais dire que je perdais quelques étudiants.

Pour essayer de les aider, je suis arrivé le lendemain avec une boîte, des autocollants de noms et des balles de ping-pong. (Personne n'a dit qu'on ne peut pas s'amuser en faisant du Windows PowerShell®). J'ai décidé de faire une démonstration en utilisant la ligne de commande suivante :

Get-Process | Where { $_.VM –gt 1000 } | Sort VM
–descending | Export-CSV C:\Procs.csv

Soyez l'applet de commande...

L'utilisation des autocollants de noms, vous savez, les autocollants « Bonjour, je m'appelle …» que vous devez toujours porter aux réunions d'école et à des événements similaires redoutés, j'ai attribué un nom de cmdlet à chaque étudiant. J'ai expliqué que les balles de ping-pong représentaient les objets de processus Windows® (plus précisément, les objets de type System.Diagnostics.Process), puis j'ai demandé aux étudiants de me dire quel nom de cmdlet semblait plus susceptible de générer des objets de processus.

En regardant les balises des autres, ils se sont décidés pour le choix évident de Get-Process. Cela démontre l'une des principales raisons pour lesquelles j'aime vraiment les noms de cmdlet utilisés dans Windows PowerShell : ils sont généralement très évidents.

Donc l'étudiant présentant Get-Process a pris toutes les balles de ping-pong et les a déposées dans le carton. La boîte représente le pipeline du shell et ce que l'étudiant a fait est à peu près ce que fait une cmdlet. Une cmd­let génère un ou plusieurs objets et les dépose dans le pipeline.

La cmdlet suivante dans le pipeline prend ensuite le relais. Dans cet exemple, l'étudiant représentant la cmdlet Where-Object a pris toutes les balles de ping-pong et les a examinées une par une, vérifiant si une propriété VM d'une balle donnée était supérieure à 1 000. Dans le shell, « VM » correspond à mémoire virtuelle et, pour cet exercice, j'avais écrit avec un marqueur les différentes quantités de mémoire virtuelle sur chaque balle de ping-pong.

Chaque balle (processus) ayant une VM de 1 000 ou supérieure est retournée dans la boîte (parfois appelée pipeline), alors que celles ayant une valeur inférieure étaient déposées dans une corbeille, pour ne jamais les revoir. (En fait, cela n'est pas vrai, je les ai récupérées pour les utiliser dans mes futurs cours).

Ensuite, l'étudiant représentant Sort-Object a examiné la boîte de balles de ping-pong et les a mis dans l'ordre, en fonction de leurs propriétés VM. Je dois admettre que cette partie de l'exercice n'a pas été bien pensée, car empêcher les balles de rouler partout était un peu difficile ! Je dois trouver des cubes de ping-pong pour mon prochain cours ou avoir des boîtes d'œufs à portée de main.

Enfin, l'étudiant jouant avec Export-CSV a pris les balles et a écrit les informations dans un fichier CSV. Physiquement, cela se traduit par l'écriture des propriétés du processus sur un tableau à feuilles mobiles qui représentait un fichier CSV.

La fonction de filtrage

Le pipeline étant traité, nous avons décidé d'examiner les fonctions de filtrage, qui sont un peu plus compliquées. J'ai proposé la fonction de filtrage et la ligne de commande illustrée à la figure 1.

Figure 1 Exemple de fonction de filtrage et de ligne de commande

Function Do-Something {
 BEGIN { }
 PROCESS {
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty "TimeStamp" (Get-Date)
  $obj | Add-Member NoteProperty "ProcessName" ($_.Name)
  Write-Output $obj
 }
 END {}
}
Get-Process | Do-Something | Format-Table *

Tout d'abord, je souhaite passer rapidement en revue ce que les fonctions de filtrage sont susceptibles de faire. L'idée est que cette fonction contient trois blocs de script, nommés BEGIN, PROCESS et END.

Lorsque la fonction est utilisée dans le pipeline, le bloc de script BEGIN est exécuté en premier, Ce script peut effectuer n'importe quelle tâche de configuration, comme l'ouverture d'une connexion de base de données.

Ensuite, le bloc de script PROCESS s'exécute une fois pour chaque objet qui a été transmis dans cette fonction. Dans le bloc de script PROCESS, la variable $_ est automatiquement peuplée avec l'objet de pipeline actuel. Donc, si 10 objets sont transmis, le bloc de script PROCESS s'exécute 10 fois.

Donc, après l'exécution de tous les objets transmis, le bloc de script END s'exécute et effectue toutes les tâches de nettoyage nécessaires, comme la fermeture d'une connexion de base de données.

Dans n'importe lequel de ces blocs de script, tout ce qui est écrit à l'aide de Write-Output se retrouve dans le pipeline pour la cmdlet suivante. Tout ce qui n'est pas écrit à l'aide de Write-Output est rejeté.

Puisque notre commande a démarré avec Get-Process, notre premier étudiant a rassemblé toutes les balles de ping-pong (nous avions fait une courte pause et les balles avaient été lancées avec espièglerie à travers la pièce, imaginez un peu) et les a déposées dans la boîte de pipeline. À la fin de cette tâche, l'étudiant représentant la fonction de filtrage Do-Something a ensuite pris le relais.

Il a d'abord exécuté son bloc de script BEGIN. Comme c'était vide, cela n'a pas nécessité beaucoup d'effort. Puis il a pris tous les objets pipeline (les balles de ping-pong) et a commencé à les examiner un par un. C'était assez amusant, car il y avait une douzaine de balles et il essayait de les garder en équilibre sur ses genoux, il fallait être là pour voir ça !

En tout cas, il a pris les objets de processus un par un et a exécuté son bloc de script PROCESS. Ce bloc de script lui a permis de créer un objet personnalisé tout neuf. (J'ai utilisé les balles de ping-pong jaunes spéciales pour cela, et ne croyez pas qu'elles étaient faciles à trouver dans le magasin d'articles de sport local). Sur ces nouvelles balles de ping-pong, il a inscrit la date et l'heure actuelle avec le nom de l'objet de processus qu'il examinait actuellement.

Ce nouvel objet personnalisé a ensuite été écrit dans le pipeline, ce qui signifie que la balle de ping-pong jaune a été placée dans la boîte et que la balle de ping-pong d'objet de processus original a été rejetée. Il a fait de même pour chaque balle de ping-pong d'objet de processus qui était dans la boîte, environ 12 au total. Lorsque c'était terminé, chaque balle de ping-pong blanche a été remplacée par une balle de ping-pong d'objet personnalisé jaune. Enfin, il a exécuté son bloc de script END, qui était vide et n'a pas pris de temps.

Pour terminer, notre étudiant Format-Table a pris le relais. Elle a tout pris dans la boîte, des objets « personnalisés » jaunes à ce stade et a commencé à construire une table, utilisant les deux propriétés écrites sur chaque balle. Le résultat était une table, écrite sur notre tableau à feuilles mobiles, avec deux colonnes, TimeStamp et ProcessName et d'une douzaine de lignes.

Pensez physique

Cet exercice a vraiment facilité les fonctions de filtrage et de pipeline pour tous les étudiants du cours. Les balles de ping-pong ont permis de représenter les objets, qui ont tendance à être un peu abstraits lorsque vous parlez simplement du shell.

Tout le monde pouvait voir comment les cmdlets ont manipulé ces objets, comment les résultats ont été placés dans le pipeline et comment la cmdlet suivante a pris ces résultats et a encore manipulé les objets. La séquence d'événements dans une fonction de filtrage était plus évidente, comme l'était la technique du bloc de script PROCESS permettant de fonctionner avec un objet d'entrée à la fois.

Cela a démontré également les moyens par lesquels un nouvel objet personnalisé peut être créé et placé dans le pipeline. De plus, il aide à démontrer les avantages de produire des objets personnalisés par opposition au texte simple, les nouveaux objets de coutume pouvaient être utilisés par d'autres cmdlets, comme Format-Table, offrant beaucoup de souplesse dans la manière dont les données pouvaient être ensuite utilisées et représentées.

Applications pratiques

La question évidente des étudiants était comment le pipeline et ces fonctions de filtrage que nous venons de présenter peuvent-ils être utilisés dans les applications pratiques. La réponse était facile pour moi, car j'avais créé plusieurs exemples pour une session de conférences récente (vous pouvez télécharger les exemples à l'adresse scriptinganswers.com/essentials/index.php/2008/03/25/techmentor-2008-san-francisco-auditing-examples).

Un des exemples a pour objectif de répertorier plusieurs propriétés de la classe Win32_UserAccount dans Windows Management Instrumentation (WMI) à partir de plusieurs ordinateurs. En supposant que les noms d'ordinateur sont répertoriés dans C:\Computers.txt, cette commande simple effectuera la tâche :

Gwmi win32_useraccount –comp (gc c:\computers.txt)

Le problème est que la classe Win32_UserAccount n'inclut pas de propriété qui indique de quel ordinateur provient chaque instance, donc la liste résultante sera un mélange inutile de comptes provenant de nombreux ordinateurs. Je résous le problème en créant un nouvel objet personnalisé qui inclut le nom de l'ordinateur d'origine et sélectionne les propriétés de classe qui m'intéressent. Le code de cet objet personnalisé est illustré à la figure 2.

Figure 2 Utilisation d'un objet personnalisé pour collecter des noms d'ordinateur et sélectionner des propriétés

function Get-UserInventory {
  PROCESS {
    # $_ is a computer name
    $users = gwmi win32_useraccount -ComputerName $_
    foreach ($user in $users) {
      $obj = New-Object
      $obj | Add-Member NoteProperty Computer $_
      $obj | Add-Member NotePropertyPasswordExpires ($user.PasswordExpires)
      $obj | Add-Member NoteProperty Disabled ($user.Disabled)
      $obj | Add-Member NotePropertyFullName ($user.FullName)
      $obj | Add-Member NoteProperty Lockout ($user.Lockout)
      $obj | Add-Member NoteProperty Name ($user.Name)
      $obj | Add-Member NotePropertyPasswordRequired ($user.PasswordRequired)
      $obj | Add-Member NotePropertyPasswordChangeable ($user.PasswordChangeable)
    }
  }
}

Get-Content c:\computers.txt | 
  Get-UserInventory | 
  where { $_.PasswordRequired -eq $False } | 
  selectComputer,Name | 
  Export-Csv c:\BasUsersBad.csv

La ligne de commande finale transmet tous les noms d'ordinateur à la fonction de filtrage, ce qui génère des objets personnalisés. Ensuite j'ai éliminé tous les utilisateurs sauf ceux dont la propriété PasswordRequired est False (l'idée est de générer un rapport d'audit de comptes à problèmes). Alors je garde simplement les propriétés Computer et Name, donc le rapport final est une liste de noms d'ordinateur et de noms de compte qui nécessitent de l'attention car ils ont des mots de passe sans délai d’expiration. La fonction de filtrage permet d'obtenir un rapport multi-ordinateur car il ajoute le nom d'ordinateur d'origine aux résultats tout en ne laissant que les propriétés que je souhaite voir.

Même s'il existe des façons similaires de réaliser cette tâche, cette approche est peut-être la plus directe. Elle permet également d'illustrer des techniques et des concepts importants.

Prenez le temps de jouer

Même si vous êtes à l'aise avec le pipeline, il y a une leçon à tirer ici. Penser en termes d'objets physiques peut vous aider à déterminer ce que vous essayez de faire.

Donc la prochaine fois que vous aurez des difficultés avec un concept Windows PowerShell, essayez de vous écarter de l'ordinateur et de copier la tâche en utilisant des objets de tous les jours comme illustration. Je recommande humblement que vous gardiez à portée de main un petit sac de balles de ping-pong (ou des cubes, si vous pouvez en trouver) uniquement dans ce but.

Applet de commande du mois Out-File

Combien de fois avez-vous dirigé le résultat d'une cmdlet vers un fichier à l'aide du symbole > ? C'est quelque chose comme Get-Process > Processes.txt. Savez-vous que vous utilisez en réalité la cmdlet Out-File ? Voici une commande qui exécute la même fonction : Get-Process | Out-File Processes.txt.

Bien sûr, cela nécessite de taper un peu plus, alors pourquoi s'ennuyer à taper la cmdlet Out-File en entier ? Une raison est que Out-File est beaucoup plus clair lorsqu'il est lu. Quelqu'un venant dans, disons, six mois peut regarder un de vos scripts et se demander ce que signifie > (c'est, après tout, une sorte d'héritage).

Par contre, avec Out-File, il est assez évident qu'un fichier sera créé et écrit. De plus, Out-File vous donne le paramètre -append (à peu près identique à >>), ainsi que les paramètres -force et -noClobber, vous permettant de contrôler si les fichiers existants sont remplacés. Enfin, taper Out-File vous donne également accès au paramètre -whatif. Ce paramètre pratique affichera ce que Out-File fera, sans le faire réellement ! C'est un bon moyen de tester une ligne de commande sans danger.

Don Jones est coauteur de Windows PowerShell: TFM et donne des cours Windows PowerShell (www.ScriptingTraining.com).

© 2008 Microsoft Corporation et CMP Media, LLC. Tous droits réservés. Toute reproduction, totale ou partielle, est interdite sans autorisation préalable.