Explain Try/Catch/Finally block in PowerShell

PowerShellMicrosoft TechnologiesSoftware & Coding

Try/Catch block in PowerShell is to handle the errors which are produced in the script. To be specific, the errors should be terminating errors. The Finally block in the PowerShell is not mandatory to write each time along with Try/Catch but it will be executed regardless the error occurs or not.

So when you use the Try block, the Catch block is mandatory but not Finally block.

  • Try/Catch block with Terminating error − Below is the example of Terminating error without finally block.

Example

try{
   This is not allowed
   "This is Allowed"
}
catch{
   Write-Host "Error occured" -BackgroundColor DarkRed
}

Output

PS C:\WINDOWS\system32> try{
   This is not allowed
   "THis is allowed"
}
catch{
   Write-Host "Error occured" -BackgroundColor Darkred
}
Error occured

In the above example, we have return something which is not allowed but the next line was genuine although it couldn’t execute because of the terminating error.

Our goal is to catch the exception and error message generated in the Try block. As we know, the error is stored in the $Error variable. If you check the output of the $error variable you can get the entire view but whenever you run any script and you are handling the errors make sure you clear the old errors using $error.clear() command or use the new PowerShell console. In case you know the specific Error variable location in an array you can directly use that. For example, $error[2]

PS C:\WINDOWS\system32> $Error
This : The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:3 char:5
+    This is not allowed
+    ~~~~
   + CategoryInfo             : ObjectNotFound: (This:String) [],
CommandNotFoundException
   + FullyQualifiedErrorId    : CommandNotFoundException

We can see what are all properties of the $Error variable.

PS C:\WINDOWS\system32> $Error | Get-Member | Select Name, MemberType
Name                                     MemberType
----                                     ----------
Equals                                     Method
GetHashCode                                Method
GetObjectData                              Method
GetType                                    Method
ToString                                   Method
CategoryInfo                              Property
ErrorDetails                              Property
Exception                                 Property
FullyQualifiedErrorId                     Property
InvocationInfo                            Property
PipelineIterationInfo                     Property
ScriptStackTrace                          Property
TargetObject                              Property
PSMessageDetails                      ScriptProperty

There are few properties from above are helpful to find the exception and error details. Let see them and we can leverage them in the Catch block as well.

First InvocationInfo Property. You can also use $Error[0] but this is the only error generated so far so we are using directly $Error but you can not get the AutoSuggestion Popup with $error variable directly.

PS C:\WINDOWS\system32> $Error.InvocationInfo
MyCommand              :
BoundParameters        : {}
UnboundArguments       : {}
ScriptLineNumber       : 3
OffsetInLine           : 5
HistoryId              : 50
ScriptName             :
Line                   : This is not allowed

PositionMessage        : At line:3 char:5
                        + This is not allowed
                        + ~~~~
PSScriptRoot           :
PSCommandPath          :
InvocationName         : This
PipelineLength         : 0
PipelinePosition       : 0
ExpectingInput         : False
CommandOrigin          : Internal
DisplayScriptPosition  :

You can get the specific information from Line and PositionMessage as shown below.

PS C:\WINDOWS\system32> $Error.InvocationInfo.Line
   This is not allowed
PS C:\WINDOWS\system32> $Error.InvocationInfo.PositionMessage
At line:3 char:5
+    This is not allowed
+    ~~~~

Check now the Exception Properties.

PS C:\WINDOWS\system32> $Error.Exception
The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Exception Message

PS C:\WINDOWS\system32>$error.Exception.Message
The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

You can use the other properties that you think will be helpful to display the error message. We are going to use a few of these in the Catch block to catch the error. As we are working with the current error we will use $_. to deal with the current error/exception.

$error.clear()
try{
   This is not allowed
   "THis is allowed"
}
catch{
   Write-Host "`nError Message: " $_.Exception.Message
   Write-Host "`nError in Line: " $_.InvocationInfo.Line
   Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber
   Write-Host "`nError Item Name: "$_.Exception.ItemName

}

Output

Error Message: The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Error in Line:          This is not allowed
Error in Line Number:    3
Error Item Name:

As we have seen above there was no Finally block but Try/Catch continued to work. You can add the Finally block to clear your variables and errors and display any message.

try{
   This is not allowed
   "THis is allowed"
}
catch{
   Write-Host "`nError Message: " $_.Exception.Message
   Write-Host "`nError in Line: " $_.InvocationInfo.Line
   Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber
   Write-Host "`nError Item Name: "$_.Exception.ItemName
}
finally{
   "This is going to run anyway"
   $error.clear()
}
  • Try/Catch block with Non-Terminating error.

As we have seen in the above example that Terminating errors can be controlled with the Try/Catch block but Non-Terminating errors cannot because they are built-in cmdlets and functions generated errors and the default preference for the Error action is Continue and hence next command continue to run even if the error is not handled.

PS C:\WINDOWS\system32> $ErrorActionPreference
Continue

To force the Non-Terminating error to the Terminating error we need to change either $ErrorActionPreference variable to Stop or need to use the ErrorAction parameter with Stop value. Here, we are going to use the ErrorAction Parameter as we need it for a specific command and not for the entire script.

Example

$error.clear()
try{
   Get-Service WhichService -ErrorAction Stop
}
catch{
   Write-Host "`nError Message: " $_.Exception.Message
   Write-Host "`nError in Line: " $_.InvocationInfo.Line
   Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber
   Write-Host "`nError Item Name: "$_.Exception.ItemName
}
finally{
   "This is going to run anyway"
   $error.clear()
}

Output

Error Message: Cannot find any service with service name 'WhichService'.
Error in Line:       Get-Service WhichService -ErrorAction Stop
Error in Line Number: 4
Error Item Name:
This is going to run anyway

As you can see in the above example, Get-Service produces the non-terminating error and we can convert it to terminating error by –ErrorAction Stop parameter and the same exception has been caught by Catch Block.

  • Manually Handling Specific Exception

If you want to handle a specific type of exception then you can provide the exception name in the catch block. To know the name of the exception you need to get the property of the $Error variable and it is GetType(). In the below example, we need to find the exception name from the error output below.

Example

PS C:\WINDOWS\system32> Test-Connection Remote-Computer -Count 1 -ErrorAction
Stop
Test-Connection : Testing connection to computer 'Remote-Computer' failed: No
such host is known
At line:1 char:4
+    Test-Connection Remote-Computer -Count 1 -ErrorAction Stop
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   + CategoryInfo : ResourceUnavailable: (Remote-Computer:String)
[Test-Connection], PingException
   + FullyQualifiedErrorId :
TestConnectionException,Microsoft.PowerShell.Commands.
   TestConnectionCommand

Suppose your error is stored in $Error[0] variable, you need to run below command to get the exception name to use into catch block.

$Error[0].Exception.GetType().FullName
PS C:\WINDOWS\system32> $Error[0].Exception.GetType().FullName
System.Management.Automation.MethodInvocationException

You got the exception type name with the above command, you can use the same in the catch block so the catch block will catch only that specific exception.

$error.clear()
try{
   Test-Connection Remote-Computer -Count 1 -ErrorAction Stop
}
catch [System.Net.NetworkInformation.PingException]{
   Write-Host $_.Exception.Message -BackgroundColor DarkRed
}

Output

PS C:\WINDOWS\system32> $error.clear()
try{
   Test-Connection Remote-Computer -Count 1 -ErrorAction Stop
}
catch [System.Net.NetworkInformation.PingException]{
   Write-Host $_.Exception.Message -BackgroundColor DarkRed -NoNewline
}
Testing connection to computer 'Remote-Computer' failed: No such host is known
  • Catch Multiple Exception PowerShell.

You can also catch the multiple exceptions in PowerShell. For that, you can use a single Try block and multiple catch blocks.

Example

$error.clear()
$ErrorActionPreference = "Stop"
try{
   Get-ItemProperty C:\temp\cominfo1.html
   Test-Connection Remote-Computer -Count 1
}
catch [System.Management.Automation.ItemNotFoundException]{
   Write-Host $_.Exception.Message -BackgroundColor DarkRed
}
catch [System.Net.NetworkInformation.PingException]{
   Write-Host ""
   Write-Host $_.Exception.Message -BackgroundColor DarkRed
}
Finally{
   Write-Output "`nSetting up ErrorActionPreference to the Default value"
   $ErrorActionPreference = "Continue"
}

Output

Cannot find path 'C:\temp\cominfo1.html' because it does not exist.
Setting up ErrorActionPreference to the Default value

Here, in the first command, itself error generated so the next command won’t execute. If the first command doesn’t generate any error then the next command will be checked and if the exception occurs then Catch with that specific exception block will be executed.

If you don’t want to handle multiple exceptions and still you need for some commands errors can be ignored but shouldn’t pass through catch block so the next command could execute then you can use the Ignore or SilentlyIgnore in the ErrorAction Parameter.

raja
Published on 06-Jun-2020 16:36:12
Advertisements