Как включить локально определенную функцию при использовании команды Invoke-Command PowerShell для удаленного взаимодействия?

У меня есть скрипт ps1, в котором определена функция. Он вызывает функцию, а затем пытается использовать ее удаленно:

function foo
{
    Param([string]$x)

    Write-Output $x
}

foo "Hi!"

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

этот короткий пример сценария печатает " Привет!"а затем происходит сбой "термин" foo " не распознается как имя командлета, функции, файла сценария или действующей программы."

Я понимаю, что функция не определена на удаленном сервере, потому что он не находится в ScriptBlock. Я мог бы пересмотреть его там, но предпочел бы не делать этого. Я хотел бы определить функцию один раз и использовать ее локально или удаленно. Есть ли хороший способ сделать это?

4 ответов


вам нужно передать саму функцию (не вызов функции в ScriptBlock).

у меня была такая же потребность только на прошлой неделе и нашел это так обсуждение

таким образом, ваш код станет:

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

обратите внимание, что с помощью этого метода вы можете передавать параметры в свою функцию только позиционно; вы не можете использовать именованные параметры, как при локальном запуске функции.


вы можете передать определение функции в качестве параметра, а затем переопределить функцию на удаленном сервере, создав блок скриптов, а затем точечный источник:

$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 –ComputerName server –FilePath .\foo.ps1

файл будет скопирован на удаленные компьютеры и выполнен.


хотя это старый вопрос, я хотел бы добавить свое решение.

забавно, что список параметров scriptblock в функциональном тесте не принимает аргумент типа [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

еще одна возможность-передать хэш-таблицу в наш блок скриптов, содержащий все методы, которые вы хотели бы иметь в удаленном сеансе:

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