en-us/about_Scripting_Try_Catch.help.txt

TOPIC
    about_Scripting_Try_Catch
 
SHORT DESCRIPTION
    A tutorial and suggestions on using Try/Catch.
     
LONG DESCRIPTION
    I see a lot of scripts that people write so I’d include a short guide on
    how to properly use Try/Catch. This is the way I think it should be used.
     
    Let’s start with a Try/Catch block that might look ok at first glance.
 
    Try {
      Get-Service Foo
    }
 
    Catch {
      Write-Warning "Oops"
      Write-Warning $_.Exception.Message
    }
     
    You might expect that if the service FOO can’t be found that the code in
    the Catch script block will run.
 
    PS C:\work> .\trydemo.ps1
    Get-Service : Cannot find any service with service name 'Foo'.
    At C:\work\trydemo.ps1:4 char:14
    + Get-Service <<<< Foo
        + CategoryInfo : ObjectNotFound: (Foo:String) [Get-Service],
        ServiceCommandException
        + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.Power
        Shell.Commands.GetServiceCommand
         
    Nope. I got an exception, but my code in the Catch script block did not
    run. You can only catch *terminating* exceptions. In order for Try/Catch
    to work properly, I have to make sure that if there is an exception, that
    it gets treated as a terminating exception.
     
    The best way is to use the common -ErrorAction parameter and set it to
    Stop. Usually this is done on a per cmdlet basis.
 
    Try {
      Get-Service Foo -ErrorAction Stop
    }
 
    Catch {
      Write-Warning "Oops"
      Write-Warning $_.Exception.Message
    }
     
    The parameter has an alias of -ea which you’ll often see used. Now let’s
    see what happens:
 
    PS C:\work> .\trydemo.ps1
    WARNING: Oops
    WARNING: Cannot find any service with service name 'Foo'.
    PS C:\work>
     
    That’s what I was expecting. The exception was detected and treated as a
    terminating exception which was caught by the Catch scriptblock. The $_
    in the Catch scriptblock is the exception object.
     
    Now for the tricky part. Look at this variation.
 
    Try {
      Get-Service -ComputerName Bogus
    }
 
    Catch {
      Write-Warning "Oops"
      Write-Warning $_.Exception.Message
    }
     
    What happens when I run this?
 
    PS C:\work> .\trydemo.ps1
    WARNING: Oops
    WARNING: Cannot open Service Control Manager on computer 'Bogus'. This
    operation might require other privileges.
     
    How about that? Even without -erroraction, my catch code still ran. Based
    on this I can safely deduce that the remote connection failure auto-
    matically created a terminating exception. So the fact that I didn't have
    -ErrorAction Stop was irrelevant.
     
    But without a lot of trial and error or experience, I think it is extremely
    difficult to know in advance what type of error will throw a terminating
    exception and what won’t. Personally, I think the best approach is to
    always use -ErrorAction stop on a cmdlet in a Try scriptblock to guarantee
    you will always get a terminating exception.
 
    Finally, depending on your needs you might have a single Try/Catch that
    handles multiple commands. If so, you can set the ErrorActionPreference
    at the scope level.
     
    Try {
        $ErrorActionPreference='Stop'
        $comp = "SERVER01"
        Write-Host "Getting Process data" -foreground Green
        $p = Get-Process svchost -computername $comp
        Write-Host "Getting Service data" -foreground Green
        $s = Get-Service -computername $comp | where {$_.status -eq 'Running'}
        Write-Host "Getting OS data" -foreground Green
        $w = Get-WMIObject win32_operatingsystem -computername $comp
    }
    Catch {
        Write-Warning "There was a problem gathering data"
        Write-Warning $_.Exception.message
    }
     
    If any of the commands in the Try scriptblock encounter and error, they
    will be treated as terminating exceptions and code in the Catch scriptblock
    will run. Also note that if there is a terminating exception in one command
    subsequent commands will not be run and PowerShell will move on to whatever
    is after the Catch scriptblock.
 
SEE ALSO
    about_Try_Catch_Finally