Question about try/catch error handling in scripts/modules

As mentioned in another post here, I’m working on module for handling users in our AD. It’s easy to mistype a user or computer name so I’d like to add a check to see if an object exists in the AD before running the code.

However, whenever I look at info about the try/catch error handling, it never goes beyond just the try/catch it never describes how you write the code to be run after a success.

Basically what I’d like to have spelled out is how do exactly do I proceed after passing the try-test?

Do i write the test like this:

try {
  [bool] (Get-ADUser -Filter {samAccountName -eq $UserName}) -ErrorAction Stop
}
catch {
  Write-Warning "Can't you spell? User does not exist"
} 
# Success!
Do-WhateverAction to $UserName

or do I write it like this - with all of the code embedded within the try code block:

try {
  [bool] (Get-ADUser -Filter {samAccountName -eq $UserName}) -ErrorAction Stop
  # Success
  Do-WhateverAction to $UserName
}
catch {
  Write-Warning "Can't you spell? User does not exist"
}

 

generally i approach it by including the code to execute as part of the initial try…

so
[pre]
try
{
get-aduser $username
#do something with valid user here
}
catch
{
#user not found, place error handling code here, notify user with popup whatever
}
[/pre]

You can add a Finally block that contains an If-else statement. For example,

Finally {

if (error)

{

do-something

}

else

{

take action on user

}

}

 

 

[quote quote=136500]You can add a Finally block that contains an If-else statement.
[/quote]

Never found a real usecase for the Finally block…
It always appeared to me as beeing useless because the code after the whole Try/Catch statement would anyway be executed.
If someone could provide a good real example (not just a theoratical one)…

@Klaage

Basically see it like this

[pre]
try{

Run code here that you want to use errorhandling for

If there are no-errors in this block it means that this block will be the only thing that gets done.

Except the optional finally-block which will always run.

Most of the time you want this block to succeed.

$allServices = Get-Service
}
catch {

If there is an error in the try-block the catch-block will be executed.

You want to do some logging, maybe even abort the whole run because of the error in the try-block.

The example I gave you in the other post kind of reversed the meaning of try/catch, since it’s checking for a fail rather than a success.

}
finally {

If you use try, just must use catch.

finally is optional but it will run wether the try was successfull or triggered the catch.

Not sure if I’ve ever used it.

}
[/pre]

try/catch/finally is not really a test, it’s a wrapper for code that you want to be able to handle if it fails.

E.g. using a modification of your example:

[pre]
try {
[bool] (Get-ADUser -Filter {samAccountName -eq $UserName}) -ErrorAction Stop

Success!

Do-WhateverAction to $UserName
}
catch {
Write-Warning “Cought an error in the try-block”
}
[pre]

If either the first line in the try-block fails or the Do-WhateverAction fails it will trigger the catch-block.

Hi KLaage,

You would use a try /catch block for catching or handling a terminating error. In your case, I would recomment the following :

if (-not (Get-AdUser $UserName)) {
<# run code to add user#>
} else {
Write-Verbose -Message ("User '{0}' already exists in AD." -f $UserName)

I hope that helps.

 

Thank you to all who responded. It helped a lot.

I find that sometimes tutorials are too focused on the exact functionality it is teaching and forgets to show how it is, or can be, used in real world scenarios.

I will agree with a couple of you that the finally block seems, at first glance, mostly pointless.

I’d reccomend checking out the ebooks offered under free resources.
Namely the error handling ebook.

If you aren’t using try/catches around your actual ad object creation/manipulation scriptblocks especially.

https://leanpub.com/thebigbookofpowershellerrorhandling

A couple of problems:

Get-ADUser -Filter {samAccountName -eq $UserName}

That does not produce a terminating error, it just has no results because the search was unsuccessful, so try\catch is pointless. For a terminating error, you can do:

Get-ADUser -Identity $UserName

or I normally do this:

$user = Get-ADUser -Filter {samAccountName -eq $UserName}

if ($user) {
    Set-ADUser -Identity $user ...
}
else {
    'User {0} was not found' -f $username
}

I typically use Rob’s method above, for simplicity as much as anything. However, it is worth noting that you can use try/catch on specific error types, if you know what they are likely to be.

In this case, the most likely problem (if a username is mistyped) is that the AD user account won’t be found. Therefore, you can specifically deal with a Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException as follows:

$Username = "mickeymouse"
$Forename = "Mickey"
$Surname = "Mouse"

try{
Set-ADUser -Identity $Username -GivenName $Forename -Surname $Surname
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{
Write-Warning "This is not Disneyland!"
}
catch
{
Write-Warning "$Username exists, but something else went wrong: $($_.Exception.Message)"
}

This gives you the ability to handle specific types of error, before the final catch block deals with anything else. Note that this method starts with “Set-ADUser”, without making a preliminary “Get-ADUser” call to Active Directory. This may have a slight performance benefit (not tested).

Thank you again to all who responded.

In this case a simple if/else is probably just as good a solution as a try/catch, but this is just as much about teaching me the best ways of scripting solutions in PS as it is

I was aware of the problem with Get-ADUser -Filter not producing a terminating error, which is why I cast it as boolean in the OP. Have switched to the Get-ADUser -Identity in the version of the script I’m running now.

I was not aware there was a specific error type for AD Identity Not Found, that’s cool and something I will be using going forward.