PowerShell: the mysterious -RemainingScripts parameter of ForEach-Object -
short question: has detailed information on -remainingscripts parameter of foreach-object?
long question:
i started learning powershell last week , i'm going through each cmdlets learn more details. based on public documentation, know foreach-object can have begin-process-end blocks, this:
get-childitem | foreach -begin { "block1"; $filecount = $directorycount = 0} -process { "block2"; if ($_.psiscontainer) {$directorycount++} else {$filecount++}} -end { "block3"; "$directorycount directories , $filecount files"} result expected: 1 time "block1" , "block3", "block2" repeated each item passed in, , dir count/file count correct. far good.
now, what's interesting is, following command works , gives same result:
get-childitem | foreach { "block1" $filecount = $directorycount = 0}{ "block2"; if ($_.psiscontainer) {$directorycount++} else {$filecount++}}{ "block3"; "$directorycount directories , $filecount files"} just 3 scriptblocks passed foreach. based on manual, first 1 goes -process (position 1). how remaining 2? according manual, there's not parameter "position 2". turned trace-command, , found later 2 script blocks remainingscripts "ilist 2 elements".
bind arg [$filecount = $directorycount = 0] parameter [process] bind arg [system.management.automation.scriptblock[]] param [process] successful bind arg [system.collections.arraylist] parameter [remainingscripts] bind arg [system.management.automation.scriptblock[]] param [remainingscripts] successful so if change command this:
# no difference with/without comma "," between last 2 blocks get-childitem | foreach -process { "block1" $filecount = $directorycount = 0} -remainingscripts { "block2"; if ($_.psiscontainer) {$directorycount++} else {$filecount++}},{ "block3"; "$directorycount directories , $filecount files"} still, same result.
so noticed, 3 commands give same result. raises interesting question: both of later 2 commands (implicitly) specified -process, foreach-object surprisingly ends using argument of -process "-begin"! (script block executed once @ beginning).
this experimentation suggests:
- -remainingscripts parameter take unbound scriptblocks
- when 3 blocks passed in, although first 1 goes -process, later used "begin" while remaining 2 become "process" , "end"
still, above wild guess. didn't find documentation support guess
so, go short question :) has detailed information on -remainingscripts parameter of foreach-object?
thanks.
i did more research , feel confident answer behavior of -remainingscripts parameter when multiple scriptblocks passed in.
if run following commands , inspect result carefully, find pattern. it's not quite straightforward, still not hard figure out.
1..5 | foreach { "process block" } { "remain block" } 1..5 | foreach { "remain block" } -process { "process block" } 1..5 | foreach { "remain block" } -end { "end block" } -process { "process block" } -begin { "begin block" } 1..5 | foreach { "remain block 1" } -end { "end block" } -process { "process block" } { "remain block 2" } 1..5 | foreach { "remain block 1" } { "remain block 2" } -process { "process block" } -begin { "begin block" } 1..5 | foreach { "remain block 1" } { "remain block 2" } -process { "process block" } { "remain block 3" } 1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } -begin { "begin block" } 1..5 | foreach { "process block" } { "remain block 1" } { "remain block 2" } { "remain block 3" } so what's pattern here?
when there's single scriptblock passed in: easy, goes -process (the common usage)
when 2 scriptblocks passed in, there 3 possible combinations
- -process & -begin -> execute specified
- -process & -end -> execute specified
- -process & -remainingscripts -> process becomes begin, while remainingscripts becomes process
if run these 2 statements:
1..5 | foreach { "process block" } { "remain block" } 1..5 | foreach { "remain block" } -process { "process block" } # both of them return: process block remain block remain block remain block remain block remain block as find out, special case of following test case:
when more 2 scriptblocks passed in, follow workflow:
- bind scriptblocks specified (begin,process,end); remaining scriptblocks go remainingscripts
- order scripts as: begin > process > remaining > end
result of ordering collection of scriptblocks. let's call collection orderedscriptblocks
- if begin/end not bound, ignore
(internally) re-bind parameters based on orderedscriptblocks
- orderedscriptblocks[0] becomes begin
- orderedscriptblocks[1..-2] become process
- orderedscriptblocks[-1] (the last one) becomes end
let's take example
1..5 | foreach { "remain block 1" } { "remain block 2" } -process { "process block" } { "remain block 3" } order result is:
{ "process block" } # new begin { "remain block 1" } # new process { "remain block 2" } # new process { "remain block 3" } # new end now execution result predictable:
process block remain block 1 remain block 2 remain block 1 remain block 2 remain block 1 remain block 2 remain block 1 remain block 2 remain block 1 remain block 2 remain block 3 that's secret behind -remainingscripts , understand more internal behavior of foreach-object!
still have admit there's no documentation support guess (not fault!), these test cases should enough explain behavior described.
Comments
Post a Comment