【问题标题】:Calling a function variably变量调用函数
【发布时间】:2021-11-27 12:55:58
【问题描述】:

我有几个 PS1,其中的功能格式为“Invoke-T1234”、“Invoke-T1235”等。 我想在 PS 模块中创建一个函数,允许用户通过参数调用这些 PS1 之一,例如“Invoke-Script -Script T1234”,然后运行“Invoke-T1234”。是否可以将变量传递给调用脚本的函数,这样我就不必创建多个“If”子句了?

例如

function Invoke-Script {
        param (
        [Parameter(Mandatory = $false)]       
            [string]$Script= ""
        )
    If ($Script){
    Invoke-$Script    
    }

显然这是行不通的,因为 PowerShell 是按字面意思解释 $Script 而不是值。

我知道我能做到

If ($Script -eq T1234){
Invoke-T1234}

但是 PS1 有很多,所以我想用尽可能少的代码做到这一点。

【问题讨论】:

标签: .net powershell


【解决方案1】:

您可以使用Get-Command 根据参数发现目标函数:

function Invoke-TScript
{
  param(
    [int]$ScriptID
  )

  $cmd = Get-Command "Invoke-T${ScriptID}" -ErrorAction SilentlyContinue
  if($cmd){
    & $cmd @args
  }
  else {
    Write-Error "No function named 'Invoke-T${ScriptID}' available"
  }
}

在函数中自动添加$args 变量意味着任何额外的参数参数都将被传递给目标脚本。

现在你可以这样做了:

Invoke-TScript -ScriptID 1234 -ScriptParam 'script argument'

然后执行:

Invoke-T1234 -ScriptParam 'script argument'

【讨论】:

    【解决方案2】:

    使用Get-Command来发现和测试命令的存在,如Mathias R. Jessen's helpful answer所示,绝对是一种选择,但如果你知道命令(函数)的具体名称,如你的情况,就足够了使用&call operator,它可以调用通过a(n可扩展)字符串变量表达式

    # Use an expandable string to construct the target command name
    # and invoke it with &
    # If needed, pass arguments as you usually would; e.g.
    #   & "Invoke-$Script" foo bar
    & "Invoke-$Script"
    
    • 你甚至不需要在这里引用(封闭的"..."):& Invoke-$Script 就可以了。

      • 由于传递给& 的参数在argument(-parsing) mode 中解析,因此PowerShell 通常会将包含变量引用(例如Invoke-$Script)的未加引号的参数隐式 视为expandable string,即好像它们已明确包含在 "..." 中。但是,存在陷阱,因此养成明确使用"..." 的好习惯 - 有关背景信息,请参阅this answer
    • 相反,当引用 is 时,& 的使用是必需,即使是 逐字 字符串,而 未引用,逐字逐句 命令名称和路径需要&(但可以与它一起使用);例如c:\foo\script.ps1 也可以不使用 &,但
      & 'c:\foo\script file.ps1' 需要 &。有关背景信息,请参阅this answer

    在您的代码上下文中,使用错误处理程序:

    function Invoke-Script {
            param (
            [Parameter(Mandatory = $false)]       
                [string]$Script= ""
            )
        if ($Script) {
          try {
            & "Invoke-$Script"
          } catch {
            throw "Failed to call 'Invoke-$Script': $_"
          }
        }
    }
    

    【讨论】:

    • 我会补充一点,这个答案确实不会创建命令注入漏洞,即使它看起来可能。这是因为 & 运算符会将传递给第一个参数的任何内容视为文字可执行文件/脚本名称。例如,如果您传递"234; whoami",则脚本将出错,而不是执行Invoke-234 然后whoami。这可以防止任何可以访问$Script 参数的人只执行他们想要的任何操作,这很好。
    • 谢谢,@spicy.dll;只是为了明确您的评论所暗示的内容:& 具有动态构造的命令名称/路径是 Invoke-Expression (iex) 的安全替代品,其使用很少被证明是合理的,通常是 should not be used to invoke an external program or PowerShell command
    猜你喜欢
    • 2011-09-08
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多