3

Given a list with some duplicate items, I can use Group-Object -AsHashtable and I get a hash table that seems to have keys with the item names, and the value is something I don't recognize.

So, given

$array = [System.Collections.Generic.List[String]]@('A', 'B', 'C', 'B', "c", 'C')
$grouped = $array | Group-Object -AsHashTable

$grouped will be

Name                           Value                                                                                                                                                                                                                                              
----                           -----                                                                                                                                                                                                                                              
A                              {A}                                                                                                                                                                                                                                                
B                              {B, B}                                                                                                                                                                                                                                             
C                              {C, c, C}  

At which point I would have thought that $grouped['B'].Count or $grouped.'B'.Count would produce the correct count of 2. But I am getting 0. What am I missing?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Gordon
  • 6,257
  • 6
  • 36
  • 89
  • 1
    hmmm, not too sure why that don't work. In the meantime, you can try: `$grouped.GetEnumerator().Where{$_.Name -eq 'B'}.Value.Count` before the smart people answer this;) – Abraham Zinala Dec 04 '21 at 21:39
  • Ah, should have mentioned PS 5.1. Perhaps a bug that will never be fixed, since 5.1 is terminal. – Gordon Dec 04 '21 at 21:42
  • 1
    @abraham-zinala, that's a viable workaround, if it proves to be a bug, not something I was doing wrong. – Gordon Dec 04 '21 at 21:43
  • Can't help, but feel like it's a bug i.m.o.. *shrug*.. – Abraham Zinala Dec 04 '21 at 21:46
  • 2
    Hmm..... I used the `-AsString` switch, and it gave me the proper results: `$grouped = $array | Group-Object -AsHashTable -AsString; $grouped['b'].Count`. Guess you can do that for now. Very odd indeed! @mklement0, any thought's on this? – Abraham Zinala Dec 04 '21 at 21:51
  • 2
    This is clearly a bug on 5.1. Even `$grouped.ContainsKey('B')` will yield `$false`. Works fine on Core. – Santiago Squarzon Dec 04 '21 at 21:55
  • 1
    Well, seems like this has been noticed before, I'm amazed to find this out just now. https://powershell.one/bugs/windows-powershell/group-object. @Gordon I would recommend you to take a classic approach to build your hashtable in case you do not want to use `-AsString` switch as [Abraham](https://stackoverflow.com/questions/70229678/group-object-get-counts#comment124146932_70229678) pointed out. Using `.GetEnumerator()` even tho it works, will remove all the good qualities of a proper `hashtable` (efficiency). – Santiago Squarzon Dec 04 '21 at 22:05

2 Answers2

2

You're seeing a bug in Windows PowerShell that has since been fixed in PowerShell (Core) 7+ - see GitHub issue #6933 for details.

Workaround: In Windows PowerShell, always combine -AsHashTable with -AsString, even if the input objects or grouping property values already are strings. Tip of the hat to Abraham Zinala.

# Note: .B.Count is equivalent to ['B'].Count
PS> ('A', 'B', 'C', 'B', "c", 'C' | Group-Object -AsHashTable -AsString).B.Count

2 # OK, thanks to -AsString (not necessary in PowerShell 7+)

This bypasses the bug, which otherwise manifests as follows: the strings that are meant to become the hashtable keys are unexpectedly wrapped in invisible [psobject] wrappers, which in turn prevents string-based key lookup.
(('A', 'B', 'C', 'B', "c", 'C' | Group-Object -AsHashTable).B yields $null in Windows PowerShell.)

Note: The implication is that you cannot use -AsHashtable in Windows PowerShell if you want the keys to be of a data type other than string (e.g. [int]), because for such data types the invisible [psobject] wrapping cannot be bypassed.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    I'm struggling to understand how can we tell if a `string` has been "invisible wrapped", if I do `$grouped.Keys.ForEach({ $_ -is [string] })` I get `$true`. And even if I compare `'A'.PSObject` with `foreach($key in $grouped.Keys){ $key.PSObject ; break }` I don't see any difference. Some insight would be much appreaciated. – Santiago Squarzon Dec 04 '21 at 22:26
  • 2
    @Santiago, try `-is [psobject]`. Compare `'foo' -is [psobject]` to `([psobject] 'foo') -is [psobject]`. With `-is` - unless you explicitly test for `[psobject]` - the `[psobject]` wrapper is _ignored_, so that `([psobject] 'foo') -is [string]` is _also_ true, because what the `[psobject]` instance _wraps_ is a string. – mklement0 Dec 04 '21 at 22:42
  • Oh wow, I see why you call it "invisible" now. You're great thank you! Does this imply that all data types in PowerShell are wrapped instances of `PSObject` ? Sorry to bother you with these questions but I'm a curious person :P – Santiago Squarzon Dec 04 '21 at 22:49
  • 1
    No worries, @Santiago, they're great questions. The answer is that the wrapping happens _situationally_, and while it always _should_ be completely transparent (invisible) - an _implementation detail_ - _sometimes it isn't_: see [GitHub issue #5579](https://github.com/PowerShell/PowerShell/issues/5579). – mklement0 Dec 04 '21 at 22:54
-1

Please Note This Was Done On PowerShell Version 7.2 & Not Version 5 Which Was The Question. 05.12.2021

try the below (it worked for me, see pic)

$array = [System.Collections.Generic.List[String]]@('A', 'B', 'C', 'B', "c", 'C')
$grouped = $array | Group-Object -AsHashTable
$grouped.B 
$grouped.B.Count

Write-Host $grouped.B.Count

$b = $grouped.B.Count
Write-Host "The Number of Values in Column B Is - $b"

enter image description here

NeoTheNerd
  • 566
  • 3
  • 11
  • 2
    I believe it's just a bug in Windows PowerShell, and not in Core. – Abraham Zinala Dec 04 '21 at 22:04
  • 1
    Sorry I just saw your using 5.2 – NeoTheNerd Dec 04 '21 at 22:28
  • 3
    I too did initially not realize that the bug only manifests in _Windows PowerShell_. Generally speaking, if you can't reproduce a problem, it's better to seek clarification from the OP _via a comment_ rather than posting what works for you _as an answer_. – mklement0 Dec 04 '21 at 23:02