Windows PowerShell Du beau boulot

Don Jones

Il n'est pas rare de souhaiter que des scripts produisent un résultat attrayant et l'on me demande souvent quelle est la meilleure façon de produire des choses telles que des tableaux. Il existe en fait deux façons d'y parvenir. La première étape consiste à écrire un script qui place les données que je souhaite afficher de façon formatée dans des variables appelées

$data1, $data2 et $data3. À présent, je peux passer au formatage des données.

La méthode texte

Sur le Web

Vous cherchez une démonstration rapide des techniques abordées dans l'article Windows PowerShell de ce mois-ci ? Visitez le site technetmagazine.com/video pour voir comment Don Jones utilise ces applets de commande.

En général, les gens tentent de réaliser cette tâche de la même façon que s'ils travaillaient dans un langage tel que VBScript, Perl, KiXtart ou un autre langage orienté texte. Je vais peut-être commencer par écrire une série d'en-têtes de colonnes à l'écran :

Write-Host "ColumnA'tColumnB'tColumnC"

Notez que `t est une séquence d'échappement spéciale dans Windows PowerShellTM qui insère un caractère de tabulation. Pour écrire chaque ligne de mon tableau, sans oublier que mes données sont dans $data1, $data2 et $data3, je dispose de plusieurs choix. L'un consiste simplement à écrire les variables, en comptant sur la capacité du shell à remplacer les variables par leurs contenus entre guillemets doubles :

Write-Host "$data1't$data2't$data3"

Une autre méthode légèrement plus attrayante pour y parvenir utilise l'opérateur –f. Cette technique sépare le formatage des données et produit ce qui est, selon moi, une ligne de code plus facile à lire et à gérer :

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

Cette approche pose cependant des problèmes importants. Tout d'abord, en comptant sur les taquets de tabulation fixes de la fenêtre de console, je peux m'attendre à des formatages étranges. Par exemple, si une ligne de tableau particulière a une valeur de 20 caractères dans la première colonne, je vais mettre en l'air tout le formatage de la ligne. De plus, comme j'obtiens ce texte via Write-Host, je suis quasiment limité à un affichage de console.

Il n'y a pas de méthode facile pour envoyer ce résultat vers un fichier ou pour le mettre dans d'autres formats, si jamais je le souhaitais. Plus important encore, cette approche basée sur le texte ignore complètement le shell basé sur les objets dans lequel je travaille. Elle ne tire pas parti des techniques et fonctionnalités incroyables qu'offre Windows PowerShell.

La méthode Windows PowerShell

Windows PowerShell est un shell orienté objets. Ceci signifie, dans l'idéal, que tout ce avec quoi vous travaillez doit se trouver dans des objets, ce qui permet au shell de transformer les choses en affichages texte lorsque c'est nécessaire. Mais comment créer des objets pour des éléments de données arbitraires ?

En gardant le même exemple, je commence par créer un objet personnalisé vide que j'enregistre dans une variable :

 $obj = New-Object PSObject

Ceci me donne un nouvel objet vide à utiliser. J'ajoute ensuite mes données à l'objet sous la forme de propriétés. Pour ce faire, il me suffit de canaliser mon objet vers l'applet de commande Add-Member. J'ajoute quelque chose appelé NoteProperty, je donne un nom à la propriété (je vous recommande d'utiliser les en-têtes de colonnes comme noms de propriétés), puis j'insère les données comme valeurs des propriétés :

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

À présent, je génère cet objet, pas sur la console, mais sur le pipeline :

Write-Output $obj

Je peux ensuite répéter alors ces étapes pour chacune des lignes de tableau que j'ai besoin de générer. Voici une fonction courte qui accepte une chaîne et génère une version en majuscules et en minuscules, ainsi que la chaîne originale :

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

Je commence par un tableau de variables de chaînes, que j'envoie une par une à la fonction. Et le résultat de la fonction est écrit dans le pipeline.

Notez qu'il y a des méthodes plus courtes pour écrire ce code, mais j'ai choisi cette technique parce qu'elle illustre clairement ce que je cherche à vous montrer. Le résultat, illustré à la figure 1, est un tableau parfaitement formaté. C'est parce que le shell sait déjà formater des objets dans un tableau.

Figure 1 Résultats Windows PowerShell affichés dans un tableau

Figure 1 Résultats Windows PowerShell affichés dans un tableau (Cliquez sur l'image pour l'agrandir)

Quand un objet a quatre propriétés (ou moins), Windows PowerShell choisit automatiquement un tableau. Ainsi, sans aucun travail de ma part, j'ai maintenant un superbe tableau.

Mais attendez, ce n'est pas tout !

Applet de commande du mois Get-Command

Je suis sûr que vous avez déjà utilisé Get-Command, ou son alias pratique (gcm), une fois ou deux pour passer en revue la liste d'applets de commande Windows PowerShell disponibles. Mais peut-être n'êtes-vous pas conscient de la flexibilité de gcm ? Ainsi, si vous voulez voir tout ce que Windows PowerShell peut faire avec un service, exécutez le service gcm-noun. Et si vous souhaitez voir toutes les options d'exportation Windows PowerShell, essayez l'exportation gcm -verb. Si vous avez juste besoin de voir quelles applets de commande ont été ajoutées par un composant logiciel enfichable particulier (par exemple PowerShell Community Extensions), essayez gcm -pssnapin pscx. (Vous pouvez remplacer « pscx » par n'importe quel nom de composant logiciel enfichable pour voir les applets de commande de ce composant logiciel enfichable).

Comme vous pouvez le voir, Get-Command joue un rôle primordial dans la détectabilité de Windows PowerShell. Elle vous permet de savoir quelle fonctionnalité est disponible sans avoir à consulter un manuel. Et notez que gcm représente une façon plus précise de découvrir des fonctionnalités que l'utilisation d'une commande telle que Help *. La fonction Help répertorie uniquement les rubriques d'aide disponibles. Toutes les applets de commande non accompagnées d'une aide n'y sont pas répertoriées, bien que les applets de commande soient à votre disposition si vous en avez besoin.

L'avantage de cette technique s'étend bien au-delà des tableaux. Lorsque vous travaillez avec des objets, Windows PowerShell sait comment faire une énorme quantité de choses. Vous souhaitez que vos données soient dans un fichier CSV ? Utilisez Export-CSV. Vous préférez un tableau HTML ? Transférez vos objets dans ConvertTo-HTML. Vous avez besoin d'un format de liste ? Transférez-les dans Format-List. En utilisant des objets, vous pouvez utiliser toutes les choses que le shell sait déjà faire. Voici un exemple révisé :

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

Cette fois, j'ai modifié la fonction pour accepter les entrées de pipeline. C'est toujours préférable lorsque vous travaillez avec des objets et pour effectuer la sortie sur le pipeline.

Cette fonction a maintenant son code à l'intérieur d'un scriptblock PROCESS. Ceci signifie que cette fonction acceptera les entrées de pipeline et qu'elle exécutera le scriptblock PROCESS une fois pour chaque objet transféré.

À l'intérieur du scriptblock PROCESS, la variable spéciale $_ se réfère à l'objet de pipeline actuel en cours de traitement. Résultat pratique : à présent, je peux simplement transférer un ensemble de chaînes :

@("one","two","three") | StringVersions

J'obtiens un tableau parce que la fonction met son résultat dans le pipeline. À la fin du pipeline, le shell sait qu'il doit appeler son sous-système de formatage, qui prend la décision d'utiliser un tableau parce que les objets du pipeline ont moins de cinq propriétés (pour plus de propriétés, le shell utilisera une liste par défaut).

Mais je ne suis pas obligé de compter sur le comportement par défaut. Je peux simplement transférer ces objets vers une autre applet de commande pour en faire autre chose :

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

La figure 2 montre le code HTML résultant du second exemple affiché dans un navigateur Web. En représentant simplement mes données de sortie dans des objets, plutôt qu'en tant que texte simple, j'ai maintenant un accès complet à de nombreuses fonctionnalités qui sont intégrées dans le shell : toute une gamme de dispositions de format, conversion HTML, options d'exportation, la possibilité de trier, filtrer et regrouper et bien plus encore.

Figure 2 Sortie de données Windows PowerShell au format HTML

Figure 2 Sortie de données Windows PowerShell au format HTML (Cliquez sur l'image pour l'agrandir)

C'est très puissant. En fait, j'irai même jusqu'à suggérer que chacun des scripts que vous écrivez produise un objet comme résultat afin que vous puissiez utiliser ce résultat d'autant de façons différentes possibles, le tout sans avoir à écrire une seule ligne de code supplémentaire.

Don Jonesest un expert dans l'automatisation administrative de Windows et a rédigé des ouvrages tels que Windows PowerShell: TFM and VBScript, WMI, and ADSI Unleashed. Vous pouvez le contacter par l'intermédiaire des forums du site ScriptingAnswers.com.

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