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