I've encountered a quirk which no doubt has something to do with the differences between ForEach vs ForEach-Object. I have a workaround but I'm curious to understand the behaviour to help further my knowledge of PowerShell.
When enumerating a hashtable and running it through a ForEach-Object with a Try/Catch/Finally block, the Catch block does not retrieve the keypairs from the hashtable; however the values are accessible within both the Try and Finally blocks. When I do the same thing using a foreach loop they do get passed though.
A couple of examples.
#Example 1: Inconsistent output ie keypairs not present in Catch block
$ht = @{
1 = 'one'
2 = 'two'
3 = 'three'
}
$ht.GetEnumerator() | ForEach-Object {
Try {
"Try block: $($_.Name) - $($_.Value)" ; Start-Something
}
Catch {
"Catch block: $($_.Name) - $($_.Value)"
}
Finally {
"Finally block: $($_.Name) - $($_.Value)"
}
}
Example 1 output:
Try block: 3 - three
Catch block: -
Finally block: 3 - three
Try block: 2 - two
Catch block: -
Finally block: 2 - two
Try block: 1 - one
Catch block: -
Finally block: 1 - one
Using a similar approach with a foreach loop it behaves as expected:
#Example 2: Working ie keypairs present in Try/Catch/Finally
foreach ($h in $ht.GetEnumerator() ) {
Try {
"Try block: $($h.Name) - $($h.Value)" ; Start-Something
}
Catch {
"Catch block: $($h.Name) - $($h.Value)"
}
Finally {
"Finally block: $($h.Name) - $($h.Value)"
}
}
Example 2 output:
Try block: 3 - three
Catch block: 3 - three
Finally block: 3 - three
Try block: 2 - two
Catch block: 2 - two
Finally block: 2 - two
Try block: 1 - one
Catch block: 1 - one
Finally block: 1 - one
$_represents the caught exception in the context of acatchblock which explains this behavior. The caught exception no longer has a.Nameor a.Valueproperty, no longer represents the current pipeline object. See Accessing exception informationThe workaround for exception handling to preserve the pipeline object is to assign it a variable: