简体   繁体   中英

Group-Object diffencies with or without code block

The code below produce 2 "identical" Hashtables, however on the one that was grouped using a code block I can't get items from the key.

$HashTableWithoutBlock = 
    Get-WmiObject Win32_Service | Group-Object State -AsHashTable
$HashTableWithBlock = 
    Get-WmiObject Win32_Service | Group-Object {$_.State} -AsHashTable

Write-Host "Search result for HashTable without using code block : " -NoNewline
if($HashTableWithoutBlock["Stopped"] -eq $null)
{
    Write-Host "Failed"
}
else
{
    Write-Host "Success"
}

Write-Host "Search result for HashTable with code block : " -NoNewline
if($HashTableWithBlock["Stopped"] -eq $null)
{
    Write-Host "Failed"
}
else
{
    Write-Host "Success"
} 

Output :

Search result for HashTable without using code block : Success
Search result for HashTable with code block : Failed

What is the difference between the two Hashtables ?

How to get Items on second one that was grouped by code block ?

EDIT : More than a workaround, I'd like to know if it is possible to retrieve the Item I want with a table lookup , and if yes, how ?

The difference between two Hashtable s is that $HashTableWithBlock have its key wrapped in PSObject . Problem is that PowerShell normally unwrap PSObject before pass it to the method call, so even if you have right key, you still can not just pass it to indexer. To workaround this you can create helper C# method what would call indexer with right object. Another way is to use reflection:

Add-Type -TypeDefinition @'
    public static class Helper {
        public static object IndexHashtableByPSObject(System.Collections.IDictionary table,object[] key) {
            return table[key[0]];
        }
    }
'@
$HashTableWithBlock = Get-WmiObject Win32_Service | Group-Object {$_.State} -AsHashTable
$Key=$HashTableWithBlock.Keys-eq'Stopped'
#Helper method
[Helper]::IndexHashtableByPSObject($HashTableWithBlock,$Key)
#Reflection
[Collections.IDictionary].InvokeMember('','GetProperty',$null,$HashTableWithBlock,$Key)

The other posters are correct that the problem is with the key being stored as a PSObject but there is a built-in solution for this: use the -AsString switch along with -AsHashTable . This will force the key to be stored as a string. You can take a look at the code here

I've opened an issue on GitHub for this bug.

Here's a workaround I found, which is really not great:

$HashTableWithBlock = 
    Get-WmiObject Win32_Service | ForEach-Object -Process {
        $_ | Add-Member -NotePropertyName _StateProp -NotePropertyValue $_.State -Force -Passthru
    } |
    Group-Object -Proerty _StateProp -AsHashTable

I mean I guess once you're doing ForEach-Object you almost might as well just build a hashtable yourself?

Do note that, interestingly, this will not work if you group on a ScriptProperty instead. I haven't figured out why.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM