Reputation: 37690
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?
Upvotes: 2
Views: 167
Reputation: 2063
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
Upvotes: 1
Reputation: 4742
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
Upvotes: 0