about_Foreach
Short description
Describes a language command you can use to traverse all the items in a collection of items.
Long description
The foreach
statement is a language construct for iterating over a set of
values in a collection.
The simplest and most typical type of collection to traverse is an array.
Within a foreach
loop, it's common to run one or more commands against each
item in an array.
Syntax
The following shows the foreach
syntax:
foreach ($<item> in $<collection>){<statement list>}
The part of the foreach
statement inside parenthesis represents a variable
and a collection to iterate. PowerShell creates the variable $<item>
automatically when the foreach
loop runs. At the start of each iteration,
foreach
sets the item variable to the next value in the collection. The
{<statement list>}
block contains the commands to execute for each iteration.
Examples
For example, the foreach
loop in the following example displays the values in
the $letterArray
array.
$letterArray = 'a','b','c','d'
foreach ($letter in $letterArray)
{
Write-Host $letter
}
In this example, the $letterArray
contains the string values a
, b
,
c
, and d
. The first time the foreach
statement runs, it sets the
$letter
variable equal to the first item in $letterArray
(a
). Then, it
uses Write-Host
to display the value. The next time through the loop,
$letter
is set to b
. The pattern repeats for each item in the array.
You can also use foreach
statements with cmdlets that return a collection of
items. In the following example, the foreach
statement steps through the list
of items returned by the Get-ChildItem
cmdlet.
foreach ($file in Get-ChildItem)
{
Write-Host $file
}
You can refine the example using an if
statement to limit the results that
are returned. In the following example, the if
statement limits the results
to files that are greater than 100 kilobytes (KB):
foreach ($file in Get-ChildItem)
{
if ($file.Length -gt 100KB)
{
Write-Host $file
}
}
In this example, the foreach
loop uses a property of the $file
variable to
perform a comparison operation ($file.length -gt 100KB
). The $file
variable
has all the properties of the object returned by the Get-ChildItem
.
In the next example, the script displays the length and the last access time inside the statement list:
foreach ($file in Get-ChildItem)
{
if ($file.Length -gt 100KB)
{
Write-Host $file
Write-Host $file.Length
Write-Host $file.LastAccessTime
}
}
You can also use variables from outside a foreach
loop. The following example
counts files over 100 KB in size:
$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 100KB in the current directory.'
}
else {
Write-Host 'No files greater than 100KB in the current directory.'
}
In the preceding example, $i
starts with a value of 0
outside the loop.
Then, $i
is incremented inside the loop for each file that's larger than
100KB. When the loop exits, an if
statement evaluates the value of $i
to
display a count of files over 100KB.
The previous example also demonstrates how to format the file length results:
($file.length / 1024).ToString('F0')
The value is divided by 1,024 to show the results in kilobytes rather than
bytes, and the resulting value is then formatted using the fixed-point format
specifier to remove any decimal values from the result. The 0
makes the
format specifier show no decimal places.
The following function parses PowerShell scripts and script modules and returns
the location of functions contained within. The example demonstrates how to use
the MoveNext
method and the Current
property of the $foreach
variable
inside of a foreach
script block.
For more information, see Using Enumerators.
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
}
$parser = [System.Management.Automation.Language.Parser]
foreach ($item in $filesToProcess) {
if ($item.PSIsContainer -or
$item.Extension -notin @('.ps1', '.psm1')) {
continue
}
$tokens = $errors = $null
$ast = $parser::ParseFile($item.FullName, ([ref]$tokens),
([ref]$errors))
if ($errors) {
$msg = "File '{0}' has {1} parser errors." -f $item.FullName,
$errors.Count
Write-Warning $msg
}
: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
}
$addMemberSplat = @{
InputObject = $functionPosition
TypeName = 'FunctionPosition'
PassThru = $true
}
Add-Member @addMemberSplat
}
}
}
catch {
throw
}
}
}