Windows PowerShellThéorie des chaînes

Don Jones

Sommaire

Une situation réelle
Correspondances complexes
Un monde rempli de chaînes

Lorsque j'interviens dans des conférences, comme Tech•Ed ou TechMentor, je m'habitue à proclamer certaines choses — des annonces générales qui aident les utilisateurs à se rappeler les points clés de Windows PowerShell par exemple. La dernière en date était : « Si vous traitez une chaîne dans Windows PowerShell, quelque chose ne va pas ».

En effet, je considère Windows PowerShell™ comme un shell orienté objet. Si, par exemple, vous transférez des listes de services dans un fichier texte et que vous traitez ce dernier pour voir quels services ont été démarrés, vous en faites trop. Cette approche est valide dans un système d'exploitation textuel comme UNIX, mais Windows PowerShell (de même que Windows® lui-même) vous permet d'utiliser les objets d'une façon bien plus efficace.

Même vos propres scripts devraient produire des objets, non pas du texte formaté, pour que les divers formatages, filtrages, exportations et autres commandes du shell puissent être utilisés afin de manipuler la sortie de vos scripts. (Lisez mon article de juillet 2008 sur Windows PowerShell pour en savoir plus sur la notion d'objets personnalisés, comme la sortie de script).

Lors d'un récent TechMentor à Orlando, en Floride, l'un de mes étudiants m'a rappelé que presque toutes les règles, en particulier les règles générales, ont des exceptions. « Pourquoi ne pas trouver des éléments dans un fichier journal IIS ? Vous ne devez pas analyser le texte dans ce cas ? »

Oui, en effet. Et heureusement, même s'il est très facile à utiliser avec des objets, Windows PowerShell peut aussi traiter des chaînes de texte. Et maintenant que vous le dites, les fichiers journaux IIS, les fichiers journaux de pare-feu et les autres journaux textuels en sont des exemples parfaits.

Une situation réelle

J'ai déjà dû traiter une série de fichiers journaux de pare-feu pour une entreprise qui m'embauchait. On avait découvert un employé qui regardait certains sites Web inappropriés et dans le cadre de l'enquête de suivi, le service des Ressources humaines avait besoin d'une liste exhaustive des sites Web qu'il avait consultés. S'il est un peu délicat d'extraire le fichier journal d'un jour donné, le service RH voulait remonter jusqu'à plusieurs semaines — ce que je n'avais pas envie de faire manuellement.

Le serveur DHCP (Dynamic Host Configuration Protocol) de l'entreprise indiquait que l'ordinateur de l'employé avait utilisé la même adresse IP (disons 192.168.17.54 pour donner un exemple) depuis plusieurs mois. Cela n'est bien sûr pas surprenant, puisqu'il s'agissait d'un ordinateur de bureau qui était rarement éteint. Et puisque le journal de pare-feu conservait une liste des adresses IP source, j'ai vu que Windows PowerShell pourrait être utile.

Le secret réside dans la commande, souvent négligée, Select-String. Vous devrez également connaître les expressions régulières (que j'ai abordées dans l'article de novembre 2007 sur Windows PowerShell).

La commande Select-String accepte les chemins d'accès remplis de fichiers textuels, les expressions régulières ou les simples chaînes. Elle fera alors sortir chaque ligne de chaque fichier journal correspondant à l'expression régulière ou à la chaîne simple. Pour commencer, j'ai simplement voulu obtenir chaque ligne contenant l'adresse IP de l'ordinateur de bureau de l'employé. Chaque ligne de fichier journal contenait une date et un horodatage, exactement ce que recherchait le service RH.

Voici la commande :

select-string -path c:\logs\*.txt -pattern "192.168.17.54" 
-allmatches –simplematch

Le paramètre –simpleMatch spécifie que le modèle fourni est juste une simple chaîne, pas une expression régulière. La figure 1 affiche une partie de la sortie, qui pourrait également être rattachée à un fichier. Il est important de noter que la sortie inclut le nom de fichier et le numéro de la ligne où la correspondance a été trouvée, ce qui peut être très utile si vous voulez revenir en arrière à un moment donné pour rechercher plus d'informations.

Cmdlet du mois : Start-Sleep

Voici une cmdlet qui vous apporte exactement ce dont vous avez besoin en plein milieu d'une longue journée de travail — une petite sieste. Start-Sleep offre une pause rapide — pour les scripts Windows PowerShell, évidemment.

Il n'est pas rare d'avoir besoin d'une pause rapide dans un script. Par exemple, admettons que vous ayez besoin de démarrer un service, d'attendre quelques secondes pour qu'il se mette en route, puis d'effectuer d'autres tâches qui dépendent de ce service. Start-Sleep est exactement ce qu'il vous faut dans ce cas. Exécuter Start-Sleep 10, par exemple, mettra le shell en pause pendant 10 secondes. Si vous avez besoin d'un contrôle plus précis, vous pouvez exécuter Start-Sleep -milli 100, par exemple, pour pauser pendant 100 millisecondes. Start-Sleep suspend totalement le shell, y compris les scripts, les canaux et tout ce qui reste, pendant la durée spécifiée. Si seulement quelqu'un pouvait maintenant écrire cette cmdlet Start-Nap que je recherche depuis si longtemps.

fig01.gif

Figure 1 Sortie d'une commande Select-String (cliquer sur l'image pour l'agrandir)

Correspondances complexes

Après avoir fourni aux personnes du service RH ce qui était demandé, elles se sont rendu compte que ce n'était pas ce qu'elles voulaient. Mon rapport comprenait des visites à de nombreuses adresses IP, comme 207.68.172.246 (le site Web de MSN®). La demande suivante de l'enquêteur était d'affiner mon rapport pour n'inclure que les visites à une adresse IP spécifique, qu'ils avaient identifiée comme appartenant à un des sites Web en question. Je ne révélerai pas dans cet article la véritable adresse IP mentionnée dans l'enquête. J'utiliserai à la place 207.68.172.246 pour cet exemple (bien que le site Web de MSN ne soit généralement pas considéré comme inapproprié).

Cette demande aurait pu être un peu plus difficile. Dans le fichier journal sur lequel je travaillais, les adresses IP de source et de destination étaient juste à côté l'une de l'autre et séparées par une virgule. Je pouvais donc simplement modifier ma chaîne de recherche en « 192.168.17.54,207.68.172.246 » et répéter la recherche.

Cependant, un fichier journal plus complexe pourrait contenir des données variables enregistrées entre les deux adresses IP. Une simple correspondance de chaînes ne suffirait alors pas. Dans ce cas, vous devriez recourir à une expression régulière, qui fonctionne également bien sur les formats de journaux plus simples, thème que je vais maintenant aborder.

Dans une expression régulière, le point remplace n'importe quel caractère. Je peux également utiliser la sous-expression (.)* pour rechercher un nombre de caractères donné entre mes deux adresses IP. Cependant, il est nécessaire d'utiliser une barre oblique inverse pour ignorer les points qui apparaissent dans les adresses IP.

La commande qui en résulte est :

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

J'ai supprimé le paramètre –simpleMatch puisque j'utilise cette fois une expression régulière. La sortie en résultant affichait seulement les visites de l'ordinateur de l'employé en question sur le site Web identifié comme inapproprié. Elle incluait également les informations de date et d'horodatage dont l'enquêteur avait besoin. La figure 2 montre une partie de la sortie que vous pouvez obtenir lorsque vous exécutez une commande comparable.

fig02.gif

Figure 2 Résultats de recherche affinés n'affichant que les visites sur un site spécifique (cliquer sur l'image pour l'agrandir)

Mais je peux aller un peu plus loin et rattacher la sortie à Format-Table afin d'afficher des colonnes calculées. Je peux faire en sorte que le tableau comprenne le nom du fichier journal et le numéro de la ligne où la correspondance a été trouvée. Je peux même afficher la ligne correspondante elle-même. Cependant, je peux indiquer au shell de remplacer la correspondance de l'expression régulière avec une chaîne vide pour n'afficher que le reste de la ligne — la date et l'horodatage dans mon exemple. Il s'agit d'une astuce de niveau avancé, mais elle démontre un peu plus comment Windows PowerShell peut manipuler des données de chaînes et produire des sorties hautement personnalisées, le tout dans une seule ligne de commande :

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | 
ft  filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto

La figure 3 montre le possible aspect de mes résultats finaux.

fig03.gif

Figure 3 Sortie formatée provenant d'une commande Select-String (cliquer sur l'image pour l'agrandir)

Un monde rempli de chaînes

Proclamer que la nature orientée objet de Windows PowerShell est l'une de ses plus grandes forces est peut-être un peu rapide. Mais il y a néanmoins des situations où les objets ne conviennent pas.

Windows PowerShell réside peut-être dans un monde orienté objet. Heureusement, l'équipe de Windows PowerShell a reconnu que votre monde contient fréquemment des données externes sous forme de chaînes formatées. Elle a donc inclus la commande Select-String. Avec cette commande et une connaissance des expressions régulières, vous pouvez utiliser Windows PowerShell pour écrire des commandes unilignes qui traiteront les chaînes les plus complexes qui soient.

Don Jones est coauteur de Windows PowerShell: TFM et auteur de douzaines d'autres ouvrages informatiques. Contactez-le sur son blog à www.concentratedtech.com.