PROJET AUTOBLOG


IT-Connect

Site original : IT-Connect

⇐ retour index

PowerShell et les boucles ForEach

lundi 4 mai 2020 à 09:10

I. Présentation

Dans la continuité de mon article précédent sur les boucles For en PowerShell, je trouvais intéressant d'en proposer un second sur les boucles ForEach car elles sont vraiment indispensables. C'est le type de boucle que j'utilise le plus dans mes scripts notamment lorsqu'il y a besoin de manipuler une collection de données. L'avantage c'est que la boucle ForEach va automatiquement traiter toutes les lignes de notre collection, il n'y a pas besoin de connaître à l'avance le nombre qu'il y en a, comme c'est le cas avec une boucle For.

Pratique et simple d'apparence, elle peut s'utiliser de différentes façons avec, à chaque fois, les spécificités qui vont avec. L'utilisation est possible directement dans la ligne de commande au sein d'une console PowerShell, mais aussi dans un script avec une syntaxe adaptée. Nous allons voir ensemble les boucles ForEach afin qu'elles n'aient plus de secret pour vous !

II. ForEach - Syntaxe n°1

Dans un script, une boucle Foreach se déclare de façon relativement simple et classique pour du PowerShell. La syntaxe d'une boucle ForEach est la suivante :

Foreach(<élément> in <collection>

   # bloc d'instructions / traitement
}

La collection correspond à notre ensemble de valeurs, représenté par une variable. Il peut s'agir du contenu d'un fichier CSV, de la liste des processus en cours d'exécution sur votre PC, du résultat du recherche d'utilisateurs dans l'Active Directory, etc... Tout ce qui permet de récupérer un ensemble de valeurs.

L'élément correspond à une variable qui va prendre pour valeur chaque objet à traiter de la collection de données. Par exemple, au premier tour de boucle, l'élément sera notre première ligne du fichier CSV, au second tour de boucle, ce sera la deuxième, etc... jusqu'à arriver à la fin du fichier. Cette variable est valide uniquement au sein de la boucle ForEach pour le traitement interne de la boucle.

Le bloc d'instructions correspond aux actions à réaliser à chaque tour de boucle sur l'objet en cours de traitement (variable de l'élément). Par exemple, si l'on utilise un fichier CSV qui contient une liste de nom et prénom, on peut imaginer que l'on va vouloir créer un utilisateur dans l'Active Directory pour chaque ligne du CSV.

Prenons un exemple : nous allons récupérer la liste des services sur notre PC (Get-Service) que l'on va stocker dans la variable $collection, et afficher l'état du service, à savoir s'il est démarré ou arrêté, avec une phrase personnalisée.

$collection = Get-Service

Foreach($element in $collection) 
{ 
   "$($element.Name) dans l'état : $($element.Status) ($($element.StartType))" 
}

J'ai utilisé les noms $element et $collection pour mes variables, mais vous pouvez utiliser d'autres noms... Le résultat contiendra le nom du service, son état actuel et son type de démarrage (manuel ou automatique).

wscsvc dans l'état : Running (Automatic)
WSearch dans l'état : Running (Automatic)
wuauserv dans l'état : Running (Manual)
WwanSvc dans l'état : Stopped (Manual)
XblAuthManager dans l'état : Stopped (Manual)
XblGameSave dans l'état : Stopped (Manual)
XboxGipSvc dans l'état : Stopped (Manual)
XboxNetApiSvc dans l'état : Stopped (Manual)

Nous aurions pu faire la même chose avec cette syntaxe :

Foreach($element in Get-Service) 
{ 
   "$($element.Name) dans l'état : $($element.Status) ($($element.StartType))" 
}

A chaque itération de la boucle ForEach, la variable $element va prendre un nouvel objet de notre collection $collection, à savoir un nouveau service. A chaque fois, il est possible d'accéder aux propriétés de l'objet et à ses méthodes. Ainsi, nous avons pu facilement récupérer le nom du service via $element.Name, ainsi que son état avec $element.Status et son type de démarrage avec $element.StartType.

Cette syntaxe est très intéressante et performante puisqu'elle permet de réaliser un ensemble d'actions sur une collection complète de données chargée au préalable dans une variable. Attention à la consommation de mémoire sur votre PC puisque l'on va charger l'intégralité de la collection en mémoire avant traitement.

III. ForEach - Syntaxe n°2

Une autre façon d'utiliser une boucle ForEach plutôt que dans un bloc dans un script, c'est directement de passer la collection d'objets à traiter à la boucle ForEach au travers d'un pipeline. Dans ce cas, la boucle ne s'appelle plus ForEach mais Foreach-Object bien que le mot clé "ForEach" fonctionne toujours, la différence est à signaler.

Pour que ce soit plus simple pour vous de comprendre la différence au niveau de la syntaxe, reprenons l'exemple précédent. Si l'on s'appuie sur une boucle Foreach-Object, et que l'on veut reproduire exactement le même résultat que précédemment, la syntaxe est la suivante :

Get-Service | Foreach-Object { "$($_.Name) dans l'état : $($_.Status) ($($_.StartType))" }

Cette syntaxe vu qu'elle tient sur une seule ligne et parfaitement adaptée à la console PowerShell. La commande Get-Service va envoyer toute sa collection d'objets à la boucle Foreach-Object qui va traiter chaque objet.

Avec cette syntaxe, nous laissons tomber notre variable $element puisque l'on peut récupérer directement l'objet en cours avec l'appel de la variable automatique : $_

Bon à savoir : au niveau de la consommation mémoire, l'impact est plus faible qu'avec la méthode précédente car on traite les objets au fur et à mesure, on ne stocke pas toute la collection d'objets dans une variable avant de la traiter. Néanmoins, cette méthode est moins efficace d'un point de vue des performances.

Enfin, il faut savoir qu'à l'instar de la commande Where-Object, la commande Foreach-Object propose elle aussi une syntaxe simplifiée. Si l'on souhaite afficher seulement un champ, avec la syntaxe complète on doit écrire :

Get-Service | Foreach-Object { $_.Name }

Avec la syntaxe simplifiée (qui limite les possibilités), cela donne :

Get-Service | Foreach Name

Vous avez désormais connaissance des deux syntaxes possibles pour une boucle ForEach en PowerShell, avec les avantages et inconvénients de chaque méthode. Si vous souhaitez calculer les différences au niveau des performances, vous pouvez vous amuser avec la commande Measure-Command 😉

📌 Comment créer son premier script PowerShell ?

Si vous avez des questions ou une remarque, pensez à laisser un commentaire sur cet article.