2

In a complex script, I have a bunch a calls that repeat the same pattern: prepare,execute,clean.

Only the execute part is different, so I want to define only once the prepare and clean calls.

To achieve this, I'd like to wrap this in a function, having the execute part passed as a parameter.

I tried this:

function SomeFunc{
    param(
        [scriptblock]$Action,
        [int]$x,
        [int]$y
    )


    Write-Host "Before"

    Invoke-Command -ScriptBlock $Action  -PipelineVariable ($x*$y) 

    Write-Host "After"

}


SomeFunc  -x 2 -y 4 -Action {  Write-Host -ForegroundColor Yellow "Result is $_"  }

But this not works. $_ is always empty.

How can I reach my goal?

1
  • 1
    What are you doing with -PipelineVariable there? Doesn't it take the name of the variable to assign the pipeline variable to? Do you want to pass that result as an argument to the invoked block? Commented Jun 4, 2015 at 16:16

2 Answers 2

1

You can pass arguments for the ScriptBlock not through the pipeline but as arguments in array as ArgumentList parameter to the Invoke-Command cmdlet. Then you will be able to access the arguments by $args variable inside your 'process' ScriptBlock.

function SomeFunc {
    param ($x, $y, $sb)
    Write-Host "Before";
    Invoke-Command -ScriptBlock $sb -ArgumentList @("Some string", $x, ($x * $y))
    Write-Host "After";
}
SomeFunc -x 4 -y 2 -sb { foreach ($a in $args) { Write-Host ("Parameter: $a")  } }

The output would be

Before
Parameter: Some string
Parameter: 4
Parameter: 8
After

You can also include param() block inside your ScriptBlock. This way allows you to easily place additional restrictions on the arguments, such as strong typing

function SomeFunc {
    param ($x, $y, $sb)
    Write-Host "Before";
    Invoke-Command -ScriptBlock $sb -ArgumentList @("Not x", $y, ($x * $y));
    Write-Host "After";
}
SomeFunc -x 4 -y 2 -sb { param ([int]$a, $b, $c) Write-Host ("a is {0}, c is {1}, b is {2}" -f $a, $c, $b)} 

The output shows the error

Before
Invoke-Command : Cannot convert value "Not x" to type "System.Int32". Error: "Input string was not in a correct format."
At line:4 char:5
+     Invoke-Command -ScriptBlock $sb -ArgumentList @("Not x", $y, ($x * $y));
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-Command], PSInvalidCastException
    + FullyQualifiedErrorId : InvalidCastFromStringToInteger,Microsoft.PowerShell.Commands.InvokeCommandCommand

After
Sign up to request clarification or add additional context in comments.

2 Comments

using the param within my script block is what I was looking for. Thx
You are welcome. In reality all functions and scripts are just scriptblocks. If you enter $function:SomeFunc you'll see the body of the function - which is a script block. Basically it means that things you can do with functions and scripts can be done with scriptblocks either, e.g. including param
0

If you don't really need to pipeline to it, you can just use a variable that is set:

function SomeFunc{
    param(
        [scriptblock]$Action,
        [int]$x,
        [int]$y
    )

    $s = $x*$y
    Invoke-Command -ScriptBlock $Action

}

[scriptblock]$sb = { Write-Host -ForegroundColor Yellow "Result is $s" }
SomeFunc  -x 2 -y 4 -Action $sb

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.