Currently Write-Error has many parameters to create a rich ErrorRecord and write it to the error channel as a non-terminating error.
Throw allows us to generate a terminating error and provide a string for the exception message, or an ErrorRecord object to pass, but without getting into New-Object territory there is no easy way to create an error record and pass to Throw.
New-ErrorRecord would allow us to generate the error details and then choose to write or throw it as necessary.
See https://gist.github.com/wpsmith/e8a9c54ca1c7c741b5e9 as an example Cmdlet.
See also this search for 1683 examples of this pattern:
https://github.com/search?utf8=%E2%9C%93&q=%22New-Object+System.Management.Automation.ErrorRecord%22+language%3APowerShell&type=Code&ref=searchresults
Is there a good reason to not prefer an improved api?
I'd imagine this is annoying for authors of C# cmdlets as well.
Can we use
$a=Write-Error -Message "eee" 2>&1
instead of New-ErrorRecord
?
@iSazonov that's a clever way to achieve the same result, but I don't think everyone should need to be that clever to create an error record for throwing.
Maybe we just add such feature in Write-Error
? New parameter?
A new parameter on Write-Error
is still not obvious, and still doesn't help C# authors.
I'd start with a new api - and if that's still not sufficient, only then would I consider a new cmdlet.
@lzybkr Can you help me understand as someone without background in C# what the experience would be in Powershell for interacting with a new API? I'm not sure what that would mean in this context. I'm happy for any solution that makes it easier to generate detailed terminating/non-terminating errors.
Is the objection to needing New-Object
? Or the need for multiple invocations to New-Object
?
It's already fine to throw an ErrorRecord
today even though it is not an Exception.
I was thinking there could be another constructor to ErrorRecord
with a signature similar to the New-ErrorRecord
script you linked to, so you'd use something like:
$err = [ErrorRecord]::new([InvalidOperationException], $message, $errorId, $errorCategory, $targetObj)
It's definitely useful to be able to make a new error record with an exception in a single line, but I'm pretty sure that it would be enough if there was just a -AsTerminatingException
switch on Write-Error ;-)
@Jaykul Personally I am fine with that solution. I think that covers 95% of the use cases, I just wasn't sure if throwing a terminating error was kosher for a "Write" verb.
Maybe -Throw
more clear for users?
It is not exclude New-ErrorRecord
for more complex cases (5%).
Let me try to summarize and make a suggestion:
In _PowerShell code_, Write-Error
, via its -Category
, -ErrorId
, ... parameters, already offers a way to create custom ErrorRecord
instances, by either wrapping a _custom error message_ (-Message
) or a _preexisting exception_ (-Exception
) - though the latter is currently broken - see #10774.
However, creating such a custom ErrorRecord
is currently tied solely to writing directly to the error stream, i.e. limited to creating a _non-terminating_ error.
Introducing something like a -AsTerminatingError
switch as suggested by @Jaykul (or @iSazonov's simpler alternative name, -Throw
, which I like for its association with the Throw
statement) would remove this limitation, to allow the custom error record to be thrown as a script-terminating (runspace-terminating) error as well, like a customized Throw
call.
$PSCmdlet.ThrowTerminatingError
directly, which scripters should not be expected to need to use); conversely, (binary) cmdlets _cannot_ raise script-terminating errors themselves and can only create _statement_-terminating ones, via Cmdlet.ThrowTerminatingError()
or by throwing or not catching a raw exception.Someone who really wants to create a custom ErrorRecord
_in isolation_, for later use - which is clearly an advanced use case - can use New-Object System.Management.Automation.ErrorRecord
or [System.Management.Automation.ErrorRecord]::new()
directly, as needed.
_Separately_, in parallel, _for SDK users_ (in C#) , providing a more convenient way to construct custom ErrorRecord
s implicitly, via arguments passed to new Cmdlet.WriteError()
/ Cmdlet.ThrowTerminatingError()
overloads, as suggested by @lzybkr, is well worth considering.
One point I'd like to mention is that Write-Error
_does_ in fact support creating terminating errors, via -ErrorAction Stop
if I'm not mistaken. 馃檪
The rest sounds good!
Thanks, @vexx32. -ErrorAction Stop
does work, but is suboptimal in that it creates an _extra_ entry in $Error
: a System.Management.Automation.ActionPreferenceStopException
exception with message
The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop
Write-Error
also doesn't provide access to all the properties of ErrorRecord
. Consider ScriptStackTrace
for example.
Most helpful comment
Let me try to summarize and make a suggestion:
In _PowerShell code_,
Write-Error
, via its-Category
,-ErrorId
, ... parameters, already offers a way to create customErrorRecord
instances, by either wrapping a _custom error message_ (-Message
) or a _preexisting exception_ (-Exception
) - though the latter is currently broken - see #10774.However, creating such a custom
ErrorRecord
is currently tied solely to writing directly to the error stream, i.e. limited to creating a _non-terminating_ error.Introducing something like a
-AsTerminatingError
switch as suggested by @Jaykul (or @iSazonov's simpler alternative name,-Throw
, which I like for its association with theThrow
statement) would remove this limitation, to allow the custom error record to be thrown as a script-terminating (runspace-terminating) error as well, like a customizedThrow
call.$PSCmdlet.ThrowTerminatingError
directly, which scripters should not be expected to need to use); conversely, (binary) cmdlets _cannot_ raise script-terminating errors themselves and can only create _statement_-terminating ones, viaCmdlet.ThrowTerminatingError()
or by throwing or not catching a raw exception.Someone who really wants to create a custom
ErrorRecord
_in isolation_, for later use - which is clearly an advanced use case - can useNew-Object System.Management.Automation.ErrorRecord
or[System.Management.Automation.ErrorRecord]::new()
directly, as needed._Separately_, in parallel, _for SDK users_ (in C#) , providing a more convenient way to construct custom
ErrorRecord
s implicitly, via arguments passed to newCmdlet.WriteError()
/Cmdlet.ThrowTerminatingError()
overloads, as suggested by @lzybkr, is well worth considering.