在Powershell函数中处理管道和参数输入

时间:2012-03-06 23:38:41

标签: powershell

我对在一个月的午餐中学习PowerShell一书中看到的内容感到困惑。在第21章中,当作者讨论通过参数绑定或管道接受输入的函数时,他给出了两种模式。

第一个如下

function someworkerfunction {
# do some work
}
function Get-SomeWork {
   param ([string[]]$computername)
   BEGIN {
      $usedParameter = $False
      if($PSBoundParameters.ContainsKey('computername')) {
         $usedParameter = $True
      }   
   }
   PROCESS {
      if($usedParameter) {
         foreach($computer in $computername) {
            someworkerfunction -computername $comptuer
         }
      } else {
         someworkerfunction -comptuername $_
      }
   }

   END {}
}

第二个像这样

function someworkerfunction {
# do stuff
}
function Get-Work {
   [CmdletBinding()]
   param(
      [Parameter(Mandatory=$True,
      ValueFromPipelineByPropertyName=$True)]
      [Alias('host')]
      [string[]]$computername
   )
   BEGIN {}
   PROCESS {
      foreach($computer in $computername) {
         someworkerfunction -comptuername $computer
      }
   }
   END {}
}

我知道第二个样本是标准的Powershell 2.0 Advanced功能。我的问题是Powershell 2.0对cmdletbinding指令的支持你是否想要使用第一个模式。这只是Powershell 1.0的遗产吗?基本上有一段时间使用Powershell 2.0时我会想要第一个模式,第二个模式更清洁。

任何见解都将受到赞赏。

谢谢。

5 个答案:

答案 0 :(得分:3)

如果您想在函数中处理管道输入但不想添加所有参数属性或想要向后兼容,请使用cmdletbinding方法。

如果您想使用PowerShell脚本cmdlet的其他功能,例如参数属性,参数集等,那么请使用第二个功能。

答案 1 :(得分:2)

如果有人希望有关如何从管道输入读取的非常简单的解释,请参阅

How do you write a powershell function that reads from piped input?

如果我有这个问题,这个^存在,我会节省很多时间,因为这个线程非常复杂,并没有真正解释如何处理函数中的流水线输入。

答案 2 :(得分:2)

不,第一个例子不仅仅是遗产。为了创建一个使用数组参数并接受管道输入的PowerShell函数,你必须做一些工作。

我甚至会说第二个例子不起作用。至少我无法让它发挥作用。

以此为例......

function PipelineMadness()
{
   [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        [int[]] $InputArray
    )

    Write-Host ('$InputArray.Count {0}' -f $InputArray.Count)
    Write-Host $InputArray

    Write-Host ('$input.Count {0}' -f $input.Count)
    Write-Host $input

    if($input) { Write-Host "input is true" }
    else { Write-Host "input is false" }
}

结果......

PS C:\Windows\system32> 1..5 | PipelineMadness
$InputArray.Count 1
5
$input.Count 5
1 2 3 4 5
input is true

PS C:\Windows\system32> PipelineMadness (1..5)
$InputArray.Count 5
1 2 3 4 5
$input.Count 1

input is false

请注意,使用管道时,$InputArray变量的单个值为5 ...

现在使用BEGIN和PROCESS块

function PipelineMadnessProcess()
{
    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        [int[]] $InputArray
    )

    BEGIN
    {
        Write-Host 'BEGIN'
        Write-Host ('$InputArray.Count {0}' -f $InputArray.Count)
        Write-Host $InputArray

        Write-Host ('$input.Count {0}' -f $input.Count)
        Write-Host $input

        if($input) { Write-Host "input is true" }
        else { Write-Host "input is false" }
    }

    PROCESS
    {
        Write-Host 'PROCESS'
        Write-Host ('$InputArray.Count {0}' -f $InputArray.Count)
        Write-Host $InputArray

        Write-Host ('$input.Count {0}' -f $input.Count)
        Write-Host $input

        if($input) { Write-Host "input is true" }
        else { Write-Host "input is false" }
    }
}

现在这是奇怪的地方

PS C:\Windows\system32> 1..5 | PipelineMadnessProcess
BEGIN
$InputArray.Count 0

$input.Count 0

input is false
PROCESS
$InputArray.Count 1
1
$input.Count 1
1
input is true
PROCESS
$InputArray.Count 1
2
$input.Count 1
2
input is true

...

PROCESS
$InputArray.Count 1
5
$input.Count 1
5
input is true

BEGIN块根本没有任何数据。并且过程块效果很好,但是如果你有一个foreach的例子它会实际工作,但是它将运行foreach并输入1次X次。或者如果您传入数组,它将使用完整集运行foreach一次。

所以我觉得从技术上说这个例子可行,但它可能不会像你期望的那样工作。

另请注意,即使BEGIN块没有数据,该函数也会通​​过语法验证。

答案 3 :(得分:1)

为了回答你的问题,我想说第一个模式只是PowerShell 1.0的遗产,你也可以在没有Process脚本块的经典函数中使用$input。至于你只是为PowerShell 2.0编写代码,你可以忘记它。

关于管道功能,在powerShell V1.0中,可以使用filters处理它们。

你必须知道,当你从网上采集样本或者你必须调试旧的Powerhell代码时,它已经完成了。

我个人仍然在我的模块中使用旧的functionsfilters,我保留cmdletbinding用于导出函数或配置文件函数。

Powershell有点像乐高积木,你可以用很多不同的方式做很多事情。

答案 4 :(得分:0)

第一种形式是将一个或多个计算机名称作为参数列表或管道的字符串参数。

第二种形式是期望参数列表中的字符串参数数组,或者管道中具有计算机名称作为属性的输入对象。