For a while, I am maintaining a PowerShell Join-Object cmdlet.
In here I am creating a few proxy commands with default parameters, as FullJoin-Object
, Merge-Object
and Insert-Object
as described here: Proxy Functions: Spice Up Your PowerShell Core Cmdlets.
(In earlier version I was using aliases which could problems if the user creates its own aliases.)
Everything works as expected except that the error handling differs a little between the main command and the proxy command...
Taken the following MVCE, based on the following function:
Function Inverse([Int]$Number) {
Rubbish
Write-Output (1 / $Number)
}
(Where the function Rubbish
doesn't exist)
Than I create a proxy function called Reverse0
:
$MetaData = [System.Management.Automation.CommandMetadata](Get-Command Inverse)
$Value = [System.Management.Automation.ProxyCommand]::Create($MetaData)
$Null = New-Item -Path Function:\ -Name "Script:Inverse0" -Value $Value -Force
$PSDefaultParameterValues['Inverse0:Number'] = 0 # (Not really required for reproducing the issue)
If I run the original function Reverse 0
, I get two errors:
Rubbish : The term 'Rubbish' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:2 char:1
+ Rubbish
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (Rubbish:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Attempted to divide by zero.
At line:3 char:1
+ Write-Output (1 / $Number)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
If run the proxy command Reverse0
(or Reverse0 0
), I get only the first error:
Rubbish : The term 'Rubbish' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:2 char:1
+ Rubbish
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (Rubbish:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : CommandNotFoundException
It seems that something like the $ErrorActionPreference
has changed but I checked that and it appears to be the same within both functions.
Is there and explanation for the different behavior?
Is there a way to get a Proxy Command act the same as the original command with respect to error handling?
The code that [System.Management.Automation.ProxyCommand]::Create()
generates is currently (PowerShell Core 7.0.0-preview.5) flawed:
It incorrectly propagates statement-terminating errors as script-terminating errors, by using throw
rather than $PSCmdlet.ThrowTerminatingError($_)
in its catch
blocks, causing the function to abort instantly.
If you manually correct these calls, your proxy function should behave as expected.
See GitHub issue #10863; the linked issue isn't specifically about this behavior, but a change has been green-lighted, and it should include a fix for it.
In concrete terms, for now, you'll have to fix the generated code manually:
try
/ catch
statements that look like this: try {
# ...
} catch {
throw
}
try {
# ...
} catch {
$PSCmdlet.ThrowTerminatingError($_)
}