【问题标题】:How to call a script with unknown parameters如何调用未知参数的脚本
【发布时间】:2022-10-02 01:42:41
【问题描述】:

我有一个脚本可以调用其他人管理的其他脚本。它本质上是一个 CI/CD 脚本,使用户能够利用管道。

我现在遇到的问题是我希望这个调用脚本实现几个新参数。但是,旧脚本并不总是实现这些参数。

如果我调用他们没有实现参数的脚本,我会得到一个错误“找不到与参数名称匹配的参数”。

有没有办法动态传入参数,这样如果参数不存在就不会失败?我不介意他们不实施它。这是他们不需要使用的奖励参数。

或者,我可以为自定义 .ps1 脚本执行 Get-Command 之类的操作,以获取接受的参数列表吗?这样,我可以在传递参数之前确认参数已实现。

    标签: powershell


    【解决方案1】:

    这可能会帮助您入门,您可以使用Parser Class 从脚本中获取所有函数及其参数,这个答案显示了最小的复制。我会留给你进一步调查。

    鉴于 myScript.ps1 具有以下 3 个功能:

    function ExampleFunc {
        param([int] $param1 = 123, [string] $param2)
    }
    
    function ExampleFunc2 {
        param([object] $param3, [switch] $param4)
    }
    
    function ExampleFunc3 ($param5, [hashtable] $param6 = @{foo = 'var'}) {
    
    }
    

    您可以使用ParseFile Method 来获取AST,然后您可以使用.FindAll method 过滤所有FunctionDefinitionAst,然后找到过滤所有ParameterAst 的所有参数。

    using namespace System.Management.Automation.Language
    
    $ast = [Parser]::ParseInput($myscript, [ref] $null, [ref] $null)
    $ast.FindAll({ $args[0] -is [FunctionDefinitionAst] }, $true) | ForEach-Object {
        $out = [ordered]@{ Function = $_.Name }
        $_.FindAll({ $args[0] -is [ParameterAst] }, $true) | ForEach-Object {
            $out['ParameterName'] = $_.Name.VariablePath
            $out['Type']          = $_.StaticType
            $out['DefaultValue']  = $_.DefaultValue
            [pscustomobject] $out
        }
    } | Format-Table
    

    对于myScript.ps1,上面的代码将导致以下结果:

    Function     ParameterName Type                                         DefaultValue
    --------     ------------- ----                                         ------------
    ExampleFunc  param1        System.Int32                                 123
    ExampleFunc  param2        System.String
    ExampleFunc2 param3        System.Object
    ExampleFunc2 param4        System.Management.Automation.SwitchParameter
    ExampleFunc3 param5        System.Object
    ExampleFunc3 param6        System.Collections.Hashtable                 @{foo = 'var'}
    

    使用Get-Command 也可以实现相同的目的:

    (Get-Command 'fullpath\to\myScript.ps1').ScriptBlock.Ast.FindAll({
        ... same syntax as before ... }, $true # or $false for non-recursive search
    )
    

    【讨论】:

    • 圣地亚哥。那很完美。我已经确认我可以使用它来获取脚本中所有参数(或任何内容)的列表。真是令人印象深刻。我确实需要使用 PowerShell 7.0 而不是我在几个地方得到的 5.1,但这是可以实现的。
    • @ScottForsyth 我很高兴这很有帮助,我添加了一个专门针对脚本中的函数的最小示例,但是,您可以通过遍历 AST 找到所有内容。我不想太详细,因为这是一个相当复杂的话题,我个人认为自己知识不够
    • Santiago(或其他任何人),我重新开始工作,发现 PowerShell 7 已经支持可选参数。如果传入的参数未在脚本中实现,它不会失败。在 PowerShell 5.1 中,情况并非如此,它引发了异常。在升级所有 DevOps 代理以使用 PowerSehll 7 后,它“正常工作”。这使它变得更容易,而且我毕竟不必使用 AST(尽管了解 AST 很有帮助)
    • @ScottForsyth我不知道这样的事情,我相信您指的是未实现cmdletbinding的脚本或函数,在这种情况下,如果您传递目标函数中不存在的参数,它将被忽略获得异常(适用于 WinPS 和 PS Core)。一个简单的例子function test {param($s, $d) $s, $d}; test -s asd -d zxc -x asd-x 是一个不存在的参数,但它会被忽略,因为该函数不是高级函数)
    • 你是对的,还有别的东西在起作用。毕竟这不是 PS 5.1 和 7.2 的区别。我也可以通过测试“get-childitem -abc”看到它。在我的控制台窗口中,那些因未知参数而失败。但是,从 VS Code 终端窗口(也是 7.2.3),它不会失败。幸运的是,DevOps 代理似乎也没有抱怨。我现在有一个解决方案,但我不确定是什么设置切换了这种差异。
    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 2011-10-10
    • 2017-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多