powershell - 能否将 CmdletBinding 与未绑定(bind)参数结合使用?

标签 powershell parameter-passing

(Powershell 5)
我有以下合并功能:

(更新:删除了 process block 中的“优化”continue 调用。)

function Find-Defined {
    begin   { 
        $ans  = $NULL;
        $Test = { $_ -ne $NULL };
    }
    process { 
        if ( $ans -eq $NULL ) {
            $ans = $_ |? $Test | Select -First 1;
        }
    }
    end     {
        if ( $ans -ne $NULL ) { 
            return $ans;
        }
        else {
            $Args `
                |% { if ( $_ -is [Array] ) { $_ |% { $_ } } else { $_ } } `
                |? $Test `
                | Select -First 1 `
                | Write-Output `
                ;
        }
    }
}

这对我来说非常有效,在如下命令行中:

$NULL, $NULL, 'Legit', 1, 4 | Find-Defined;

$NULL, $NULL | Find-Defined $NULL, @( $NULL, 'Value' ), 3;

$NULL, $NULL | Find-Defined $NULL $NULL 3 4;

您可能会注意到我将决策逻辑封装在一个ScriptBlock 变量中。这是因为我想对其进行参数化,因此我开始尝试这样做。

[CmdletBinding()]param( [ScriptBlock] $Test = { $_ -ne $NULL } );

但是,在我添加 CmdletBinding 的那一刻,我开始出现错误。绑定(bind)想要尝试将参数部分中的所有内容转换为 ScriptBlock,因此我添加了

[CmdletBinding(PositionalBinding=$False)]

然后它提示无法绑定(bind)未绑定(bind)的参数,所以我添加了:

param( [parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)][Object[]] $Arguments ...

然后无论我做什么,都会添加一个新错误。如果我删除了 $Test 参数,只是将其本地化以查看我能做什么,然后我开始遇到开发第一代时遇到的错误:

The input object cannot be bound to any parameters for the command either 
because the command does not take pipeline input or the input and its 
properties do not match any of the parameters that take pipeline input.

... 即使我有一个 process block 。

最后干脆去掉param语句,把它放回我喜欢的灵活函数。

我仍然想扩展此功能以接受 ScriptBlock 测试和 unbound 参数(以及 -Verbose 等常用参数,如果可能的话)。这样我也可以有一个通用的字符串合并算法:

$Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen'

我错过了什么吗?

最佳答案

我相信这可以解决您要解决的问题,但实现方式有所不同。使用 CmdletBinding 时,必须声明所有内容。因此,您需要一个参数用于管道输入,一个参数用于“未绑定(bind)”参数。

根据你的问题我写了这些测试用例:

Describe 'Find-Defined' {
  it 'should retun Legit' {
    $NULL, $NULL, 'Legit', 1, 4 | Find-Defined | should be 'Legit'
  }
  it 'should retun Value' {
    $NULL, $NULL | Find-Defined  $NULL, @( $NULL, 'Value' ), 3 | should be 'Value'
  }
  it 'should retun 3' {
    $NULL, $NULL | Find-Defined $NULL $NULL 3 4 | should be '3'
  }
  it 'Should return "This should be it"' {
    $Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
    $NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen'  | should be 'This should be it'
  }
}

这是我的解决方案,它通过了上述所有情况。

function Find-Defined {
  [CmdletBinding()]
  param (
    [ScriptBlock] $Test = { $NULL -ne $_},
    [parameter(Mandatory=$False,ValueFromPipeline =$true)]
    [Object[]] $InputObject,
    [parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
    [Object[]] $Arguments
  )

    begin   { 
        $ans  = $NULL;

        function Get-Value {
          [CmdletBinding()]
          param (
            [ScriptBlock] $Test = { $_ -ne $NULL },
            [parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
            [Object[]] $Arguments,
            $ans = $NULL
          )
          $returnValue = $ans
          if($null -eq $returnValue)
          {
            foreach($Argument in $Arguments)
            {
              if($Argument -is [object[]])
              {
                $returnValue = Get-Value -Test $Test -Arguments $Argument -ans $returnValue
              }
              else
              {
                if ( $returnValue -eq $NULL ) {
                    $returnValue = $Argument |Where-Object $Test | Select-Object -First 1;
                    if($null -ne $returnValue)
                    {
                      return $returnValue
                    }
                }
              }
            }
          }
          return $returnValue
        }
    }
    process { 
        $ans = Get-Value -Test $Test -Arguments $InputObject -ans $ans
    }
    end     {
        $ans = Get-Value -Test $Test -Arguments $Arguments -ans $ans

        if ( $ans -ne $NULL ) { 
            return $ans;
        }
    }
}

关于powershell - 能否将 CmdletBinding 与未绑定(bind)参数结合使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37709429/

相关文章:

powershell - 在 Powershell 中计算日志结果

rest - 如何从 PSMethod 类型返回有意义的结果

c# - 打包参数的好设计?

powershell - Import-Module 找不到部分路径

powershell - 与 Powershell 等效的 awk 命令

c# - 在一个类中定义 MySqlConnection 并在另一个类中使用它来处理数据库

Python:如何使用变量传递参数名称

objective-c - 修改 iOS 中的 BOOL 内部方法

javascript - 将字符串列表作为参数从 native java 代码传递给 javascript 函数

mysql - 在 powershell 中将参数传递给 mysql.exe