Powershell 如何将哈希表枚举为键值对/通过键值集合筛选哈希表

Powershell 如何将哈希表枚举为键值对/通过键值集合筛选哈希表,powershell,hashtable,Powershell,Hashtable,编者按: 这个问题有着复杂的历史,但归结起来是: *要了解如何通过哈希表的键值对枚举哈希表的条目,请参阅。 *要了解如何通过键值集合过滤哈希表,请参阅。 我想我又陷入了xy问题,我最初的问题是关于筛选哈希表。我发现在创建哈希表之前更容易过滤。问题回答了,对吗 不,Y问题是循环每个键并使用@briantist帮助我的值 我的目标是循环使用键名称(即时间戳),并使用键名称作为任务名称和触发器来调度任务 我正在使用组对象-AsHashTable-AsString-edit从CSV文件创建一个哈希表

编者按: 这个问题有着复杂的历史,但归结起来是:
*要了解如何通过哈希表的键值对枚举哈希表的条目,请参阅。
*要了解如何通过键值集合过滤哈希表,请参阅。


我想我又陷入了xy问题,我最初的问题是关于筛选哈希表。我发现在创建哈希表之前更容易过滤。问题回答了,对吗

不,Y问题是循环每个键并使用@briantist帮助我的值

我的目标是循环使用键名称(即时间戳),并使用键名称作为任务名称和触发器来调度任务

我正在使用
组对象-AsHashTable-AsString
-edit从CSV文件创建一个哈希表,这里值得一提的是,在创建哈希表之前过滤CSV只会使
管道或脚本中的事情变得更简单

例如:

Import-CSV (ls -path D:\ -Filter source*.csv | sort LastWriteTime | Select -Last 1).FullName |
 where {$_.TimeCorrected -ne 'ManualRebootServer'} |
 group TimeCorrected -AsHashTable -AsString
我正在尝试循环键名,并能够使用以下命令显示键名:

$var = Import-Csv csv123.csv | Group-Object Value1 -AsHashTable -AsString

foreach ($key in $var.Keys){"The key name is $key"}

#Create a scheduled task named and triggered based on the HashTable keyname
#test test test
foreach ($key in $var.keys){IF($key -ne 'ManualRebootServer'){"Register-ScheduledJob"}}
我只是不知道如何从我感兴趣的键中获取值

我发现以下方法有效,但仅当我手动输入密钥名时有效。我只是不知道如何组合这两个循环

($val.GetEnumerator() | Where {$_.key -eq '06-11-16 18:00'} | ForEach-Object { $_.value }).Server

你在这里有一些选择

通过键枚举:

foreach ($key in $var.Keys) {
    $value = $var[$key]
    # or
    $value = $var.$key 
}
枚举键值对(已发现,但可能未有效使用):

通过关注通过键值数组过滤哈希表来补充(PSv3+语法):

要进一步处理匹配的键值对,只需通过管道连接到
%
ForEach Object
)并访问
$.key
$.value
(值):

等效命令使用更高效的
foreach
循环
而不是管道:

foreach ($key in $ht.Keys) { 
  if ($key -in 'one', 'two') { "Value for key '$($key)': $($ht.$key)" }
}
注:在PSv2中: *不支持运算符
-in
,但您可以使用
-contains
替换操作数:
'one'、'two'-包含$key

*在管道中,使用
Where对象{'one','two'-包含$\ Key}

对于示例哈希表,这将产生:

Value for key 'two': 2
Value for key 'one': 1
注意输出中的键顺序与定义顺序的不同;在PSv3+中,您可以创建有序哈希表(
[ordered]@{…}
)以保留定义顺序

上面使用的密钥过滤技术不限于通过文本密钥数组进行过滤;任何(字符串)集合都将作为
操作数中
-in的RHS,例如不同哈希表的
.Keys
集合:

# Sample input hashtable.
$htInput = @{ one = 1; two = 2; three = 3 }

# Hashtable by whose keys the input hashtable should be filtered.
# Note that the entries' *values* are irrelevant here.
$htFilterKeys = @{ one = $null; two = $null }

# Perform filtering.
$htInput.GetEnumerator()  | ? Key -in $htFilterKeys.Keys | 
  % { "Value for key '$($_.Key)': $($_.Value)" }

# `foreach` loop equivalent:
foreach ($key in $htInput.Keys) {
  if ($key -in $htFilterKeys.Keys) { "Value for key '$($key)': $($htInput.$key)" }
}
结果与使用静态筛选键数组的示例中的结果相同

最后,如果希望就地筛选哈希表创建一个仅包含筛选项的新哈希表

# *In-place* Updating of the hashtable.
# Remove entries other than the ones matching the specified keys.
# Note: The @(...) around $ht.Keys is needed to clone the keys collection before
# enumeration, so that you don't get an error about modifying a collection
# while it is being enumerated.
foreach ($key in @($ht.Keys)) { 
  if ($key -notin 'one', 'two') { $ht.Remove($key) } 
} 

# Create a *new* hashtable with only the filtered entries.
# By accessing the original's .Keys collection, the need for @(...) is obviated.
$htNew = $ht.Clone()
foreach ($key in $ht.Keys) { 
  if ($key -notin 'one', 'two') { $htNew.Remove($key) }
} 

旁白:

[System.Collections.DictionaryEntry]
(因此哈希表(
[System.Collections.Hashtable]
)的默认输出格式使用列名
名称
,而不是
名称
定义为PowerShell添加的
键的别名属性(它不是

@{one=1}.GetEnumerator()| Get Member
)。

我在第一个块中尝试了该代码,使用了IF语句,因为有一个键我想跳过。这有效
$value=$val[$key].server
但我还有进一步的筛选工作需要完成。这是否可以简单到将
$value
放入一个数组并在事实发生后进行筛选?@user4317867如果您能更明确地说明您最终要完成的任务,这会有所帮助,因为我只能根据您目前所说的进行推测。“进一步的过滤工作”可能意味着很多事情。抱歉,我花了半天的时间来回答这个问题!值得指出的是,在创建哈希表之前过滤CSV,例如
Import CSV file.CSV | where{$\ Column-ne'String'}
让事情变得更简单!简洁地总结了需要掌握的两个习惯用法。令人遗憾的是,Powershell没有一个更简单的.GetEnumerator()。只是为了提供一个解释,筛选(至少在Powershell中)最好在管道操作符
|
之前或左侧完成,以提高脚本的效率。事实上,换言之:使用提供程序本机筛选和
-Filter
参数(如果可用)通常比通过管道传递未过滤的输出要快得多,以便让
Where-Object
cmdlet稍后执行过滤。
Value for key 'two': 2
Value for key 'one': 1
# Sample input hashtable.
$htInput = @{ one = 1; two = 2; three = 3 }

# Hashtable by whose keys the input hashtable should be filtered.
# Note that the entries' *values* are irrelevant here.
$htFilterKeys = @{ one = $null; two = $null }

# Perform filtering.
$htInput.GetEnumerator()  | ? Key -in $htFilterKeys.Keys | 
  % { "Value for key '$($_.Key)': $($_.Value)" }

# `foreach` loop equivalent:
foreach ($key in $htInput.Keys) {
  if ($key -in $htFilterKeys.Keys) { "Value for key '$($key)': $($htInput.$key)" }
}
# *In-place* Updating of the hashtable.
# Remove entries other than the ones matching the specified keys.
# Note: The @(...) around $ht.Keys is needed to clone the keys collection before
# enumeration, so that you don't get an error about modifying a collection
# while it is being enumerated.
foreach ($key in @($ht.Keys)) { 
  if ($key -notin 'one', 'two') { $ht.Remove($key) } 
} 

# Create a *new* hashtable with only the filtered entries.
# By accessing the original's .Keys collection, the need for @(...) is obviated.
$htNew = $ht.Clone()
foreach ($key in $ht.Keys) { 
  if ($key -notin 'one', 'two') { $htNew.Remove($key) }
}