30

I'm writing a PowerShell script that will execute commands on a remote host using Invoke-Command and its -ScriptBlock parameter. For example,

function Foo {
    ...
    return "foo"
}
$rv = Invoke-Command --Credential $c --ComputerName $fqdn -ScriptBlock ${function:Foo}

This works fine. What I'd like to do now is the same thing, but call a function with local arguments. For example,

function Bar {
    param( [String] $a, [Int] $b )
    ...
    return "foo"
}
[String] $x = "abc"
[Int] $y = 123
$rv = Invoke-Command --Credential $c --ComputerName $fqdn -ScriptBlock ${function:Foo($x,$y)}

But this does not work:

Invoke-Command : Cannot validate argument on parameter 'ScriptBlock'. The argument is null. Supply a non-null argument and try the command again.

How can I use Invoke-Command with a -ScriptBlock that is a local function with arguments?

I realize that I can wrap the entire function and the parameters in a big code block, but that is not a clean way of doing it, in my opinion.

4 Answers 4

53

I think you want:

function Foo ( $a,$b) {
    $a
    $b
    return "foo"
}

$x = "abc"
$y= 123

Invoke-Command -Credential $c -ComputerName $fqdn -ScriptBlock ${function:Foo} -ArgumentList $x,$y
Sign up to request clarification or add additional context in comments.

9 Comments

thanks man, works perfectly! I was messing with combos of param() + -Arguments with no luck.
took me several hours to find this solution ;-) Much better than exporting/importing sessions Thank You!
I believe the correct format should be -ScriptBlock {$function:Foo} (note $ position)
I tried it out and this is the only way that it works ${function:Foo}. At least when you have the format ${function:Foo-Bar}.
There is big difference between {$function:Foo} and ${function:Foo}. The curly braces in the former mean scriptblock, and so the expression means: "A scriptblock that resolves to variable foo in function scope." The curly braces in the latter mean the the name of the variable is taken literarly and so it translates simply to: "A variable foo in function scope." This would be useful if the "foo" variable had spaces or other special charactes in name.
|
9

You can wrap the functions in a block and pass the block;

$a = {
  function foo{}
  foo($args)
}

$a.invoke() // Locally

$rv = Invoke-Command --Credential $c --ComputerName $fqdn -ScriptBlock $a //remotely

It's hardly elegant though.

Comments

2

This also works:

function foo
{
    param([string]$hosts, [string]$commands)
    $scriptblock = $executioncontext.invokecommand.NewScriptBlock($commands)
    $hosts.split(",") |% { Invoke-Command -Credential $cred -ComputerName $_.trim() -Scriptblock $scriptblock }
}

Comments

-1
$Log = "PowerShellCore/Operational"

Invoke-Command -ComputerName Server01 -ScriptBlock {Get-WinEvent -LogName $Using:Log -MaxEvents 10}\

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.