1

I have a quite big project with many functions in there. Just 2 questions:

  1. What would be here the "best practice" regarding Error-Handling? To use a local handling per Function, or use only one Error-Logging in the Main-Section?
  2. The tricky part (!), let's have a look at the strange Error behaviour in the function F_XXX: only $_ delivers an error message, $Error[0] is here empty! Strange enough, when I start the function F_XXX separately (cut out from the module), it behaves as expected, it means: $Error[0] gives an error back. The code:

Blockquote

$ErrorActionPreference = "Stop"
Function F1
{
    try
    {
    # do something
    }
    catch
    {
        # 1. cascade Error to Main?
        # throw $Error[0].InnerException
        # or
        # local Error-Logging?
        write-MyErrorLogging -message $Error[0].InnerException
    }
}



Function F2
{
    try
    {
        # do something
    }
    catch
    {
        # 1. cascade Error to Main?
        # throw $Error[0].InnerException
        # or
        # local Error-Logging?
        write-MyErrorLogging -message $Error[0].InnerException
    }
}
Function F_XXXXXX
{
    try
    {
        cls
        write-host "The install data is copied.."
        $share = "\\my_wrong_path\sql_sources\" 
        Copy-Item $share -Destination $installDrive -Force -Recurse
    }
    catch
    {
        $Error[0] #here is nothing!
        $null -eq $Error[0] # here true
        $_.Exception # only here the error-message: wrong path!
    }
}

Blockquote

# here Main
try
{
    F1
    F2
    F_XXXXXX
}
catch
{
    write-MyErrorLogging -message $Error[0].InnerException
}

Blockquote

mklement0
  • 382,024
  • 64
  • 607
  • 775
Purclot
  • 483
  • 7
  • 22

1 Answers1

3
  • Inside a catch block, it's best to avoid $Error[0], given that the error at hand is reliably reflected in the automatic $_ variable.

    • If you do need access to previous errors via the automatic $Error variable, use $global:Error inside modules - see the bottom section for details.
  • Unless you need to perform additional actions when an error occurs, you can let a script-terminating (fatal) error (which your $ErrorActionPreference = "Stop" statement turns all errors in your code into) bubble up the call stack until it is either caught by a try / catch statement or, in the absence of one, terminates the entire call stack (i.e., the scripts and its callers).

    • If you do need to perform additional actions, use try / catch, and place the actions inside the catch block (as well as potential cleanup actions in a finally block), followed by re-throwing the error simply by calling throw without an argument.

Thus, you can make do with a single try / catch statement in the top-level scope of your script:

# Turn all errors in this and descendant scopes into
# script-terminating (fatal) ones.
$ErrorActionPreference = 'Stop'

# ... other function definitions, without try / catch

# Top-level code that calls the other functions and catches
# any errors.
try
{
    F1
    F2
    F_XXXXXX
}
catch
{
    write-MyErrorLogging -message $_.InnerException
}

The automatic $Error variable in modules:

Strangely, up to at least PowerShell 7.2.3 (current as of this writing):

  • Errors occurring in modules - just like ones occurring outside modules - are recorded in the $Error variable that exists in the global scope.

  • However, a seemingly unused, module-local copy of $Error exists, which shadows the global variable.

The workaround is to use use $global:Error from inside modules.

The behavior suggests a bug, given that the module-local copy is seemingly never touched and serves no apparent purpose.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • thanks, 1. I'll probably use the error handling in the top-level scope. 2. there is definitely something wrong in the Function F_XXXX, the path is wrong and I don't get anything (!) catching the $Error[0] - variable (see the code), only $_ variable has the error message. Why is here $Error[0] losing the error? – Purclot May 08 '22 at 16:47
  • I found an old one: https://stackoverflow.com/questions/20521935/error-variable-is-null-but-contains-error-in-catch $error is an automatic variable handled by Powershell: 3rd § of the LONG DESCRIPTION in about_Try_Catch_Finally. It is considered as the context of the Catch block, thus being available as $_. Since Catch block is a different block than Try, the $error automatic variable is reset and valued $null. The Problem with the reproducible example is: the strange behaviour happens only in the whole module, when I cut the Function F_XXX out and run it separately everything is fine.. – Purclot May 08 '22 at 16:59
  • ..it's a quite old problem described in the link above, now I'm using the last desktop version of PowerShell (5.1.xxx).. – Purclot May 08 '22 at 17:00
  • 1
    @Purclot, the problem exists to this day (PowerShell 7.2.3, as of this writing). Please see my update, which also shows a workaround (`$global:Error`). The explanation in the answer you quote isn't correct. – mklement0 May 08 '22 at 19:05
  • thanks, a great job, really appreciate it! How the heck did you find it out?? – Purclot May 08 '22 at 19:31
  • 1
    Glad to hear it helped, @Purclot; my pleasure. As for how I diagnosed the problem: see [this answer](https://stackoverflow.com/a/72164560/45375) I've just added to the post you linked to. – mklement0 May 08 '22 at 19:45
  • hi mklement0, is it possible you have a look at https://stackoverflow.com/questions/73403089/powershell-runtime-execption-in-remote-call ..? I'd appreciate it very much.. – Purclot Aug 29 '22 at 07:44