明らかなはずの何かを見逃しているように感じますが、どうすればよいかわかりません。
関数が定義されているps1スクリプトがあります。関数を呼び出し、リモートで使用を試みます。
function foo
{
Param([string]$x)
Write-Output $x
}
foo "Hi!"
Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential [email protected]
この短いスクリプト例は「Hi!」を出力しますそして、「「foo」という用語は、コマンドレット、関数、スクリプトファイル、または操作可能なプログラムの名前として認識されません」とクラッシュします。
ScriptBlockにないため、関数がリモートサーバーで定義されていないことを理解しています。そこで再定義できましたが、そうではありません。関数を一度定義して、ローカルまたはリモートで使用したいと思います。これを行う良い方法はありますか?
関数自体を渡す必要があります(ScriptBlock
の関数の呼び出しではありません)。
先週と同じニーズがあり、 this SO Discussion
したがって、コードは次のようになります。
Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential [email protected]
このメソッドを使用すると、関数に位置的にのみパラメーターを渡すことができます。関数をローカルで実行するときのように、名前付きパラメーターを使用することはできません。
関数の定義をパラメーターとして渡し、スクリプトブロックを作成してからドットソースを取得することで、リモートサーバーで関数を再定義できます。
$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!"
}
これにより、関数のコピーを複製する必要がなくなります。また、この方法で複数の関数を渡すこともできます。
$allFunctionDefs = "function foo { ${function:foo} }; function bar { ${function:bar} }"
また、関数とスクリプトをファイル(foo.ps1)に入れ、FilePathパラメーターを使用してInvoke-Commandに渡すこともできます。
Invoke-Command –ComputerName server –FilePath .\foo.ps1
ファイルがリモートコンピューターにコピーされ、実行されます。
それは古い質問ですが、解決策を追加したいと思います。
面白いことに、関数test内のスクリプトブロックのパラメーターリストは、[scriptblock]型の引数をとらないため、変換が必要です。
Function Write-Log
{
param(
[string]$Message
)
Write-Host -ForegroundColor Yellow "$($env:computername): $Message"
}
Function Test
{
$sb = {
param(
[String]$FunctionCall
)
[Scriptblock]$WriteLog = [Scriptblock]::Create($FunctionCall)
$WriteLog.Invoke("There goes my message...")
}
# Get function stack and convert to type scriptblock
[scriptblock]$writelog = (Get-Item "Function:Write-Log").ScriptBlock
# Invoke command and pass function in scriptblock form as argument
Invoke-Command -ComputerName SomeHost -ScriptBlock $sb -ArgumentList $writelog
}
Test
もう1つの可能性は、リモートセッションで使用できるようにするすべてのメソッドを含むハッシュテーブルをスクリプトブロックに渡すことです。
Function Build-FunctionStack
{
param([ref]$dict, [string]$FunctionName)
($dict.Value).Add((Get-Item "Function:${FunctionName}").Name, (Get-Item "Function:${FunctionName}").Scriptblock)
}
Function MyFunctionA
{
param([string]$SomeValue)
Write-Host $SomeValue
}
Function MyFunctionB
{
param([int]$Foo)
Write-Host $Foo
}
$functionStack = @{}
Build-FunctionStack -dict ([ref]$functionStack) -FunctionName "MyFunctionA"
Build-FunctionStack -dict ([ref]$functionStack) -FunctionName "MyFunctionB"
Function ExecuteSomethingRemote
{
$sb = {
param([Hashtable]$FunctionStack)
([Scriptblock]::Create($functionStack["MyFunctionA"])).Invoke("Here goes my message");
([Scriptblock]::Create($functionStack["MyFunctionB"])).Invoke(1234);
}
Invoke-Command -ComputerName SomeHost -ScriptBlock $sb -ArgumentList $functionStack
}
ExecuteSomethingRemote