'.Count' not working when array only contains 1 entry, simple arrays work

I had logic in my script to display specific messages when the array count was zero or 1.
1 was never working so I investigated further.
Whenever my array had a size of 1, the ‘.Count’ value was always Null.
I found this to be the case with arrays created by commands: Get-DistributionGroupMember, Get-AzureADGroupOwner, Get-AzureADGroupMember, and Get-MailboxPermission

$PSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://outlook.office365.com/PowerShell-LiveId/' -Credential XXXXXXXXXXXXXXX -Authentication Basic -AllowRedirection
Import-PSSession $PSSession -DisableNameChecking -AllowClobber
$DistributionList = Get-DistributionGroup | Select DisplayName, Identity | Sort DisplayName
ForEach ($D in $DistributionList) {
Write-Output $D.DisplayName
$Members = Get-DistributionGroupMember -Identity $D.Identity | Select DisplayName, Id | Sort DisplayName
Write-Output $Members.Count
[Int]$Count = 0
ForEach ($M in $Members) {
$Count++
}
Write-Output "ForEach count: $Count"
}
Remove-PSSession $PSSession

Results showing 0, 1, and 27 Members (notice there is no ‘.Count’ displayed for ‘A’:

A
ForEach count: 1
B
0
ForEach count: 0
C
27
ForEach count: 27

Oddly enough, the count works for 1 when the array is simple:

$myArray = @()
Write-Output $myArray.Count
$myArray = @('A')
Write-Output $myArray.Count
$myArray = @('A', 'B', 'C')
Write-Output $myArray.Count

Results:

0
1
3

My PS Version Info
$psversiontable
Name Value


PSVersion 5.1.18362.145
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
BuildVersion 10.0.18362.145
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

When more than 1 object is returned from the cmdlet, an array is created, as expected. When only 1 is returned, though, the variable storing the results is actually the type of object of results.

PS /Users/cmdowning/Scripts> $arr = gci -File | ForEach-Object { $_.Name }
PS /Users/cmdowning/Scripts> $arr.GetType()                                                                                                           

IsPublic IsSerial Name                                     BaseType                                                                                  
-------- -------- ----                                     --------                                                                                  
True     True     String                                   System.Object 
PS /Users/cmdowning/Scripts> $arr2 = gci -File -Path ../Downloads/ | ForEach-Object { $_.Name }
PS /Users/cmdowning/Scripts> $arr2.gettype()                                                                                                          

IsPublic IsSerial Name                                     BaseType                                                                                  
-------- -------- ----                                     --------                                                                                  
True     True     Object[]                                 System.Array 

To elaborate on what Charles D posted, you can ‘force’ the output type to System.Array even if there is just one object being returned:

$DistributionList = @(Get-DistributionGroup | Select-Object -Property DisplayName, Identity | Sort-Object -Property DisplayName)
...

 

Thanks Charles D and Aaron Hardy! Useful information and will begin forcing an array when I expect an array!

That’s right. @() forces the result to always be an array. People often initialize an array like this:

$a = @(1,2,3)

But the @() is unnecessary in that case. The comma is an operator.

$a = 1,2,3