Where-Object не находит ни одного экземпляра пользовательского объекта, но находит несколько его экземпляров. Возможна ошибка?

Я работаю над сценарием, который выполняет вызов API и возвращает результат JSON и обрабатывается как массив пользовательских объектов в Powershell. Одним из свойств пользовательского объекта является статус, поэтому для каждого уникального статуса я хотел получить количество объектов с этим статусом. Я был удивлен, когда мой код для определенных статусов вернул число 0, потому что, если бы он не существовал с самого начала, мой скрипт не искал бы этот статус.

Затем я заметил, что код работает, когда есть более одного объекта со статусом, но когда есть только один объект с таким статусом, мой код не найдет его с помощью Where-Object. Если я перебираю массив пользовательских объектов и выполняю оператор if(), он находит все статусы, включая те, которые имеют только один объект.

Я что-то пропустил здесь или это ошибка? Мой ноутбук работает под управлением PS 5.1, и я также попробовал его на сервере W2K12 с PS 4.0, и я получил то же самое.

Я также смог смоделировать это (удалив части API и JSON) в приведенном ниже коде:

$testArray = @()
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name1' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name2' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status2' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name3' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject

$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name4' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name5' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name6' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject

$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name7' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name8' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name9' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject

$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name10' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject

$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name11' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name12' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name13' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status1' -Force
$testArray += $testObject

$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name14' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name15' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject
$testObject = New-Object -TypeName PSObject
$testObject | Add-Member -type NoteProperty -name Name -value 'Name16' -Force
$testObject | Add-Member -type NoteProperty -name Status -value 'Status3' -Force
$testArray += $testObject


Write-Host "`n`nPowerShell version:"
$PSVersionTable.PSVersion


Write-Host "`n`nUsing Where-Object on the array"
$uniqueStatuses = ( $testArray.Status | sort | Get-Unique )
foreach ($status in $uniqueStatuses)
{
    $status
    ($testArray | Select-Object | Where-Object { $_.Status -eq $status }).Count

}


Write-Host "`n`nLooping through the array"
foreach ($status in $uniqueStatuses)
{
    $status
    [int]$count = 0
    foreach ($object in $testArray)
    {
        if ($object.Status -eq $status)
        {
            $count++
        }   
    }
    $count
}

В приведенном выше примере кода статус Status2 появляется только в одном из настраиваемых объектов, и Where-Object по какой-то причине не находит его, но с помощью foreach находит.

Когда я запускаю код выше, я получаю:

Версия PowerShell:

Основная незначительная редакция сборки


5 1 14393 0

Использование Where-Object в массиве

Статус1

8

Статус2

Статус3

7

Цикл по массиву

Статус1

8

Статус2

1

Статус3

7


person Rim    schedule 12.08.2016    source источник


Ответы (1)


В первом примере (с использованием Where-Object) нет гарантии, что конвейер приведет к созданию коллекции — с Status2 он возвращает только один объект, поэтому Count ничего не возвращает.

Используйте оператор подвыражения массива @(), и вы увидите правильное количество:

$uniqueStatuses = ( $testArray.Status | sort | Get-Unique )
foreach ($status in $uniqueStatuses)
{
    $status
    @($testArray | Select-Object | Where-Object { $_.Status -eq $status }).Count

}
person Mathias R. Jessen    schedule 12.08.2016
comment
Немного зло, однако, учитывая, что неявно каждый объект получает свойство Count, добавляемое при доступе к нему, и оно возвращает 1, например. '1'.count (начиная с PSv3 или около того). По-видимому, это выполняется не во всех случаях. В этом случае я бы, вероятно, переписал код для группировки по статусу, что, я думаю, также даст вам подсчет. - person Joey; 12.08.2016
comment
Отметил это как ответ. Спасибо за понятное объяснение! - person Rim; 12.08.2016