接受Powershell管道中多种形式的计算机列表

问题描述:

我试图创建一个脚本,它接受来自许多不同第三方来源的各种形式的计算机列表,这些计算机不受我控制。这些不同的来源有时会将计算机作为一个简单的字符串数组返回,有时作为Powershell对象,有时作为散列。我希望我的脚本能够使用任何这些类型的列表并获取计算机名称,并将其放入数组中。然后执行实际处理。接受Powershell管道中多种形式的计算机列表

下面是一些可能提供给我正在创建的脚本的数据示例。

@('system-01','system-02') | \\path\share\mycommand.ps1 

@(@{"ComputerName" = "system-01";OtherKey = 'foo'}, 
    @{"ComputerName" = "system-02";OtherKey = 'foo'}) | \\path\share\mycommand.ps1 

@([PSCustomObject]@{ 
    ComputerName = 'system-01' 
    OtherProperties = 'foo' 
    }, 
    [PSCustomObject]@{ 
    ComputerName = 'system-02' 
    OtherProperties = 'foo' 
    }) | \\path\share\mycommand.ps1 

我的剧本目前的模样。

[CmdletBinding()] 
param(
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True, 
    ParameterSetName="ComputerHash")] 
    [hashtable]$ComputerHash, 
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True, 
    ParameterSetName="ComputerArray")] 
    [String[]]$ComputerName, 
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True, 
    ParameterSetName="ComputerObject")] 
    [Object[]]$ComputerObjects 
) 
BEGIN 
{ 
    # create an empty array to build up a list of the computers 
    [email protected]() 
} 
PROCESS 
{ 
    # get all the computers from the pipeline 
    switch ($PsCmdlet.ParameterSetName) 
    { 
     "ComputerArray" { $computers+=$ComputerName; break} 
     "ComputerHash" { $computers+=$ComputerHash.ComputerName; break} 
     "ComputerObject"{ $computers+=$ComputerObjects.ComputerName; break} 
    } 
} 
END 
{ 
    $computers | % { 
     # do the stuff 
     "Do something on $_" 
    } 
} 

不幸的是,我目前得到Parameter set cannot be resolved ...错误。我如何制作我的脚本,以便它基本上可以接受任何类型的管线输入,然后做正确的事情?我应该使用一些更简单的方法吗?

你可以做什么,而不是做出不同的参数集,只是在获得信息后处理它。因此,像:

[CmdletBinding()] 
param(
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True)] 
    $ComputerList 
) 
BEGIN 
{ 
    # create an empty array to build up a list of the computers 
    $computers=Switch($ComputerList.GetType()){ 
     {$_.Name -eq 'Hashtable'}{$ComputerList.ComputerName;Continue} 
     {$ComputerList -is [Array] -and $ComputerList[0] -is [String]}{$ComputerList;Continue} 
     {$ComputerList -is [Array] -and $ComputerList[0] -is [Object]}{$ComputerList.ComputerName} 
    } 
} 
PROCESS 
{ 
} 
END 
{ 
    $computers | % { 
     # do the stuff 
     "Do something on $_" 
    } 
} 

或者,也许更容易:

BEGIN{$Computers=If($ComputerList[0] -is [String]){$ComputerList}Else{$ComputerList.ComputerName}} 

编辑:正如指出的那样,我们没有得到在BEGIN或END块中的数据管道,所以我的思想工作,但我的脚本没有。相反,我们必须按照Zoredache的说法,在PROCESS块中进行操作。他已经发布了他的代码,我确定它的工作非常好,但我想我会发布我的修改版本,所以我的答案不会继续错误,因为,我不喜欢有错误的答案在那里。

Function Test-Function1{ 
[CmdletBinding()] 
param(
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True)] 
    $ComputerList 
) 
BEGIN 
{ 
} 
PROCESS 
{  
    [string[]]$computers+=Switch($ComputerList){ 
     {$_ -is [Hashtable]}{$_.ComputerName;Continue} 
     {$_ -is [String]}{$_;Continue} 
     {$_ -is [Object]}{$_|Select -Expand Computer*} 
    } 
} 
END 
{ 
    $computers | % { 
     # do the stuff 
     "Do something on $_" 
    } 
} 
} 

然后,当我用管道输送数据,它是这样:

@{'ComputerName'='Server1','Server2'}|Test-Function1 
[pscustomobject]@{'Computer'='Server1'},[pscustomobject]@{'ComputerName'='Server2'}|Test-Function1 
'Server1','Server2'|Test-Function1 

他们都回应的预期输出:

Do something on Server1 
Do something on Server2 
+0

这很美丽^^如果我可以添加一些东西,重要的是要注意你不需要在PowerShell的'switch'中打断''。但是,为什么你使用'继续'? – sodawillow

+1

@sodawillow我确定'Continue'用于确保最后一个子句未被验证,并在管道中放置额外的信息。 – Matt

+0

尽管这肯定让我有了一个好地方,但这是行不通的,因为流水线输入直到'Process'部分才会变得可用。如果您尝试按照我的问题中描述的输入原样使用此代码,则会出现错误“您无法在空值表达式上调用方法。”我添加了我使用的最终代码。 – Zoredache

@TheMadTechnician我指出了正确的方向,但他的代码似乎有一些错误,并没有按照我想要的方式安静工作。这里是代码,似乎做我想要的一切。

[CmdletBinding()] 
param(
    [Parameter(Mandatory=$True, 
    ValueFromPipeline=$True)] 
    $PipelineItem 
) 
BEGIN 
{ 
    [email protected]() 
} 
PROCESS 
{ 
    $ComputerList+= 
     Switch($PipelineItem.GetType()) { 
      {$_.Name -eq 'String'} 
       {$PipelineItem} 
      {$_.Name -eq 'Hashtable'} 
       {$PipelineItem.ComputerName} 
      {$_.Name -eq 'PSCustomObject' -and (Get-Member -MemberType Properties -Name "Computer" -InputObject $PipelineItem)} 
       {$PipelineItem.Computer} 
      {$_.Name -eq 'PSCustomObject' -and (Get-Member -MemberType Properties -Name "ComputerName" -InputObject $PipelineItem)} 
       {$PipelineItem.ComputerName} 
     } 
} 
END 
{ 
    $ComputerList | % { 
     # do the stuff 
     "Do something on $_" 
    } 
}