Powershell脚本不输出第二个Where-Object



当脚本执行时,它给出了以下内容,当它给出第一个Where-Object{$_。如果名称像"$LDDCSRV"}一样正确,它不会正确地给出第二个变量,只打印列出的内容,而不是引用的变量。有什么建议吗?我不知道哪里出了问题。

脚本

# Discovery Cluster Services
# Counter
$C = 0

$LDDCSRV = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource)
# Counter
$C = 0
$F = $LDDCSRV.Count
# Start JSON
Write-Host "{"
Write-Host " `"data`":["
# For each server in $LDDCSRV
Foreach ($LDDCSRV in $LDDCSRV)
{
# Counter to not print comma after last object
$C++
Write-Host "   {"

$LDDServices = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource) | Where-Object {$_.Name -like "$LDDCSRV"}
$LDDServiceState = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource) | Where-Object {$_.State -like "$LDDCSRV"}

if ($LDDServices -ne "") 
{ Write-Host "     ""{#CLSRV}"": ""$LDDServices""" }
{ Write-Host "     ""{#SSTATE}"": ""$LDDServiceState""" }

if ($C -lt $F) { Write-Host "   }," }
else { Write-Host "   }" }
}
Write-Host " ]"
Write-Host "}"

# Counter
$C = 0


$LDDCSRV = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource)
# Counter
$C = 0
$F = $LDDCSRV.Count

# Start JSON
Write-Host "{"
Write-Host " `"data`":["

# For each server in $LDDCSRV
Foreach ($LDDCSRV in $LDDCSRV)
{
# Counter to not print comma after last object
$C++
Write-Host "   {"

$LDDServices = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource) | Where-Object {$_.Name -like "$LDDCSRV"}
$LDDServiceState = (Get-ClusterGroup -Cluster "HV-CL01" -Name "Cluster Group" | Get-ClusterResource) | Where-Object {$_.State -like "$LDDCSRV"}

if ($LDDServices -ne "") 
{ Write-Host "     ""{#CLSRV}"": ""$LDDServices""" }
{ Write-Host "     ""{#SSTATE}"": ""$LDDServiceState""" }

if ($C -lt $F) { Write-Host "   }," }
else { Write-Host "   }" }

}
Write-Host " ]"
Write-Host "}"

输出
{
"data":[
{
"{#CLSRV}": "Cloud Witness"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
},
{
"{#CLSRV}": "Cluster IP Address"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
},
{
"{#CLSRV}": "Cluster Name"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
},
{
"{#CLSRV}": "Health"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
},
{
"{#CLSRV}": "SDDC Management"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState""" 
},
{
"{#CLSRV}": "Storage Qos Resource"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
},
{
"{#CLSRV}": "Virtual Machine Cluster WMI"
Write-Output "     ""{#SSTATE}"": ""$LDDServiceState"""
}
]
}

预期输出

{
"data":[
{
"{#CLSRV}": "Cloud Witness"
""{#SSTATE}"": ""Online"""
},
{
"{#CLSRV}": "Cluster IP Address"
""{#SSTATE}"": ""Online"""
},
{
"{#CLSRV}": "Cluster Name"
""{#SSTATE}"": ""Online"""
},
{
"{#CLSRV}": "Health"
""{#SSTATE}"": ""Online"""
},
{
"{#CLSRV}": "SDDC Management"
""{#SSTATE}"": ""Online""" 
},
{
"{#CLSRV}": "Storage Qos Resource"
""{#SSTATE}"": ""Online"""
},
{
"{#CLSRV}": "Virtual Machine Cluster WMI"
""{#SSTATE}"": ""Online"""
}
]
}

正在解析的数据,

Name                        State  OwnerGroup    ResourceType
----                        -----  ----------    ------------
Cloud Witness               Online Cluster Group Cloud Witness
Cluster IP Address          Online Cluster Group IP Address
Cluster Name                Online Cluster Group Network Name
Health                      Online Cluster Group Health Service
SDDC Management             Online Cluster Group SDDC Management
Storage Qos Resource        Online Cluster Group Storage QoS Policy Manager
Virtual Machine Cluster WMI Online Cluster Group Virtual Machine Cluster WMI

怀疑这一行的bc

Foreach ($LDDCSRV in $LDDCSRV)

你需要一个唯一的变量标识符来标识当前迭代对象和要迭代的集合——这样当你在循环中时,你和解释器就可以知道你引用的是哪个对象。否则,你就会交叉手指,希望powershell只从控制语句的范围内正确地解释一切(它似乎没有这样做)

考虑下面这个超级简单的例子,我创建了4个基本对象,把它们放在一个数组中,然后在foreach循环

中使用相同名称的变量遍历它们
$alf = [PSCustomObject]@{
name = "alf"; occupation = "astronaut"
}
$bob = [PSCustomObject]@{
name = "bob"; occupation = "builder"
}
$charles = [PSCustomObject]@{
name = "charles"; occupation = "cheesemonger"
} 
$david = [PSCustomObject]@{
name = "david"; occupation = "drugdealer"
} 
$object = @($alf, $bob, $charles, $david)
foreach ($object in $object)
{
$test = $object | Where-Object { $_.name -like "charles" }
Write-Host ("Filter result count: " + $test.Count)
Write-Host($test)
} 
Write-Host($object)

它产生以下输出

Filter result count: 0
Filter result count: 0
Filter result count: 1
@{name=charles; occupation=cheesemonger}
Filter result count: 0
@{name=david; occupation=drugdealer}

因为集合和迭代对象都命名为"$object",对象的位置比较实际上只是过滤一个"组"每次只包含一个对象的。似乎起作用,因为迭代的对象最终将不可避免地是匹配条件的对象,但请注意,当循环完成时,"$object"现在只指向被迭代过的最后一个对象(老好人David the drugdealer)作为"$object"引用被每个循环覆盖。

这个例子更清楚地展示了潜在的问题,特别是当与$object

的某些条件或属性进行比较时。
$alf     = "alf"  
$bob     = "bob"  
$charles = "charles"  
$david   = "david" 
$object = @($alf, $bob, $charles, $david) 
foreach ($object in $object)
{
$test = $object | Where-Object { $_ -like $object }
Write-Host ("Filter result count: " + $test.Count)
Write-Host($test)
} 
Write-Host($object)

输出
Filter result count: 1
alf
Filter result count: 1
bob
Filter result count: 1
charles
Filter result count: 1
david
david

每次bc $object改变它指向的对象时,它都会找到一个匹配项。这些显然是非常人为的例子,并不能完全反映出在你的情况下发生的事情,但它们至少应该清楚地表明这种方法可能造成混乱/破坏,特别是在将其应用于更复杂的对象和组时。

我会从

这一行开始重构
Foreach ($Server in $ServerGroup) 

或任何对你的用例最有意义的东西,看看这是否会导致一些更预期的行为

有点切题,但我觉得"Where-Object"Cmdlet被赋予了一个非常不直观的名字。从语义上讲,它意味着对单个对象求值,但这根本不是它的用途。它用于筛选对象,只返回组中符合给定条件的对象。所以通常你不需要在foreach循环中使用它,或者根本不需要使用foreach循环,因为Where-Object"当Cmdlet被调用时,它会在后台做这些。但是由于powershell超灵活的类型推断和"任何东西都是一个集合,即使它只是一个集合";从哲学的角度来看,很容易错误地使用这个命令,而不会得到任何警告。

$d = @('a','b','c')
$d -like $d 

上面的代码没有产生任何结果。它只是默默地接受命令,不返回任何值(不是true/false,甚至不是null),也不给出任何警告。因为它实际上做的是顺序地测试列表中的每个元素的比较,并只返回那些适合的——就像where-object做的那样!

$d = @('a','b','c')
$d -like 'c'
'c'

也许你可以看到,将它们结合使用在最好的情况下可能是多余的,在最坏的情况下可能会占用内存/时间。

Powershell喜欢"乐于助人"。如果你给它一个组和一个通常用于评估单个对象的条件,它会假设你一定想对组中的每个对象单独测试那个条件,所以它通常会这样做,即使在对我们来说没有逻辑意义的情况下,它也不会说什么。这对我来说是最难适应的事情之一,它仍然时不时地把我绊倒

最新更新