Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I include a locally defined function when using PowerShell's Invoke-Command for remoting?

I feel like I'm missing something that should be obvious, but I just can't figure out how to do this.

I have a ps1 script that has a function defined in it. It calls the function and then tries using it remotely:

function foo {     Param([string]$x)      Write-Output $x }  foo "Hi!"  Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential [email protected] 

This short example script prints "Hi!" and then crashes saying "The term 'foo' is not recognized as the name of a cmdlet, function, script file, or operable program."

I understand that the function is not defined on the remote server because it is not in the ScriptBlock. I could redefine it there, but I'd rather not. I'd like to define the function once and use it either locally or remotely. Is there a good way to do this?

like image 286
David Hogue Avatar asked Jul 06 '12 17:07

David Hogue


2 Answers

You need to pass the function itself (not a call to the function in the ScriptBlock).

I had the same need just last week and found this SO discussion

So your code will become:

Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential [email protected] 

Note that by using this method, you can only pass parameters into your function positionally; you can't make use of named parameters as you could when running the function locally.

like image 152
alroc Avatar answered Sep 26 '22 21:09

alroc


You can pass the definition of the function as a parameter, and then redefine the function on the remote server by creating a scriptblock and then dot-sourcing it:

$fooDef = "function foo { ${function:foo} }"  Invoke-Command -ArgumentList $fooDef -ComputerName someserver.example.com -ScriptBlock {     Param( $fooDef )      . ([ScriptBlock]::Create($fooDef))      Write-Host "You can call the function as often as you like:"     foo "Bye"     foo "Adieu!" } 

This eliminates the need to have a duplicate copy of your function. You can also pass more than one function this way, if you're so inclined:

$allFunctionDefs = "function foo { ${function:foo} }; function bar { ${function:bar} }" 
like image 42
JamesQMurphy Avatar answered Sep 23 '22 21:09

JamesQMurphy