34

当たり前のことを見逃しているような気がしますが、どうすればいいのかわかりません。

関数が定義されているps1スクリプトがあります。関数を呼び出して、リモートで使用しようとします。

function foo
{
    Param([string]$x)

    Write-Output $x
}

foo "Hi!"

Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential someuser@example.com

この短いサンプルスクリプトは「Hi!」を出力します 次に、「「foo」という用語は、コマンドレット、関数、スクリプトファイル、または操作可能なプログラムの名前として認識されません」とクラッシュします。

ScriptBlockにないため、リモートサーバーで関数が定義されていないことを理解しています。そこで再定義することはできますが、したくありません。関数を一度定義して、ローカルまたはリモートで使用したいと思います。これを行う良い方法はありますか?

4

4 に答える 4

40

関数自体を渡す必要があります(の関数の呼び出しではありませんScriptBlock)。

私は先週同じニーズがあり、このSOディスカッションを見つけました

したがって、コードは次のようになります。

Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential someuser@example.com

このメソッドを使用することにより、パラメーターを関数に位置的にのみ渡すことができることに注意してください。関数をローカルで実行する場合のように、名前付きパラメーターを使用することはできません。

于 2012-07-06T20:23:27.477 に答える
32

関数の定義をパラメーターとして渡し、スクリプトブロックを作成してドットソーシングすることにより、リモートサーバーで関数を再定義できます。

$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} }"
于 2014-05-30T06:44:47.167 に答える
6

関数とスクリプトをファイル(foo.ps1)に入れ、FilePathパラメーターを使用してInvoke-Commandに渡すこともできます。

Invoke-Command –ComputerName server –FilePath .\foo.ps1

ファイルがリモートコンピュータにコピーされて実行されます。

于 2015-07-01T01:12:10.557 に答える
0

それは古い質問ですが、私は自分の解決策を追加したいと思います。

面白いことに、関数テスト内のscriptblockのparamリストは、[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
于 2018-04-11T06:11:17.947 に答える