about_ForEach

Aplica-se a: Windows PowerShell 2.0, Windows PowerShell 3.0, Windows PowerShell 4.0, Windows PowerShell 5.0

TÓPICO

about_Foreach

DESCRIÇÃO BREVE

Descreve um comando de linguagem que você pode usar para percorrer todos os itens em uma coleção de itens.

DESCRIÇÃO LONGA

A instrução Foreach (também conhecida como um loop Foreach) é uma construção de linguagem para percorrer (iteração) uma série de valores em uma coleção de itens.

O tipo mais simples e mais comuns de coleção para atravessar é uma matriz. Em um loop Foreach, é comum executar um ou mais comandos em cada item em uma matriz.

Sintaxe

O código a seguir mostra a sintaxe de ForEach:

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

Sintaxe simplificada

Desde o Windows PowerShell® 3.0, a sintaxe com as palavras-chave da linguagem, como Where e ForEach, foi simplificada. Operadores de comparação que funcionam nos membros de uma coleção são tratados como parâmetros. Você pode usar um método nos membros de uma coleção sem contê-lo em um bloco de script ou adicionar a variável automática "$_.". Considere os dois exemplos a seguir:

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

Embora ambos os comandos funcionem, o primeiro retorna resultados sem usar um bloco de script ou a variável automática $_. O método GetKeyAlgorithm é tratado como um parâmetro de ForEach. O primeiro comando retorna os mesmos resultados, mas sem erros, porque a sintaxe simplificada não tenta retornar resultados para os itens para os quais não aplicou o argumento especificado.

Neste exemplo, a descrição da propriedade Get-Process é passada como um argumento de parâmetro da instrução ForEach. Os resultados são as descrições dos processos ativos.

          Get-Process | ForEach Description

A instrução Foreach fora de um pipeline de comando

A parte da instrução Foreach entre parênteses representa uma variável e uma coleção para iterar. Windows PowerShell criará a variável ($<item>) automaticamente quando o loop Foreach for executado. Antes de cada iteração pelo loop, a variável é definida como um valor na coleção. O bloco que segue uma instrução Foreach {<statement list>} contém um conjunto de comandos a serem executados em cada item em uma coleção.

Exemplos

Por exemplo, o loop Foreach no exemplo a seguir exibe os valores na matriz $letterArray.

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

Neste exemplo, a matriz $letterArray é criada e inicializada com os valores de cadeia de caracteres "a", "b", "c" e "d". Na primeira vez em que a instrução Foreach é executada, ela define a variável $letter igual ao primeiro item na $letterArray ("a"). Em seguida, usa o cmdlet Write-Host para exibir a letra a. Na próxima vez que passarmos pelo loop, $letter é definida como "b" e assim por diante. Depois que o loop Foreach exibe a letra d, Windows PowerShell sai do loop.

A instrução Foreach inteira deve aparecer em uma única linha para ser executada como um comando no prompt de comando do Windows PowerShell. A instrução Foreach inteira não precisa aparecer em uma única linha, se você colocar o comando em um arquivo de script. ps1 em vez disso.

Instruções de ForEach também podem ser usadas em conjunto com os cmdlets que retornam uma coleção de itens. No exemplo a seguir, as etapas de instrução Foreach na lista de itens que é retornada pelo cmdlet Get-ChildItem.

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

Você pode refinar o exemplo usando uma instrução If para limitar os resultados que são retornados. No exemplo a seguir, a instrução Foreach executa a mesma operação de loop do exemplo anterior, mas adiciona uma Instrução If para limitar os resultados a arquivos maiores que 100 quilobytes (KB):

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

Neste exemplo, o loop Foreach usa uma propriedade da variável $file para executar uma operação de comparação ($file.length - gt 100 KB). A variável $file contém todas as propriedades no objeto que é retornado pelo cmdlet Get-ChildItem. Portanto, você pode retornar mais do que apenas um nome de arquivo. No exemplo a seguir, Windows PowerShell retorna o comprimento e a hora do último acesso dentro da lista de instrução:

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

Neste exemplo, você não está limitado à execução de um único comando em uma lista de instruções.

Você também pode usar uma variável de fora de um loop Foreach e incrementar a variável dentro do loop. O exemplo a seguir conta arquivos mais de 100 KB:

          $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."
          }

No exemplo anterior, a variável $i é definida como 0 fora do loop e a variável é incrementada dentro do loop para cada arquivo encontrado que seja maior do que 100 KB. Quando o loop é encerrado, uma instrução if avalia o valor de $i para exibir uma contagem de todos os arquivos com mais de 100 KB. Ou, ele exibirá uma mensagem informando que nenhum arquivo com mais de 100 KB foi encontrado.

O exemplo anterior também demonstra como formatar os resultados de tamanho do arquivo:

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

O valor é dividido por 1.024 para mostrar os resultados em quilobytes, em vez de bytes e o valor resultante é formatado usando o especificador de formato de ponto fixo para remover qualquer valor decimal do resultado. 0 faz com que o especificador de formato não exiba nenhuma casa decimal.

A instrução Foreach em um Pipeline de comando

Quando Foreach aparecer em um pipeline de comando, Windows PowerShell usará o alias de foreach, que chamará o comando ForEach-Object. Quando você usa o alias de foreach em um pipeline de comando, você não incluir a sintaxe ($<item> na $<collection>) como com a instrução Foreach. Isso ocorre porque o comando anterior no pipeline fornece essas informações. A sintaxe do alias de foreach quando usada em um pipeline de comando é a seguinte:

          <command> | foreach {<command_block>}

Por exemplo, o loop Foreach no comando a seguir exibe os processos cujo conjunto de trabalho (uso de memória) é maior do que 20 megabytes (MB).

O comando Get-Process obtém todos os processos no computador. O alias Foreach executa os comandos no bloco de script em cada processo em sequência.

A instrução IF seleciona processos com um conjunto de trabalho (WS) maior que 20 megabytes. O cmdlet Write-Host grava o nome do processo seguido por dois pontos. Divide o valor de conjunto de trabalho, que é armazenado em bytes por 1 megabyte para obter o valor do conjunto de trabalho em megabytes. Em seguida, converte o resultado de um double em uma cadeia de caracteres. Exibe o valor como um número de ponto fixo com zero casas decimais (F0), um separador de espaço ("") e, em seguida, "MB".

          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 ""}
          }

O alias Foreach também oferece suporte a blocos de comandos de início, blocos de comando intermediários e blocos de comandos finais. Os blocos de comando inicial e final são executados uma vez e o bloco de comando intermediário é executado sempre que o Foreach loop percorre uma coleção ou matriz.

A sintaxe do alias de foreach quando usada em um pipeline de comando com conjunto de blocos de comando inicial, intermediário e final é a seguinte:

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

O exemplo a seguir demonstra o uso de blocos de comando inicial, intermediário e final.

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

O bloco inicial cria e inicializa duas variáveis como 0:

          {$fileCount = $directoryCount = 0}

O bloco intermediário avalia se cada item retornado por Get-ChildItem é um diretório ou um arquivo:

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

Se o item que foi retornado for um diretório, a variável $directoryCount será incrementada em 1. Se o item que foi retornado não for um diretório, a variável $fileCount será incrementada em 1. O bloco final será executado após o bloco intermediário completar sua operação de looping e, em seguida, retorna os resultados da operação:

          {"$directoryCount directories and $fileCount files"}

Usando a estrutura de bloco inicial, intermediária e final do comando e o operador de pipeline, você pode reescrever o exemplo anterior para localizar todos os arquivos que são maiores que 100 KB, da seguinte maneira:

          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."}
              }

O exemplo a seguir, uma função que retorna as funções que são usadas em scripts e módulos de script, demonstra como usar o método MoveNext (que funciona de forma semelhante a "Ignorar X" em um loop For) e a propriedade atual da variável $foreach dentro de um bloco de script foreach, mesmo que haja espaço inconsistente ou excepcionalmente definições de função que abrangem várias linhas para declarar o nome da função. O exemplo também funciona se houver comentários nas funções usadas em um script ou um módulo 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
                 }
             }
         }

CONSULTE TAMBÉM

about_Automatic_Variables

about_If

ForEach-Object