ForEach-Object Scriptblock parameters

Get-Help ForEach-Object -full does not explain how the following example works.

PS C:> 1…4 | ForEach-Object {‘Begin’} {“Process $_”} {‘End’}
Process 1
Process 2
Process 3
Process 4
PS C:>

The -Begin and -End are named parameters, with a type of <scriptblock>.

While -Process <ScriptBlock> is listed as position 1.

To make things even more interesting, there is a new parameter for PS ver 3.0

-RemainingScripts <ScriptBlock>

Based on my interpretation of the help output, I would have expected the first scriptblock to be assigned to -Process, and the other two scriptblocks to flag some sort of syntax error. Is this a case where the actual behavior of the cmdlet is just not described well by the documentation conventions used?

Should I be concerned with cmdlet behavior with respect to parameter processing that does not seem to match the documentation?

Any insight would be appreciated.

Believe it or not, there is an explanation for this behaviour.

First, you should read this blog post:

Bartek explains what is actually happening here, and also shows you how Trace-Command can be used to see how parameters are bound.  This highlights how ForEach-Object internally evaluates whatever unbound script blocks you pass it and decides what to do with them based on whether or not you have explicitly provided -Begin or -End script blocks.

Regarding whether or not you should be concerned with cmdlet behaviour with respect to parameter binding not matching the documentation, I don’t think you should be too concerned because this is a bit of an anomaly. Â I would strongly recommend though that for actual scripts (as opposed to ad-hoc use of PowerShell) that you explicitly use named parameters because it removes any potential for confusion wrt parameter binding.

Amen on the named parameters. That said, it’d be nice if this was doc’d a bit better - and you should consider bugging it on Connect, so that MS can put some attention to it.