首页 > 解决方案 > Powershell脚本不输出第二个Where-Object

问题描述

执行脚本时,它给出以下内容,虽然它给出了第一个 Where-Object {$_.Name -like "$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

标签: powershell

解决方案


怀疑它是这条线的公元前

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”,所以 where-object 比较实际上只是每次过滤一个由单个对象组成的“组”。它似乎有效,因为不可避免地迭代对象最终将是匹配条件的对象,但是请注意,当循环完成时,“$object”现在仅指向被迭代的最终对象(good ol' 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 

上面的代码什么也没产生。它只是默默地接受命令并且不返回任何值(不是真/假,甚至不是空值),不发出警告。因为它实际上做的是顺序测试与列表中每个项目的比较,并且只返回那些适合的——就像 where-object 一样!

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

'c'

也许您可以看到将它们结合使用充其量是多余的,最坏的情况是吞噬内存/时间。

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


推荐阅读