You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何通过-InputObject参数使用ForEach-Object无法填充强类型字典?

为什么PowerShell中用-InputObject传递哈希表枚举器给ForEach-Object会失败?

背景

我在脚本中收集用户Java Runtime Environment(JRE)信息,用于验证是否符合要求。首先将JRE变量声明为[List[String]]类型,通过解析java --version的输出来填充:

[List[String]] $Script:JRE = ($(Invoke-Expression -Command 'java --version' | Select-Object -Last 1) `
   -replace '(?:[\(\)]|Server VM|build)', '' `
   -replace '(?:(\d{2}\-Bit)|([\d\.\-\+]+)|(?:, (.+),) )', "`n`$1`n`$2`n`$3`n" `
   -replace ' {2,}', '' `
   -replace "`n+", "`n" `
) | Split-String -Separator "`n" # 这段代码能正常工作,但我总觉得不够优雅

示例结果:

PS> $JRE[0..4]
OpenJDK
64-Bit
20.0.1+9-29
mixed mode
sharing

随后基于JRE内容做三项检测:

  • Java是否存在:($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
  • 版本是否足够新:[Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
  • 是否为64位版本:$JRE[1] -match '64'

检测结果存入强类型字典JavaIs:

[Dictionary[String, Boolean]] $Script:JavaIs = New-Object -TypeName 'Dictionary[String, Boolean]'

测试过程与结果

使用-InputObject参数:❌失败

通过-InputObject传递哈希表枚举器给ForEach-Object时,JavaIs只得到一个空键值对:

ForEach-Object -InputObject @{
   Extant = ($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
   Recent = [Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
   x86_64 = $JRE[1] -match '64' 
}.GetEnumerator() -Process {
   $JavaIs.Add($_.Key, $_.Value)
}

# 调换参数顺序结果一样:
ForEach-Object -Process { 
   $JavaIs.Add($_.Key, $_.Value)
} -InputObject @{
   Extant = ($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
   Recent = [Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
   x86_64 = $JRE[1] -match '64' 
}.GetEnumerator()

结果:

PS> $JavaIs

Key Value
--- -----
    False

使用管道传递:✔成功

通过管道传递哈希表枚举器时,JavaIs能正确填充所有键值对:

@{
   Extant = ($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
   Recent = [Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
   x86_64 = $JRE[1] -match '64' 
}.GetEnumerator() | ForEach-Object -Process {
   $JavaIs.Add($_.Key, $_.Value)
}

结果:

PS> $JavaIs

Key    Value
---    -----
x86_64  True
Extant  True
Recent  True

问题原因

核心差异在于-InputObject和管道对集合的处理逻辑不同:

  • 管道传递会自动枚举集合类型:哈希表GetEnumerator()返回的DictionaryEntry集合,管道会逐个将每个DictionaryEntry对象传递给ForEach-Object的Process块,此时$_代表单个键值对,能正常访问Key和Value属性。
  • -InputObject参数会将整个集合对象作为单个输入项传递:此时$_代表的是整个枚举器集合,而非单个DictionaryEntry。集合本身没有Key和Value属性,所以$_.Key返回$null(显示为空键),$_.Value在布尔上下文里被判定为$false,最终得到一个空键的错误条目。

如果一定要用-InputObject,可以手动在Process块里枚举集合:

ForEach-Object -InputObject @{
   Extant = ($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
   Recent = [Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
   x86_64 = $JRE[1] -match '64' 
}.GetEnumerator() -Process {
    foreach ($entry in $_) {
        $JavaIs.Add($entry.Key, $entry.Value)
    }
}

环境信息

软件版本架构
PowerShell7.3.4x86_64
Windows10.0.19045x86_64

内容的提问来源于stack exchange,提问作者Magic Spearmint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 04:00:43