about_ForEach

Mis à jour: mai 2014

S'applique à: Windows PowerShell 2.0, Windows PowerShell 3.0, Windows PowerShell 4.0, Windows PowerShell 5.0

RUBRIQUE

about_Foreach

DESCRIPTION COURTE

Décrit une commande de langage que vous pouvez utiliser pour parcourir tous les éléments d'une collection d'éléments.

DESCRIPTION DÉTAILLÉE

L'instruction Foreach (également appelée "boucle Foreach") est une construction de langage qui permet d'exécuter pas à pas (par itération) une série de valeurs dans une collection d'éléments.

Le type de collection à parcourir le plus simple et le plus courant est le tableau. Dans une boucle Foreach, il est courant d'exécuter une ou plusieurs commandes sur chaque élément d'un tableau.

Syntaxe

La syntaxe ForEach est la suivante :

          foreach ($<item> in $<collection>){<statement list>}

Syntaxe simplifiée

À compter de Windows PowerShell® 3.0, la syntaxe comportant des mots clés de langage, tels que Where et ForEach, a été simplifiée. Les opérateurs de comparaison qui sont exécutés sur les membres d'une collection sont traités comme des paramètres. Vous pouvez utiliser une méthode sur les membres d'une collection sans l'inclure dans un bloc de script ni ajouter la variable automatique "$_.". Prenons les deux exemples suivants :

          dir cert:\ -Recurse | foreach GetKeyAlgorithm
          dir cert:\ -Recurse | foreach {$_.GetKeyAlgorithm()}

Bien que les deux commandes fonctionnent, la première retourne les résultats sans utiliser de bloc de script ni la variable automatique $_.. La méthode GetKeyAlgorithm est traitée comme un paramètre de ForEach. La première commande retourne les mêmes résultats, mais sans erreur, car la syntaxe simplifiée n'essaie pas de retourner des résultats pour les éléments auxquels l'argument spécifié ne s'applique pas.

Dans cet exemple, la propriété Get-Process Description est passée comme argument de paramètre de l'instruction ForEach. Les résultats correspondent aux descriptions de processus actifs.

          Get-Process | ForEach Description

Instruction Foreach en dehors d'un pipeline de commande

La partie de l'instruction Foreach placée entre parenthèses représente une variable et une collection à itérer. Windows PowerShell crée automatiquement la variable ($<item>) quand la boucle Foreach est exécutée. Avant chaque itération dans la boucle, la variable est définie sur une valeur de la collection. Le bloc qui suit une instruction Foreach {<statement list>} contient un ensemble de commandes à exécuter sur chaque élément d'une collection.

Exemples

Par exemple, la boucle Foreach de l'exemple suivant affiche les valeurs dans le tableau $letterArray.

        
          $letterArray = "a","b","c","d"
          foreach ($letter in $letterArray)
          {
              Write-Host $letter
          }

Dans cet exemple, le tableau $letterArray est créé et initialisé avec les valeurs de chaîne "a", "b", "c" et "d". Quand l'instruction Foreach est exécutée pour la première fois, elle définit la variable $letter comme étant égale au premier élément de $letterArray ("a"). Ensuite, elle utilise l'applet de commande Write-Host pour afficher la lettre a. Lors de l'itération suivante, $letter sera défini sur "b", et ainsi de suite. Après l'affichage de la lettre d, Windows PowerShell arrête la boucle Foreach.

L'instruction Foreach doit apparaître sur une seule ligne pour être exécutée en tant que commande à l'invite de commandes Windows PowerShell. Elle n'a pas à s'afficher sur une seule ligne si vous placez la commande dans un fichier de script .ps1.

Les instructions Foreach peuvent également être utilisées avec des applets de commande qui retournent une collection d'éléments. Dans l'exemple suivant, l'instruction Foreach exécute pas à pas la liste d'éléments qui est retournée par l'applet de commande Get-ChildItem.

          foreach ($file in Get-ChildItem)
          {
              Write-Host $file
          }

Vous pouvez affiner l'exemple à l'aide d'une instruction If pour limiter les résultats retournés. Dans l'exemple suivant, l'instruction Foreach effectue la même opération de boucle que dans l'exemple précédent. Toutefois, une instruction If y est ajoutée pour limiter les résultats aux fichiers dont la taille est supérieure à 100 Ko :

          foreach ($file in Get-ChildItem)
          {
              if ($file.length -gt 100KB) 
              {
                  Write-Host $file
              }
          }

Dans cet exemple, la boucle Foreach utilise une propriété de la variable $file pour effectuer une opération de comparaison ($file.length -gt 100KB). La variable $file contient toutes les propriétés de l'objet qui est retourné par l'applet de commande Get-ChildItem. Par conséquent, vous pouvez retourner plus qu'un nom de fichier. Dans l'exemple suivant, Windows PowerShell retourne la durée et l'heure du dernier accès à la liste d'instructions :

          foreach ($file in Get-ChildItem)
          {
              if ($file.length -gt 100KB) 
              {
                  Write-Host $file
                  Write-Host $file.length
                  Write-Host $file.lastaccesstime
              }
          }

Dans cet exemple, vous n'êtes pas limité à l'exécution d'une commande unique dans une liste d'instructions.

Vous pouvez également utiliser une variable en dehors d'une boucle Foreach et incrémenter la variable à l'intérieur de la boucle. L'exemple suivant comptabilise les fichiers dont la taille est supérieure à 100 Ko :

          $i = 0
          foreach ($file in Get-ChildItem)
          {
              if ($file.length -gt 100KB) 
              {
                  Write-Host $file "file size:" ($file.length / 
          1024).ToString("F0") KB
                  $i = $i + 1
              }
          }
          if ($i -ne 0)
          {
              Write-Host
              Write-Host $i " file(s) over 100 KB in the current 
          directory."}
          else 
          {
              Write-Host "No files greater than 100 KB in the current 
          directory."
          }

Dans l'exemple précédent, la variable $i est définie sur 0 à l'extérieur de la boucle, et la variable est incrémentée à l'intérieur de la boucle pour chaque fichier dont la taille est supérieure à 100 Ko. Quand la boucle s'arrête, l'instruction If évalue la valeur de $i pour afficher le nombre de fichiers de plus de 100 Ko. Sinon, elle affiche un message indiquant qu'aucun fichier de plus de 100 Ko n'a été trouvé.

L'exemple précédent montre également comment mettre en forme les résultats relatifs à la longueur des fichiers :

          ($file.length / 1024).ToString("F0")

La valeur est divisée par 1 024 pour afficher les résultats en kilo-octets plutôt qu'en octets, et la valeur résultante est ensuite mise en forme à l'aide du spécificateur de format à virgule fixe pour supprimer les valeurs décimales du résultat. Avec le 0, le spécificateur de format n'affiche pas de décimales.

Instruction Foreach dans un pipeline de commande

Quand l'instruction Foreach apparaît dans un pipeline de commande, Windows PowerShell utilise l'alias Foreach, qui appelle la commande ForEach-Object. Quand vous utilisez l'alias Foreach dans un pipeline de commande, vous n'incluez pas la syntaxe ($<item> dans $<collection>) comme pour une instruction Foreach, car la commande précédente du pipeline fournit ces informations. Quand elle est utilisée dans un pipeline de commande, la syntaxe de l'alias ForEach est la suivante :

          <command> | foreach {<command_block>}

Par exemple, la boucle Foreach de la commande suivante affiche les processus dont la plage de travail (utilisation de la mémoire) est supérieure à 20 mégaoctets (Mo).

La commande Get-Process obtient tous les processus de l'ordinateur. L'alias Foreach exécute les commandes du bloc de script sur chaque processus, les unes après les autres.

L'instruction If sélectionne les processus dont la plage de travail est supérieure à 20 Mo. L'applet de commande Write-Host écrit le nom du processus, suivi de deux-points. Elle divise la valeur de la plage de travail (qui est stockée en octets) par 1 mégaoctet pour obtenir la valeur de la plage de travail en mégaoctets. Elle convertit ensuite le double en une chaîne. Elle affiche la valeur sous la forme d'un nombre à virgule fixe avec zéro décimale (F0), un espace de séparation (" "), puis "Mo".

          Write-Host "Processes with working sets greater than 20 MB."
          Get-Process | foreach { 
             if ($_.WS -gt 20MB)
             { Write-Host $_.name ": " ($_.WS/1MB).ToString("F0") MB -Separator ""}
          }

L'alias Foreach prend également en charge les blocs de commandes de début, les blocs de commandes de milieu et les blocs de commandes de fin. Les blocs de commandes de début et de fin ne sont exécutés qu'une seule fois, alors que le bloc de commandes de milieu est exécuté chaque fois qu'une boucle Foreach itère une collection ou un tableau.

Quand la syntaxe de l'alias Foreach est utilisée dans un pipeline de commande avec un ensemble de blocs de commandes de début, de milieu et de fin, elle se présente comme ceci :

          <command> | foreach {<beginning command_block>}{<middle 
          command_block>}{<ending command_block>}

L'exemple suivant illustre l'utilisation des blocs de commandes de début, de milieu et de fin.

          Get-ChildItem | foreach {
          $fileCount = $directoryCount = 0}{
          if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{
          "$directoryCount directories and $fileCount files"}

Le bloc de début crée, puis initialise deux variables vers la valeur 0 :

          {$fileCount = $directoryCount = 0}

Le bloc de milieu détermine si chaque élément retourné par Get-ChildItem est un répertoire ou un fichier :

          {if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}

Si l'élément retourné est un répertoire, la variable $directoryCount est incrémentée de 1. Si l'élément n'est pas un répertoire, la variable $fileCount est incrémentée de 1. Le bloc de fin est exécuté une fois terminée l'opération de boucle du bloc de milieu et une fois retournés les résultats de l'opération :

          {"$directoryCount directories and $fileCount files"}

Vous pouvez réécrire l'exemple précédent afin de rechercher tous les fichiers dont la taille est supérieure à 100 Ko en utilisant la structure de blocs de commandes de début, de milieu et de fin, et l'opérateur de pipeline. Pour cela, procédez comme suit :

          Get-ChildItem | foreach{
              $i = 0}{
              if ($_.length -gt 100KB)
              {
                  Write-Host $_.name "file size:" ($_.length / 
          1024).ToString("F0") KB
                  $i++
              }
              }{
              if ($i -ne 0)
              {
                  Write-Host
                  Write-Host "$i file(s) over 100 KB in the current 
          directory."
              }
              else 
              {
              Write-Host "No files greater than 100 KB in the current 
          directory."}
              }

L'exemple suivant (une fonction qui retourne des fonctions utilisées dans des scripts et des modules de script) montre comment utiliser la méthode MoveNext (qui fonctionne de manière similaire à "skip X" dans une boucle For) et la propriété Current de la variable $foreach dans un bloc de script Foreach, même s'il existe des définitions de fonction espacées de manière inhabituelle ou incohérente qui s'étendent sur plusieurs lignes pour déclarer le nom de la fonction. L'exemple fonctionne également s'il existe des commentaires dans les fonctions utilisées dans un script ou un module de script.

         function Get-FunctionPosition {
             [CmdletBinding()]
             [OutputType('FunctionPosition')]
             param(
                 [Parameter(Position=0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
                 [ValidateNotNullOrEmpty()]
                 [Alias('PSPath')]
                 [System.String[]]
                 $Path
             )
             process {
                 try {
                     $filesToProcess = if ($_ -is [System.IO.FileSystemInfo]) {
                         $_
                     } else {
                         Get-Item -Path $Path
                     }
                     foreach ($item in $filesToProcess) {
                         if ($item.PSIsContainer -or $item.Extension -notin @('.ps1','.psm1')) {
                             continue
                         }
                         $tokens = $errors = $null
                         $ast = [System.Management.Automation.Language.Parser]::ParseFile($item.FullName,([REF]$tokens),([REF]$errors))
                         if ($errors) {
                             Write-Warning "File '$($item.FullName)' has $($errors.Count) parser errors."
                         }
                         :tokenLoop foreach ($token in $tokens) {
                             if ($token.Kind -ne 'Function') {
                                 continue
                             }
                             $position = $token.Extent.StartLineNumber
                             do {
                                 if (-not $foreach.MoveNext()) {
                                     break tokenLoop
                                 }
                                 $token = $foreach.Current
                             } until ($token.Kind -in @('Generic','Identifier'))
                             $functionPosition = [pscustomobject]@{
                                       Name = $token.Text
                                 LineNumber = $position
                                       Path = $item.FullName
                             }
                             Add-Member -InputObject $functionPosition -TypeName FunctionPosition -PassThru
                         }
                     }
                 } catch {
                     throw
                 }
             }
         }

VOIR AUSSI

about_Automatic_Variables

about_If

ForEach-Object