Tuesday, May 31, 2022

Handling errors in Powershell (terminating and non-terminating) and capturing errors into a variable without a red letter message being output

 


If you've ever written a script for someone else and wanted to hide (but still capture) the normal red letter output that happens from time to time, you've probably experienced confusion with how Powershell handles terminating and non-terminating errors. The example code below is non-terminating error examples and it is difficult to hide the red letter output but still catch the error to do some error handling within the script. Using " -erroraction silentlycontinue -errorvariable myErr" does not work as would be expected. 

With terminating errors, a standard try catch will suffice and you probably wouldn't want to suppress a terminating error or continue running the script if one occurs. Non-terminating errors are not detrimental to a script running and can continue through if you choose to.

Why you might ask? Sometimes the red letter output will confuse the end user and a simple "Write-Host" will suffice telling them a file doesn't exist, a process doesn't exist, a user doesn't exist or a user doesn't have a photo. Capturing the output will allow the script writer to instead tell the user that "The file doesn't exist, check the name again" in a yellow informational warning output. This way you can also customize what is output to any logging informational file. The script also doesn't appear broken, however if you need to instruct the user on what to do, you can do that with your own output. Below are examples of a standard cmdlet, an AD cmdlet, an Exchange cmdlet and an o365 cmdlet (notice I add a prefix of "eo" for the o365 cmdlet). You can also dot source the variable with different properties this way.

You can also use " -erroraction silentlycontinue" to hide the red letter response, although most people that read this probably already know that. Using -erroraction and using " -errorvariable myErr" does not work, it suppresses the error output and does not store anything in the variable. Take note that the error variable, when defined in the command, does not have a dollar sign before the text.

Here is a description of terminating vs non-terminating errors for your reading.

https://www.tutorialspoint.com/what-is-terminating-and-non-terminating-errors-in-powershell


Individual command examples

 
$suppressedError = $null; try {Get-ChildItem c:\temp\blahblah.txt -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} Write-Host ""; Write-Host ""; Write-Host "Error: " $suppressedError;

$suppressedError = $null; try {Get-Process 123456789 -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError = $error[0];} Write-Host ""; Write-Host ""; Write-Host "Error: " $suppressedError;

$suppressedError = $null; try {Get-ADUser abcdefghijklm -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError = $error[0];} Write-Host ""; Write-Host ""; Write-Host "Error: " $suppressedError;

$suppressedError = $null; try {Get-UserPhoto -Identity "abcdefghijklm" -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError = $error[0];} Write-Host ""; Write-Host ""; Write-Host "Error: " $suppressedError;

$suppressedError = $null; try {Get-eoUserPhoto "abcdefghijklm" -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError = $error[0];} Write-Host ""; Write-Host ""; Write-Host "Error: " $suppressedError;




Here is an example with all commands error output added to an array. The on prem and o365 Exchange commands might behave strangely if you don't have the cmdlets loaded.

Errors stored in an array example
$suppressedError = $null; try {Get-ChildItem c:\temp\abcdefghijklm.txt -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} 
try {Get-Process 123456789 -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} 
try {Get-ADUser abcdefghijklm -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} 
try {Get-UserPhoto -Identity "abcdefghijklm" -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} 
try {Get-eoUserPhoto "abcdefghijklm" -ErrorAction Stop -ErrorVariable suppressedError; } catch [System.Exception] { $suppressedError += $error[0];} 
Write-Host ""; Write-Host ""; 
Write-Host "Error count:" $suppressedError.Count;
Write-Host "Error:" $suppressedError;
Write-Host "";
Write-Host "Error 1:" $suppressedError[0]; Write-Host "";
Write-Host "Error 2:" $suppressedError[1]; Write-Host "";
Write-Host "Error 3:" $suppressedError[2]; Write-Host "";
Write-Host "Error 4:" $suppressedError[3]; Write-Host "";
Write-Host "Error 5:" $suppressedError[4]; Write-Host "";