$integers = 1..10
foreach($int in $integers)
{
$int
}
So, the 1..10 stores an array of numbers 1 to 10 in $integers. When you place the $integers object in the foreach as shown above it iterates over the collection one item at a time so you can do as you like with it in the block.Now, what I did not understand until I started looking into this "keyword" is that it is not actually a separate construct. In fact, it is just an alias for Foreach-Object as proven by these commands:
- Get-Help foreach
- Get-Alias foreach
The real question, then, is Foreach-Object. According to the help we see this in v2:
Get-Help ForEach-Object
NAME
ForEach-Object
SYNOPSIS
Performs an operation against each of a set of input objects.
SYNTAX
ForEach-Object [-Process] <ScriptBlock[]> [-Begin <scriptblock>] [-End <scriptblock>] [-InputObject <psobject>] [<CommonParameters>]
DESCRIPTION
The ForEach-Object cmdlet performs an operation on each of a set of input objects. The input objects can be piped to the cmdlet or specified by using the InputObject parameter.
The operation to perform is described within a script block that is provided to the cmdlet as the value of the Process parameter. The script block can contain any Windows PowerShell script.
Within the script block, the current input object is represented by the $_ variable.
In addition to using the script block that describes the operations to be carried out on each input object, you can provide two additional script blocks. One, specified as the value of the Begin parameter, runs before the first input object is processed. The other, specified as the value of the End parameter, runs after the last input object is processed.
The results of the evaluation of all the script blocks, including the ones specified with Begin and End, are passed down the pipeline.
RELATED LINKS
Online version: http://go.microsoft.com/fwlink/?LinkID=113300
REMARKS
To see the examples, type: "get-help ForEach-Object -examples".
For more information, type: "get-help ForEach-Object -detailed".
For technical information, type: "get-help ForEach-Object -full".
Having gotten more information I can now see how foreach and Foreach-Object connect. With the Foreach-Object cmdlet (as opposed to the aliased foreach) you use the pipeline placeholder ($_) instead of a named placeholder ($int in our example above). Also, Foreach-Object allows you to tap into the -Begin, -Process, and, -End blocks, where -Process (that is pipelined operations) are in fact the default used without specification. Whats cool about this is you can use the -Begin and -End blocks to help iterate over a collection and handle initialization and clean up all in one single cmdlet call. For instance, if I want to install a bunch of ServerManager module Windows feature, but, report on it as part of an installation for logging, I can do this with Foreach-Object:$ServerRoles = @(Web-Server,Web-Webserver)Using a more easily demonstrated example, watch how this functions with the -Begin, -Process, and, -End block:
# Output status to hostWrite-Output "$(wts): Attempting to install server roles."
# Install server roles
$ServerRoles | ForEach-Object `
-Begin { `
Write-Output "$(wts): Attempting to install server role." `
} `
-Process { `
Write-Output "$(wts): Attempting to install $_." `
Add-WindowsFeature -FeatureName $_ | Out-Null `
}
This takes an array of 1,2,3,4, spits out the word Starting once, iterates over the array (lists 1,2,3,4), and, to close, writes Done on the host. See results below:
$array = 1,2,3,4
$array | ForEach-Object `
`
-Begin {
"Starting"
} `
`
-Process {
$_
} `
`
-End {
"Done"
}
To met this really cool. I have always used foreach and had to wrap beginning and closing statements, for reporting, in separate Write-Output statements. This is much more succinct and clean.
Starting
1
2
3
4
Done
Whats more is you can simple store scriptblocks as your desired functionality in variables (or here strings) and pass the variables to the Foreach-Object:
This is much easier to read, more organized, and, runs exactly the same as the previous output.
$array = 1..4
$begin = { "Starting" }
$process = { $_ }
$end = { "Done" }
$array | ForEach-Object -begin $begin -process $process -end $end