Home > OS >  PowerShell error variable loses the content
PowerShell error variable loses the content

Time:05-09

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

CodePudding user response:

  • 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.

  • Related