Kemilio
Kemilio

Reputation: 88

Catching Cascading Errors in PowerShell

I'm working with a wrapper script that calls a function which queries some databases inside specified servers and inserts metadata to a specific database on a separate server. I use the $error.count variable to determine if the script was successful or not. I anticipate some permission/extraction errors to happen and want these to be caught and ignored (no increase in the $error.count variable but having a warning written in the job log). I can confirm one permission error is happening and is being properly caught. The $error.count variable is not increased but a warning is printed from the catch showing the database that could not be accessed.

My problem occurs after the extraction/insertion function is finished running. Immediately after this function returns to the wrapper script, I have the $error.count variable print again. This time, it returns a 1 as if the error previously caught cascades into the wrapper script. As I mentioned previously, I do not want this to be included in the error count. I'm not sure how or why the $error.count is increased from this function.

Should I use a different variable to determine if the script "failed" or not? Is there some underlying reason why the $error.count would increase outside of the function that has the error while not increasing after the error is caught? Any guidance on this issue would be appreciated.

Code for reference: Wrapper function:

$errorCount = $error.count
    Write-Warning ("$errorCount Before function")
    Extraction/Insertion_Function -serverList $serverList -insertionDB $insertionDB -ErrorAction SilentlyContinue
    $errorCount = $error.count
    Write-Warning ("$errorCount After function")
    } catch {
    Write-Error "Error caught by wrapper: $_"
    }

Extraction/Insertion_Function:

ForEach ($db in $dbList) {
Write-Warning "$errorCount database
.
.
.
    try {
            $totalProperties = Get-ServerDBMetadata -DBConnectionString ($connStr) -DatabaseName $dbName -EA SilentlyContinue 
            } catch {
                Write-Warning "Unable to extract metadata from $dbname in $server"
                }
}

I then have the error count printing out inside the loop that extracts/inserts the metadata from each database to the insertion database, as well as in the loop for each server that contains the databases:

WARNING: 0 Before function
WARNING: 0 database
.
.
.
WARNING: 0 database
WARNING: Unable to extract metadata from *database* in *server*
WARNING: 0 database
.
.
.
WARNING: 0 database
**WARNING: 1 After function**

The error (permission issue) is caught inside the function but cascades to my wrapper script. I want this particular error to be ignored while NOT ignoring other, more serious errors (like being unable to connect to the server I'm inserting the metadata into) so placing -EA Ignore on the driver function inside the wrapper script is out of the question.

Upvotes: 2

Views: 520

Answers (3)

thepip3r
thepip3r

Reputation: 2935

Your primary problem with the try-catch not catching the error (even though you don't supply all of the code) is that your cmdlet explicitly calls -ErrorAction SilentlyContinue. Try/Catch blocks REQUIRE the use of terminating errors so in the case of your function/cmdlet, you need to change to -ErrorAction Stop for try/catch to appropriately handle an error from that function/cmdlet.

This needs to be updated for any other function/cmdlet in the code we can't see.

Edit described in comments below:

 $n = New-Object PSObject -property @{
    'Test1' = ''
    'Test2' = ''
    'Test3' = ''
}

try {
    get-process someprocess -ErrorAction Stop
    $n.Test1 = $true
} catch {
    $n.Test1 = $false
}

try {
    Get-WmiObject win32_computersystem -ErrorAction Stop
    $n.Test2 = $true
} catch {
    $n.Test2 = $false
}

try {
    Get-Content somefile.ext -ErrorAction Stop
    $n.Test3 = $true
} catch {
    $n.Test3 = $false
}


if ($n.Test1 -and $n.Test2 -and $n.Test3) {
    ## All procedures completed successfully -- do something magical
} else {
    ## At least one test procedure failed.
}

Upvotes: 2

G42
G42

Reputation: 10019

Replace SilentlyContinue with Ignore to ignore the error and not have it increase the count.

Extraction/Insertion_Function -serverList $serverList -insertionDB $insertionDB -ErrorAction Ignore

To catch it inside the function, use -ErrorAction Stop as in thepip3r's answer as try/catch statements only catch terminating errors.

Upvotes: 2

iRon
iRon

Reputation: 23830

Logging the remaining errors since the last log:

While ($Global:ErrorCount -lt $Error.Count) {
    $Err = $Error[$Error.Count - ++$Global:ErrorCount]
    $ErrLine = "Error at $($Err.InvocationInfo.ScriptLineNumber),$($Err.InvocationInfo.OffsetInLine): $Err"
    Write-Host $ErrLine -ForegroundColor Red        # Log this
}

Upvotes: 1

Related Questions