title: PowerShell: the mysterious -RemainingScripts parameter of ForEach-Object
body: <p><strong>Short question</strong>: anyone has detailed information on -RemainingScripts parameter of ForEach-Object?</p>
  
  <p><strong>Long question:</strong></p>
  
  <p>I just started learning PowerShell from last week and I'm going through each Cmdlets to learn more details. Based on public documentation, we know ForEach-Object can have Begin-Process-End blocks, like this:</p>
  
  <pre><code>Get-ChildItem | foreach -Begin { "block1";
      $fileCount = $directoryCount = 0} -Process { "block2";
      if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}} -End {
      "block3"; "$directoryCount directories and $fileCount files"}
  </code></pre>
  
  <p>Result is expected: 1 time for "block1" and "block3", "block2" is repeated for each item passed in, and dir count/file count are all correct. So far so good.</p>
  
  <p>Now, what's interesting is, the following command also works and gives exactly the same result:</p>
  
  <pre><code>Get-ChildItem | foreach { "block1"
      $fileCount = $directoryCount = 0}{ "block2";
      if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}}{
      "block3"; "$directoryCount directories and $fileCount files"}
  </code></pre>
  
  <p>Just 3 ScriptBlocks passed to foreach. Based on manual, the first one goes to -Process (Position 1). But how about the remaining 2? According to manual, there's not a parameter with "Position 2". So I turned to Trace-Command, and found that the later 2 script blocks were actually to RemainingScripts as "IList with 2 elements".</p>
  
  <pre><code>BIND arg [$fileCount = $directoryCount = 0] to parameter [Process]
  BIND arg [System.Management.Automation.ScriptBlock[]] to param [Process] SUCCESSFUL
  BIND arg [System.Collections.ArrayList] to parameter [RemainingScripts]
  BIND arg [System.Management.Automation.ScriptBlock[]] to param [RemainingScripts] SUCCESSFUL
  </code></pre>
  
  <p>So If I change the command to this:</p>
  
  <pre><code># No difference with/without the comma "," between the last 2 blocks
  Get-ChildItem | foreach -Process { "block1"
      $fileCount = $directoryCount = 0} -RemainingScripts { "block2";
      if ($_.PsIsContainer) {$directoryCount++} else {$fileCount++}},{
      "block3"; "$directoryCount directories and $fileCount files"}
  </code></pre>
  
  <p>Still, exactly the same result.</p>
  
  <p>So as you noticed, all 3 commands give the same result. This raises the interesting question: both of the later two commands (implicitly) specified -Process, however <strong>ForEach-Object surprisingly ends up using the argument of -Process as "-Begin"!</strong> (script block is executed once at the beginning).</p>
  
  <p>This experimentation suggests:</p>
  
  <ol>
  <li>-RemainingScripts parameter will take all unbound ScriptBlocks</li>
  <li>When 3 blocks are passed in, although the first one goes to -Process, later it is actually used as "Begin" while the remaining 2 become "Process" and "End"</li>
  </ol>
  
  <p>Still, all above are just my wild guess. I didn't find documentation to support my guess</p>
  
  <p>So, finally we go back to my short question :)
  Anyone has detailed information on -RemainingScripts parameter of ForEach-Object?</p>
  
  <p>Thanks.</p>