vik santata
vik santata

Reputation: 3109

I cannot use begin/process/end block in a ForEach-Object?

I've got the following code:

function f()
{
    begin{$count=0}
    process{$count+=10}
    end{$count}
}
1..10|f # OK
1..10|%{
    begin{$count=0}
    process{$count+=10}
    end{$count}
} # Error

The first "f" call succeeds, while the %{} block shows error:

100
% : The script block cannot be invoked because it contains more than one clause. The Invoke() method can only be used on script blocks that contain a single clause.
At D:\Untitled1.ps1:13 char:7
+ 1..10|%{
+       ~~
    + CategoryInfo          : InvalidOperation: (:) [ForEach-Object], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.ForEachObjectCommand

But why? ForEach-Object doesn't support begin/process/end blocks?

Upvotes: 3

Views: 4232

Answers (3)

js2010
js2010

Reputation: 27473

A cool thing is, you can do it without specifying the parameters, and it works, using -process and -remainingscripts behind the scenes.

1..10 | ForEach {$count=0} {$count+=10} {$count}

100

Upvotes: 2

ThePennyDrops
ThePennyDrops

Reputation: 171

As an addendum, just a small point if you like to structure your code for ease of reading. The continuation tick ("`") is important - as I just found out to some cost to myself!

Get-Content -Path $SelectedFiles | ForEach-Object `
-Begin {
 #- Do Begin stuff -----
 } `
-Process {
#- Do Process stuff
} `
-End {
#- Do End stuff
}
#- EndOf: ForEach is here -----
#- NB! Continuation tick "`" must be preceded by space & be LAST character on line!!!!!

To help in the ISE, the colour of the parameters (Begin, Process, End) should be the same as other parameters (my parameters are black) when correctly identified. Play with the above code in the ISE, put a space after a tick, don't have a space before a tick, etc. I didn't realise how important a 'space' could be - grin! Good luck! Hope this helps another beginner like me.

Upvotes: 2

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174555

ForEach-Object takes the individual blocks as separate named parameters.

In your case, that would be:

1..10 |ForEach-Object -Begin {$count=0} -Process {$count+=10} -End {$count}

This is well documented in the help files - from Get-Help ForEach-Object -Parameter *:

-Begin <ScriptBlock>
    Specifies a script block that runs before processing any input objects.

    Required?                    false
    Position?                    named
    Default value                None
    Accept pipeline input?       false
    Accept wildcard characters?  false


-End <ScriptBlock>
    Specifies a script block that runs after processing all input objects.

    Required?                    false
    Position?                    named
    Default value                None
    Accept pipeline input?       false
    Accept wildcard characters?  false

<# ... #>

-Process <ScriptBlock[]>
    Specifies the operation that is performed on each input object. Enter a script
    block that describes the operation.

    Required?                    true
    Position?                    1
    Default value                None
    Accept pipeline input?       false
    Accept wildcard characters?  false

Upvotes: 8

Related Questions