在使用PowerShell';调用远程处理的命令?
我觉得我错过了一些显而易见的东西,但我就是不知道该怎么做 我有一个ps1脚本,其中定义了一个函数。它调用该函数,然后尝试远程使用该函数:在使用PowerShell';调用远程处理的命令?,powershell,powershell-2.0,powershell-remoting,Powershell,Powershell 2.0,Powershell Remoting,我觉得我错过了一些显而易见的东西,但我就是不知道该怎么做 我有一个ps1脚本,其中定义了一个函数。它调用该函数,然后尝试远程使用该函数: function foo { Param([string]$x) Write-Output $x } foo "Hi!" Invoke-Command -ScriptBlock { foo "Bye!" } -ComputerName someserver.example.com -Credential someuser@example.
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’不能识别为cmdlet、函数、脚本文件或可操作程序的名称。”
我知道该函数没有在远程服务器上定义,因为它不在脚本块中。我可以在那里重新定义,但我不想。我想定义这个函数一次,然后在本地或远程使用它。有没有一个好方法可以做到这一点?您需要传递函数本身(而不是调用
脚本块中的函数)
就在上周,我也有同样的需求,发现
因此,您的代码将成为:
Invoke-Command -ScriptBlock ${function:foo} -argumentlist "Bye!" -ComputerName someserver.example.com -Credential someuser@example.com
请注意,通过使用此方法,只能按位置将参数传递到函数中;在本地运行函数时,不能像使用命名参数那样使用命名参数。可以将函数的定义作为参数传递,然后通过创建scriptblock在远程服务器上重新定义函数,然后点源:
$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命令:
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
另一个可能性是将哈希表传递给scriptblock,其中包含您希望在远程会话中可用的所有方法:
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
好吧,听起来和我读过的东西很相似。因此,更进一步:是否有一种好的方法来包含函数和一些使用函数的附加脚本行?我还没有对此进行测试,但是如果您想格式化函数的输出(例如),这应该可以:-ScriptBlock{$function:foo | format table-auto}
。基本上,任何ScriptBlock
都可以是有效的PowerShell代码的任何“块”,因此只要您正确格式化它(或在每一行末尾使用分号),您就应该是好的。例如,今天早些时候,我在胡闹“measure command{$x=[xml](get content file.xml);$x.selectsinglenode(//thing”);},这正是我要找的!您的解决方案与$Using:Var
结合使用,成功了:)非常感谢!只要函数名不包含Get Foo之类的“-”,它就可以工作。我找不到语法。这是最好的选择。减少了杂乱,操作简单。按照你想要的方式编写脚本,瞧!