接受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
答
@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 $_"
}
}
这很美丽^^如果我可以添加一些东西,重要的是要注意你不需要在PowerShell的'switch'中打断''。但是,为什么你使用'继续'? – sodawillow
@sodawillow我确定'Continue'用于确保最后一个子句未被验证,并在管道中放置额外的信息。 – Matt
尽管这肯定让我有了一个好地方,但这是行不通的,因为流水线输入直到'Process'部分才会变得可用。如果您尝试按照我的问题中描述的输入原样使用此代码,则会出现错误“您无法在空值表达式上调用方法。”我添加了我使用的最终代码。 – Zoredache