powershell 传递函数作为参数

sshcrbum  于 2023-11-18  发布在  Shell
关注(0)|答案(9)|浏览(175)

我写了一个函数“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

字符串
返回:我正在调用:C
我期待它返回:我正在调用:函数C。
我试过各种各样的方法,比如:

Param([scriptblock]$functionToCall)


无法将System.String转换为ScriptBlock

A -functionToCall $function:C


返回“写主机“函数C”

A - functionToCall (&C)


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

Function C
 I'm Calling :


我相信这是编程101,但我不能工作出正确的语法或它是我做错了。

deikduxw

deikduxw1#

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

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

字符串

9fkzdhlc

9fkzdhlc2#

你有没有想过把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

字符串

u0njafvf

u0njafvf3#

**如果你真的想传递函数的 name,作为一个 string:使用&,*call操作符 * 来调用它:

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

字符串
至于需要在"..."中使用$(...):请参阅this answer,它解释了PowerShell的字符串扩展(字符串插值)规则。
上面的结果是I'm calling: Function C
注意函数C如何使用 implicit 输出(与显式使用Write-Output相同)来返回值。
Write-Host is generally the wrong tool to use,除非意图明确地只写入显示,绕过PowerShell的输出流。
在以下情况下,通常需要&运算符:

  • 通过名称或路径调用命令,通过 * 变量引用 * 和/或如果名称是单引号或双引号。
  • 调用 * 脚本块 *。
  • Script blocks * 是在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 }


在这两种情况下,**要传递 * 参数 *,只需将它们放在:& <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


上面的结果是I'm calling: Function C with args: one two两次。

备注

  • 正如JohnLBevan所指出的,自动$args变量仅在 * 简单 *(非高级)脚本和函数中可用。
  • param(...)块上使用[CmdletBinding()]属性和/或每参数[Parameter()]属性是使脚本或函数成为advanced的原因,高级脚本和函数另外只接受绑定到 * 显式声明 * 参数的参数。
  • 如果您需要使用高级脚本或函数-例如支持[CmdletBinding(SupportsShouldProcess)]的假设功能-您可以使用以下选项来传递参数:
  • 如果传递 * 位置 *(未命名)参数就足够了,那么声明一个参数,如[Parameter(ValueFromRemainingArguments)] $PassThruArgs,它隐式地收集调用时传递的所有位置参数。
  • 否则,必须为所有潜在的(命名的)传递参数显式声明参数。
  • 您可以在PowerShell SDK的帮助下基于现有命令来搭建参数声明,这是一种用于创建代理( Package 器)函数的技术,如this answer所示。
  • 或者,你的函数可以声明一个单一的参数,它接受一个 hashtable,表示命名的传递参数,用于splarting;当然,这需要调用者显式地构造这样一个hashtable。
u5i3ibmn

u5i3ibmn4#

你需要这个吗?

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

字符串

hm2xizp9

hm2xizp95#

邓肯的解决方案对我来说很有效。然而,当函数名中有破折号时,我遇到了一些问题。
我可以通过他的第三个例子来解决这个问题:

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

字符串

vktxenjb

vktxenjb6#

用于传递沿着数量可变的命名参数

function L($Lambda){
   write-host "`nI'm calling $Lambda"
   write-host "`nWith parameters"; ft -InputObject $Args
   & $Lambda @Args
}

字符串
似乎可以很好地处理奇怪的函数名

function +Strange-Name($NotUsed,$Named1,$Named2){
   ls -filter $Named1 -Attributes $Named2
}

PS C:\>L +Strange-Name -Named1 *.txt -Named2 Archive


和exe文件以及

PS C:\>L grep.exe ".*some text.*" *.txt


不过看起来你还是要小心注射

function inject($OrigFunction){
   write-host 'pre-run injection'
   & $OrigFunction @Args
   write-host 'post-run injection'
}

PS C:\>L inject +Strange-Name -Named1 *.txt -Named2 Archive

7bsow1i6

7bsow1i67#

function strdel($a,$b,$c) {
    return ($a.substring(0,$b)+$(substr $a $c $a.length))
}
function substr($a,$b,$c) {
    return $a.substring($b,($c-$b))
}

$string = "Bark in the woods"
$in = $(substr $(strdel $string 0 5) 0 2)
write-host $in

字符串
其中函数“substr”调用函数“strdel”作为$a参数。
来自https://github.com/brandoncomputer/vds的函数

hc8w905p

hc8w905p8#

怎么样:

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

function B{
    "Function B"
}

Function C{
    "Function C"
}

A -functionToCall ${function:C}

字符串
使用${function:...}将函数路径作为值。调用该函数并将结果保存到$res。

k4ymrczo

k4ymrczo9#

匿名函数/应用函数(其中参数是某些变量的值)

function MyPrint($x,$y) { Write-Host "$x $y"}
$txt="Hi"; $num=101

# 2-stage definition of anon function (don't ask why...)
$_f = {param($x,$y) MyPrint $x $y}

# "copy" existing vars into new scope
$f  = {& $_f $txt $num}.GetNewClosure()

$f.Invoke()            # "Hi 101"
$txt="Nooo"; $num=777
$f.Invoke()            # Still "Hi 101"

MyButton.Add_Click($f) # Use in callbacks

字符串

相关问题