Context
I'm aiming to gather info about the user's Java Runtime Environment in a script for use in checking that it meets certain requirements. I start with a variable named JRE
that's cast as a list of strings, which becomes populated with info gathered about the Java Runtime Environment present (if any):
[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" # This works fine, but it doesn't make me feel fine.
Example result:
PS> $JRE[0..4]
OpenJDK
64-Bit
20.0.1+9-29
mixed mode
sharing
I then test against the contents of JRE
…
- Is Java actually present?
($null -ne $JRE) -and ($JRE[0] -match '(java|OpenJDK)')
- Is it reasonably up-to-date?
[Version]$JRE[2].Substring(0, $JRE[2].IndexOf('+')) -ge [Version]'20.0.0'
- Is it the 64-bit build?
$JRE[1] -match '64'
…and keep the results of these tests confined within a single variable, which is a strongly-typed dictionary named JavaIs
:
[Dictionary[String, Boolean]] $Script:JavaIs = New-Object -TypeName 'Dictionary[String, Boolean]'
I need to populate JavaIs
, and I decided to go with ForEach-Object
for accomplishing this. Here's where my question comes into play.
Trials, Expectations, Results
The Parameter Way: ❌
What doesn't work is using the InputObject
parameter to pass the hashtable to ForEach-Object
. The result is that JavaIs
receives a single, empty KV pair:
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)
}
# For what it's worth, swapping the parameter order makes no difference:
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
The Pipeline Way: ✔
What does work is providing the hashtable via pipe:
@{
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
I'm perfectly okay with pipelining, but this piqued my curiosity. Why does using -InputObject
fail in this scenario?
Software | Version | Architecture |
---|---|---|
PowerShell | 7.3.4 | x86_64 |
Windows | 10.0.19045 | x86_64 |