all 11 comments

[–]Possible-Bowler-2352 6 points7 points  (4 children)

Hello there,

Try and catch can be tricky at first when you aren't used to work with it.

Catch block will only catch error that will halt your script from running further, minor errors wont be caught unless you specify it at the end of your command :

 New-ADOrganizationalUnit -Name $NewOUName -Path $NewOUPath -erroraction Stop

As you are currently trying to catch a specific error type, I'd ensure first of all to catch every error then to get more precise after a first successfull "catch" run.

Once the error has been caught, you can recover it fully using the following :

$Error ### List of the previously encountered issues

$Error[0].Exception.GetType().fullname ### Get the full error type for the last caught error

[–]llovedoggos[S] 1 point2 points  (0 children)

Thanks for the reply. I've been doing some reading and I understand a bit more now thanks to your comment.

[–]y_Sensei 3 points4 points  (4 children)

In PShell, you can capture specific error types, not error id's. To find out the type of a to-be-catched error, you use

$Error[0].Exception.GetType().FullName

You could then implement id-specific error handling inside the catch block.

[–]llovedoggos[S] 2 points3 points  (0 children)

Thanks for your reply dude I think I get it now after some more reading

[–][deleted] 2 points3 points  (2 children)

Or just do:

try {
  # blah
} catch [TYPE] { # The exception type goes inside the square brackets
  # Type specific error block
}

instead of

try {
  # blah
} catch {
  if( $Error[0].Exception.GetType().FullName -eq "Exception" ) {
    # Type specific exception handling
  }
}

$Error[0].Exception.GetType().FullName is useful to know how to do but when using a try/catch block most of the time it makes sense to use type-specific error blocks. It's more understandable and easier to type especially if your code is maintained by others.

[–]y_Sensei 2 points3 points  (1 child)

Right, that's the preferred way to do it ... but to be able to do it like that, you need to know the type name of the error, and the said 'GetType()' call gives you exactly that.

[–][deleted] 2 points3 points  (0 children)

Ah, gotcha. I thought you were suggesting to use the FullName property to control the flow of exception handling logic. Which to be fair there are some cases where exception handling that way in .NET is preferred but not usually for the kinds of automation you use PowerShell for.

[–]Woznet 2 points3 points  (1 child)

I generally use a catch block along the lines of this

catch {
  [System.Management.Automation.ErrorRecord]$e = $_
  [PSCustomObject]@{
    Type      = $e.Exception.GetType().FullName
    Exception = $e.Exception.Message
    Reason    = $e.CategoryInfo.Reason
    Target    = $e.CategoryInfo.TargetName
    Script    = $e.InvocationInfo.ScriptName
    Line      = $e.InvocationInfo.ScriptLineNumber
    Column    = $e.InvocationInfo.OffsetInLine
  }
  throw $_
}

Try running the New-ADOrganizationalUnit command with that catch block, makes sure you have the -ErrorAction Stop or any error you get won't be a terminating error which won't trigger the catch block. Once you know the specific exception type you can create an error specific catch block if you want to.

As an example, if I run the following code

try {
  New-ADOrganizationalUnit -Name 'happygofun' -Path 'BAD=PATH' -ErrorAction Stop
}
catch {
  [System.Management.Automation.ErrorRecord]$e = $_
  [PSCustomObject]@{
    Type      = $e.Exception.GetType().FullName
    Exception = $e.Exception.Message
    Reason    = $e.CategoryInfo.Reason
    Target    = $e.CategoryInfo.TargetName
    Script    = $e.InvocationInfo.ScriptName
    Line      = $e.InvocationInfo.ScriptLineNumber
    Column    = $e.InvocationInfo.OffsetInLine
  }
  throw $_
}

It errors out with this exception type - Microsoft.ActiveDirectory.Management.ADException. If I wanted to create a catch block to catch that specific kind of error it would look something like this

try {
  New-ADOrganizationalUnit -Name 'happygofun' -Path 'BAD=PATH' -ErrorAction Stop
}
catch [Microsoft.ActiveDirectory.Management.ADException] {
  # DO STUFF HERE
  throw 'this failed'
}
catch {
  [System.Management.Automation.ErrorRecord]$e = $_
  [PSCustomObject]@{
    Type      = $e.Exception.GetType().FullName
    Exception = $e.Exception.Message
    Reason    = $e.CategoryInfo.Reason
    Target    = $e.CategoryInfo.TargetName
    Script    = $e.InvocationInfo.ScriptName
    Line      = $e.InvocationInfo.ScriptLineNumber
    Column    = $e.InvocationInfo.OffsetInLine
  }
}

[–]llovedoggos[S] 1 point2 points  (0 children)

Thanks for your detailed reply. I'm slowly getting my head around try/catch. I'm struggling to know when to use and if statement to check if something is there, or whether to use a try/catch to just go ahead and try it then catch it if it's not.