2

I've been reading up on generating error messages in PowerShell and stumbled across this example...

$Exception = [Exception]::new("error message")
$ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
    $Exception,
    "errorID",
    [System.Management.Automation.ErrorCategory]::NotSpecified,
    $TargetObject # usually the object that triggered the error, if possible
)
$PSCmdlet.WriteError($ErrorRecord)

However, this isn't a working example. I can't start experimenting with it, since I have no idea what would make the example tick to begin with.

InvalidOperation: You cannot call a method on a null-valued expression.

I do know I could use Write-Error instead to generate a non-terminating error. But I really don't like the error message to echo the command I used to generate the error message.

Dennis
  • 871
  • 9
  • 29
  • 1
    Santiago's answer solves your primary problem, but note that even a non-terminating error written with `$PSCmdlet.WriteError()` results in an error message that ix prefixed with the name of the error-emitting command. – mklement0 May 10 '23 at 19:39
  • Powershell script have a number of different output type (see : https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/types-of-cmdlet-output?view=powershell-7.3_) Write-Error writes to the error output, it doesn't trigger the exception. To throw exception see following : https://stackoverflow.com/questions/11981208/creating-and-throwing-new-exception – jdweng May 10 '23 at 19:40
  • 1
    @jdweng, the question is explicitly about writing a _non-terminating_ error (an error written to PowerShell's error output stream), which both `Write-Error` and `$PSCmdlet.WriteError()` do. – mklement0 May 10 '23 at 20:04
  • @mklement0 : The OP said "I have no idea what would make the example tick to begin with" – jdweng May 10 '23 at 23:19
  • @jdweng, to quote the Society for [Non Sequiturs](https://www.merriam-webster.com/dictionary/non%20sequitur): We may not make sense, but we sure love bananas. – mklement0 May 10 '23 at 23:22
  • @jdweng, I clarified the question somewhat – Dennis May 15 '23 at 18:18

1 Answers1

2

Your code looks good, the only problem is that $PSCmdlet is only available for you in the context of an advanced function or script block:

function Testing {
    [CmdletBinding()]
    param($TargetObject)

    $Exception = [Exception]::new('error message')
    $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
        $Exception,
        'errorID',
        [System.Management.Automation.ErrorCategory]::NotSpecified,
        $TargetObject) # usually the object that triggered the error, if possible

    $PSCmdlet.WriteError($ErrorRecord)
}

Testing foo!

Following up on comments, again, in the context of a script block (be it an Invoke-Command or Start-Job or any other script block) it would need to be an advanced one, so it would need to have a [cmdletbinding()] or [Parameter(...)] decoration for that to happen:

Start-Job {
    [CmdletBinding()]
    param($TargetObject)

    $Exception = [Exception]::new('error message')
    $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
        $Exception,
        'errorID',
        [System.Management.Automation.ErrorCategory]::NotSpecified,
        $TargetObject) # usually the object that triggered the error, if possible

    $PSCmdlet.WriteError($ErrorRecord)
} -ArgumentList foo! | Receive-Job -AutoRemoveJob -Wait

$Error[0].TargetObject # foo!
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    Ah, that's what throw me of. Since the $PSCmdlet variable and the associated methods are accessible from the shell, I assumed I could use them directly from the prompt. – Dennis May 10 '23 at 19:48
  • But I have issues running it as a scriptblock. Both `Invoke-Command {}` and `Start-Job {}` will fail in the same way... – Dennis May 10 '23 at 19:58