Les boucles

Qu’est-ce qu’une boucle ?

Une boucle en programmation permet de répéter des opérations ou traitements sur des valeurs, avec ou sans conditions. La répétition d’une ou plusieurs actions dans un bloc d’instructions est une notion clé.

Voici les différentes structures qui nous permettent une répétition en PowerShell :

  • For

  • Foreach

  • While

  • Do-While

  • Do-Until

La boucle For

1. Signification

La boucle For permet de répéter x fois un bloc d’instructions. On peut la comprendre comme : « pour une valeur comprise entre X et Y, exécuter ces instructions »".

2. Utilisation

Lors de l’utilisation de cette boucle, nous indiquerons :

  • une valeur de départ d’une variable ;

  • une condition de répétition de la boucle ;

  • le pas d’incrémentation (la valeur dont elle est augmentée à chaque itération).

La syntaxe de la boucle For est la suivante :

For (<initialisation de la variable> ; <condition> ; <incrément>) 
{ 
   #bloc d'instructions 
} 

Afin d’illustrer la boucle For, nous allons écrire dix « le nombre est ... ».

For ($i=0 ; $i -le 10 ;$i++) 
{ 
  Write-host "le nombre est $i" 
} 
images/17RI04.png

La boucle Foreach

1. Signification

Cette structure signifie  : «  pour chaque élément d’une collection, exécuter ces instructions ».

À la différence d’une boucle for où nous devons préciser le nombre de fois où sera répété notre code, la boucle ForEach permettra de traiter toutes les occurrences contenues dans une collection de valeurs.

Cette collection de valeurs peut provenir :

  • d’un fichier ou de son contenu ;

  • du résultat d’une commande ;

  • du contenu d’une variable.

2. Utilisation

a. Première syntaxe

Foreach($item in $collection) 
{ 
   #Bloc d'instructions 
   #ici nous devons utiliser la variable $item 
}  

Prenons l’exemple suivant :

Nous souhaitons récupérer la liste des services sur notre PC. La cmdlet à utiliser sera Get-Service. Nous procéderons comme ci-dessous :

  • Nous stockerons son résultat dans la variable $collection.

  • Nous afficherons l’état du service (démarré ou arrêté).

  • Nous ajouterons une phrase personnalisée.

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

La boucle While

1. Signification

Cette condition pourrait se traduire par « tant que cela est vrai, alors je fais ça ». Les instructions contenues dans le bloc d’instructions de cette boucle sont répétées tant que la condition de la boucle est vraie. Cela signifie que dès que la condition est évaluée à la valeur $false, l’exécution de la boucle est terminée.

2. Utilisation

La syntaxe d’une boucle While est la suivante :

While (<conditions à évaluer>) 
{ 
    #Instructions PowerShell | cmdlets 
} 

Prenons un exemple pour afficher les dix premiers nombres décimaux.

PS C:\Users\Jerome> $i=1 
PS C:\Users\Jerome> while($i -le 10){ 
>> Write-Output "la valeur de i : $i" 
>> $i++ 
>> } 
la valeur de i : 1 
la valeur de i : 2 
la valeur de i : 3 
la valeur de i : 4 
la valeur de i : 5 
la valeur de i : 6 
la valeur de i : 7 
la valeur de i : 8 
la valeur de i : 9 
la valeur de i : 10 
PS C:\Users\Jerome> 

Nous avons bien le résultat escompté et remarquons qu’une fois que notre boucle à atteint la valeur 10, la boucle est terminée.

La boucle Do-While

1. Signification

Cette boucle ressemble au fonctionnement du While excepté que la condition est évaluée après l’exécution du bloc d’instructions.

2. Utilisation

La syntaxe de la boucle Do-While est la suivante :

Do 
{ 
   #Instructions PowerShell | cmdlets 
 
} 
While (<conditions à évaluer>) 

Nous souhaitons ici incrémenter une variable $i de 1 tant qu’il y a un processus "notepad" en cours d’exécution sur la machine.

Start-Process notepad 
$i = 0 
Do{ 
 
    $i++ 
    Write-Host $i 
 
}While(Get-Process -Name notepad -ErrorAction SilentlyContinue) 
 
Write-Host "Notepad est bien fermé, on peut continuer !" 

Quelques explications sont nécessaires :

  • Dans un premier temps, le script lance l’application Notepad.

  • Nous initialisons la variable $i à zéro.

  • Nous exécutons les premières instructions du bloc.

  • La boucle sera stoppée une fois que le processus Notepad n’existera plus ; autrement dit, lorsque nous fermerons l’application Notepad. Dans la commande Get-Process, nous remarquons le paramètre -ErrorAction SilentlyContinue, qui nous permet de ne pas afficher d’erreur dans la console quand le processus sera introuvable...

La boucle Do-Until

1. Signification

Cette boucle se traduit par « faire ceci jusqu’à ce que… ». Avec cette structure, nous bouclons jusqu’à ce que la condition de sortie soit évaluée à vrai ($true). C’est donc l’inverse de la boucle Do-While.

2. Utilisation

Reprenons l’exemple du While en ajoutant une seconde variable et une autre condition dans la condition de test. Le but est de sortir de la boucle lorsqu’une des deux variables arrive à 10.

$i = 0 
$j = 4 
Do{ 
 
    $i++ 
    $j = $j + 2 
    Write-Host "i = $i et j = $j" 
 
}Until(($i -eq 10) -or ($j -eq 10)) 
 
Write-Host "Une des deux variables est arrivée à 10 donc on sort  
de la boucle !" 
images/17RI02.png

Une fois que la variable $j a atteint la valeur 10, la boucle s’arrête.

Nous allons maintenant fixer la valeur de $j à 5 et observer le comportement.

images/17RI03.png

Cette fois, la variable $j n’atteint jamais la valeur 10 mais la dépasse. La boucle ne s’arrête donc que lorsque $i est égale à 10.

Jusqu’à présent nous avons travaillé avec Windows PowerShell en 5.1. Cependant PowerShell 7, sorti en février 2020, introduit une nouvelle fonctionnalité pour les boucles...

Comparaison des deux boucles

1. Boucle traditionnelle ForEach

Afin de comprendre l’avantage de la parallélisation avec PowerShell 7, nous allons tout d’abord utiliser une boucle simple affichant des valeurs et faisant une pause entre chaque itération :

1..10 | ForEach-Object {  
"Passage dans la boucle $_" 
Start-Sleep -Seconds 1  
} 

Il peut être très intéressant de comparer le temps d’exécution de ce code en fonction de la version PowerShell.

Pour cela, nous utiliserons la commande Measure-command qui retournera le temps d’exécution exprimé en secondes :

(Measure-command {1..10 | ForEach-Object {  
"Passage dans la boucle $_" 
Start-Sleep -Seconds 1  
} 
}).seconds 

Ci-dessous le résultat retourné :

images/NRI18_01M2.png

Le temps d’exécution est de 10 secondes, car chaque élément est traité séquentiellement.

2. Boucle ForEach parallélisée

Pour voir les avantages de Powershell 7 sur cette parallélisation, nous allons utiliser le paramètre -Parallel avec le même code et observer les différences.

Nous allons également mesurer le temps d’exécution, comme précédemment :

(Measure-command {1..10 | ForEach-Object -Parallel {  
"Passage dans la boucle $_" 
Start-Sleep -Seconds 1  
} 
}).seconds 

Le temps d’exécution est maintenant de 2 secondes.

Son exécution montre les premiers avantages de cette parallélisation, le temps d’exécution a été divisé par cinq.

images/NRI18_02M2.png

Un autre paramètre nommé -ThrottleLimit indique le nombre de scripts blocs à exécuter en même temps par défaut. Cette valeur est égale à 5, ce qui explique que dans notre résultat le temps a été divisé par deux.

Nous pouvons essayer de réduire encore le temps d’exécution...