Powershell 带或不带代码块的组对象差异

Powershell 带或不带代码块的组对象差异,powershell,powershell-4.0,Powershell,Powershell 4.0,下面的代码生成2个“相同”的哈希表,但是在使用代码块分组的哈希表上,我无法从键中获取项 $HashTableWithoutBlock = Get-WmiObject Win32_Service | Group-Object State -AsHashTable $HashTableWithBlock = Get-WmiObject Win32_Service | Group-Object {$_.State} -AsHashTable Write-Host "Search

下面的代码生成2个“相同”的哈希表,但是在使用代码块分组的哈希表上,我无法从键中获取项

$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"
} 
输出:

Search result for HashTable without using code block : Success
Search result for HashTable with code block : Failed
这两个哈希表之间的区别是什么

如何获取第二个按代码块分组的项目


编辑:不仅仅是一种解决方法,我想知道是否可以通过表查找来检索我想要的项,如果可以,如何检索?

两个
哈希表
之间的区别在于
$HashTableWithBlock
将其键包装在
PSObject
中。问题是PowerShell在将其传递给方法调用之前通常会展开
PSObject
,所以即使您有正确的密钥,也不能只将其传递给indexer。为了解决这个问题,您可以创建helper C#方法,该方法将使用right对象调用indexer。另一种方法是使用反射:

添加类型-TypeDefinition@'
公共静态类助手{
公共静态对象IndexHashtableByPSObject(System.Collections.IDictionary表,对象[]键){
返回表[键[0]];
}
}
'@
$HashTableWithBlock=获取WmiObject Win32|u服务|组对象{$\uu.State}-AsHashTable
$Key=$HashTableWithBlock.Keys-eq“已停止”
#辅助方法
[Helper]::IndexHashtableByPSObject($HashTableWithBlock,$Key)
#倒影
[Collections.IDictionary].InvokeMember(“”,'GetProperty',$null,$HashTableWithBlock,$Key)

我发现了一个解决方法,但其实并不太好:

$HashTableWithBlock = 
    Get-WmiObject Win32_Service | ForEach-Object -Process {
        $_ | Add-Member -NotePropertyName _StateProp -NotePropertyValue $_.State -Force -Passthru
    } |
    Group-Object -Proerty _StateProp -AsHashTable
我的意思是,我猜一旦你对每个对象进行了
ForEach
,你几乎可以自己构建一个哈希表


请注意,有趣的是,如果改为对ScriptProperty进行分组,这将不起作用。我还没有弄清楚原因。

其他海报是正确的,问题在于密钥存储为
PSObject
,但有一个内置解决方案:使用
-AsString
开关和
-AsHashTable
。这将强制将密钥存储为字符串。你可以看看代码


我在GitHub上打开了一个用于此bug的程序。

我注意到,使用一个块,显然可以按多个属性分组,然后将哈希表键转换为一个对象。但是,如果只有一个属性,我会假设它是一个普通字符串,并且我的查找应该可以工作。.在$HashTableWithBlock中,
PSObject
中包含了块键,因此
Hashtable
无法正确比较它们。@PetSerAl我明白了,但是您如何进行正确的查找?即使我创建了一个带有属性的PSObject,我也怀疑比较会比较对象引用。如果不使用块,不能按多个属性分组吗?你到底想做什么?为什么必须使用哈希表?我只能建议重新创建
哈希表
$HashTableWithBlock.GetEnumerator()|%{$HashTableWithBlock=@{}}{$HashTableWithBlock.Add($..Key,$..Value)}
@PetSerAI谢谢,看起来很有趣。但是,我不明白为什么调用表[key[0]]不同。是因为.Net对IDictionary和Object的隐式强制转换吗?因为其他原因,这将起作用:
$HashTableWithBlock[($HashTableWithBlock.Keys-eq'Stopped')[0]
@LukeMarlin PowerShell将打开此表达式的结果
PSObject
($HashTableWithBlock.Keys-eq'Stopped')[0]
,并在索引器中只传递字符串。@PetSerAI感谢您的帮助。不过,我希望与C#Net相比,PS中没有太多其他奇怪的东西!