简体   繁体   English

使用 PowerShell 的 Invoke-Command 进行远程处理时,如何包含本地定义的函数?

[英]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.我有一个 ps1 脚本,其中定义了一个函数。 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 someuser@example.com

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."然后崩溃并说“术语‘foo’未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。”

I understand that the function is not defined on the remote server because it is not in the ScriptBlock.我知道该函数未在远程服务器上定义,因为它不在 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?有没有好的方法可以做到这一点?

You need to pass the function itself (not a call to the function in the ScriptBlock ).您需要传递函数本身(而不是调用ScriptBlock的函数)。

I had the same need just last week and found this SO discussion上周我也有同样的需求,发现这个 SO 讨论

So your code will become:所以你的代码将变成:

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

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.您不能像在本地运行函数时那样使用命名参数。

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} }"

You can also put the function(s) as well as the script in a file (foo.ps1) and pass that to Invoke-Command using the FilePath parameter:您还可以将函数和脚本放在文件 (foo.ps1) 中,并使用 FilePath 参数将其传递给 Invoke-Command:

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

The file will be copied to the remote computers and executed.该文件将被复制到远程计算机并执行。

Although that's an old question I would like to add my solution.虽然这是一个老问题,但我想添加我的解决方案。

Funny enough the param list of the scriptblock within function test, does not take an argument of type [scriptblock] and therefor needs conversion.有趣的是,函数测试中脚本块的参数列表不接受 [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

Another posibility is passing a hashtable to our scriptblock containing all the methods that you would like to have available in the remote session:另一种可能性是将哈希表传递给我们的脚本块,其中包含您希望在远程会话中可用的所有方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Powershell中使用Invoke-Command时,如何在本地显示远程exe的输出? - How do I display the output of a remote exe locally when using Invoke-Command in Powershell? PowerShell远程处理-调用命令不返回输出 - PowerShell Remoting - Invoke-Command not Returning Output 当命令在本地运行以尝试获取 SSLBinding 时,使用 PowerShell Invoke-Command 不提供相同的 IIS 信息 - Using PowerShell Invoke-Command not providing same IIS info when commands ran locally trying to get SSLBinding Powershell /批处理卸载脚本在本地有效,但在使用invoke-command时无效 - Powershell/batch uninstall script works locally but not when using invoke-command Powershell调用命令失败,在本地有效 - Powershell Invoke-Command fails, Locally it works 使用Powershell的Invoke-Command调用带参数的批处理文件 - Using Powershell's Invoke-Command to call a batch file with arguments 使用 invoke-command 时 PowerShell 将文件写入本地计算机 - PowerShell write file to local machine when using invoke-command Powershell 使用 Invoke-Command 时 $PSScriptRoot 为空 - Powershell $PSScriptRoot empty when using Invoke-Command 如何退出PowerShell中的Invoke-Command -ScriptBlock? - How do you exit from an Invoke-Command -ScriptBlock in PowerShell? 如何使用Invoke-Command运行此PowerShell命令? - How to run this PowerShell command with Invoke-Command?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM