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

1 Answer 1

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, both in Windows PowerShell and in PowerShell (Core) up to at least v7.3.7 (current as of this writing). See this answer for the history behind this problem, and GitHub issue #20458 for a discussion about fixing it.

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.

Sign up to request clarification or add additional context in comments.

7 Comments

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?
I found an old one: stackoverflow.com/questions/20521935/… $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..
..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, 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.
Glad to hear it helped, @Purclot; my pleasure. As for how I diagnosed the problem: see this answer I've just added to the post you linked to.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.