PowerShell:将函数作为参数传递

wot*_*324 32 powershell parameter-passing calling-convention

我编写了函数'A',它将调用许多其他函数之一.为了保存重写函数'A',我想传递函数作为函数'A'的参数调用.例如:

function A{
    Param($functionToCall)
    Write-Host "I'm calling : $functionToCall"
}

function B{
    Write-Host "Function B"
}

Function C{
    write-host "Function C"
}

A -functionToCall C
Run Code Online (Sandbox Code Playgroud)

返回:我正在打电话:C

我期待它回归:我在呼唤:功能C.

我尝试了各种各样的东西,比如:

Param([scriptblock]$functionToCall)
Run Code Online (Sandbox Code Playgroud)

无法将System.String转换为ScriptBlock

A -functionToCall $function:C
Run Code Online (Sandbox Code Playgroud)

返回"写主机"功能C"

A - functionToCall (&C)
Run Code Online (Sandbox Code Playgroud)

这在其余部分之前进行评估:

 Function C
 I'm Calling :
Run Code Online (Sandbox Code Playgroud)

我确定这是编程101,但我无法弄清楚正确的语法或它是什么我做错了.我们将非常感激地提供任何帮助.非常感谢.

Dun*_*can 39

我不确定这是最好的,但是:

function A{
    Param([scriptblock]$FunctionToCall)
    Write-Host "I'm calling $($FunctionToCall.Invoke(4))"
}

function B($x){
    Write-Output "Function B with $x"
}

Function C{
    Param($x)
    Write-Output "Function C with $x"
}

PS C:\WINDOWS\system32> A -FunctionToCall $function:B
I'm calling Function B with 4

PS C:\WINDOWS\system32> A -FunctionToCall $function:C
I'm calling Function C with 4

PS C:\WINDOWS\system32> A -FunctionToCall { Param($x) "Got $x" }
I'm calling Got x
Run Code Online (Sandbox Code Playgroud)

  • 难道你不能恰当地把它包起来考虑破折号吗?A -functionToCall $ {Function:Execute-FunctionWithDash} (3认同)
  • 只是证明您可以在调用函数时传递参数 (2认同)
  • 如果要使用脚本块的结果,可能会考虑使用 InvokeResultAsIs 而不是 Invoke,因为 Invoke 似乎返回了一个集合——即使只返回了一个对象。 (2认同)

mkl*_*nt0 10

如果你真的想通过名字的函数,作为一个字符串:使用&电话运营商,来调用它:

function A {
  Param($functionToCall)
  # Note the need to enclose a command embedded in a string in $(...)
  Write-Host "I'm calling: $(& $functionToCall)"
}

Function C {
  "Function C"  # Note: Do NOT use Write-Host to output *data*.
}

A -functionToCall C
Run Code Online (Sandbox Code Playgroud)

至于需要使用$(...)inside "...":请参阅此答案,其中解释了 PowerShell 的字符串扩展(字符串插值)规则。

以上产量 I'm calling: Function C

请注意函数如何C使用隐式输出(与Write-Output显式使用相同)来返回值。
Write-Host通常是使用错误的工具,除非意图明确地仅写入显示,绕过 PowerShell 的输出流。

您通常&在以下场景中需要运算符:

  • 通过名称或路径,通过变量引用和/或名称是单引号或双引号来调用命令。

  • 调用脚本块

脚本块在 PowerShell中传递代码片段的首选方式;上面可以重写为(注意调用机制不会改变,只是传递的参数):

function A {
  Param($scriptBlockToCall)
  Write-Host "I'm calling: $(& $scriptBlockToCall)"
}

Function C {
  "Function C"  # Note: Do NOT use Write-Host to output *data*.
}

A -scriptBlockToCall { C }
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,要传递参数,只需将它们放在:& <commandNameOrScriptBlock>; 请注意如何使用splatting ( @<var>) 传递存储在自动$args变量中的未绑定参数。

function A {
  Param($commandNameOrScriptBlockToCall)
  Write-Host "I'm calling: $(& $commandNameOrScriptBlockToCall @Args)"
}

Function C {
  "Function C with args: $Args"
}


A -commandNameOrScriptBlockToCall C one two # by name
A -commandNameOrScriptBlockToCall { C @Args } one two # by script block
Run Code Online (Sandbox Code Playgroud)

以上产量I'm calling: Function C with args: one two两次。

注意

  • 正如JohnLBevan指出的那样,自动$args变量仅在简单(非高级)脚本和函数中可用。

  • 使用的[CmdletBinding()]上述属性param(...)块和/或每个参数[Parameter()]的属性是什么使一个脚本或功能的先进的一个,和先进的脚本和功能还只接受论点,结合显式声明的参数。

  • 如果您需要使用高级脚本或函数 - 例如支持假设功能[CmdletBinding(SupportsShouldProcess)]- 您可以选择以下方式传递参数:

    • 如果传递位置(未命名)参数就足够了,请声明一个参数,例如[Parameter(ValueFromRemainingArguments)] $PassThruArgs,它隐式收集调用时传递的所有位置参数。

    • 否则,您必须为所有潜在的(命名的)传递参数显式声明参数。

      • 您可以在 PowerShell SDK 的帮助下基于现有命令构建参数声明,PowerShell SDK 是一种用于创建代理(包装器)函数的技术,如本答案所示。
    • 或者,您的函数可以声明一个参数,该参数接受一个表示命名传递参数的哈希表,与 splatting 一起使用;当然,这需要调用者显式构造这样的哈希表。


小智 8

您是否考虑过将ScriptBlock作为参数传递?

$scriptBlock = { Write-Host "This is a script block" }
Function f([ScriptBlock]$s) {
  Write-Host "Invoking ScriptBlock: "
  $s.Invoke()
}

PS C:\> f $scriptBlock
Invoking ScriptBlock:
This is a script block
Run Code Online (Sandbox Code Playgroud)


Fro*_* F. 7

这是你需要的吗?

function A{
    Param($functionToCall)
    Write-Host "I'm calling : $functionToCall"

    #access the function-object like this.. Ex. get the value of the StartPosition property
    (Get-Item "function:$functionToCall").ScriptBlock.StartPosition

}

function B{
    Write-Host "Function B"
}

Function C{
    write-host "Function C"
}


PS> a -functionToCall c

I'm calling : c


Content     : Function C{
                  write-host "Function C"
              }
Type        : Position
Start       : 307
Length      : 43
StartLine   : 14
StartColumn : 1
EndLine     : 16
EndColumn   : 2
Run Code Online (Sandbox Code Playgroud)

  • 不,这只是将字符串“c”传递给函数,而不是将函数对象 C 作为参数传递。 (2认同)

Der*_*rek 5

邓肯的解决方案对我很有用。但是,当函数名称中有破折号时,我遇到了一些问题。

我能够通过构建他的第三个示例来绕过它:

function A{
    Param([scriptblock]$functionToCall)
    Write-Host "I'm calling $($functionToCall.Invoke(4))"
}

function Execute-FunctionWithDash($x)
{
    Write-Output "Function Execute-FunctionWithDash with $x"
}

PS C:\WINDOWS\system32> A -functionToCall { Param($x) Execute-FunctionWithDash $x }
I'm calling Function Execute-FunctionWithDash with 4
Run Code Online (Sandbox Code Playgroud)

  • 可以像这样访问带破折号的函数:`${Function:Do-SomethingCool}` (3认同)