That would work. The other way - and the way I would normally use - is to create a module containing the three task functions and a controlling function.
You could do that, but keep in mind that the $error variable is not guaranteed to be empty when your script starts. You could either clear it yourself, or use ErrorVariable in your function calls (make sure each of the functions has the [CmdletBinding()] or [Parameter()] attributes somewhere, so they will be advanced functions that accept the common parameters.)
Another option would be to put all three tasks into a Try block in conjunction with ErrorAction Stop (to make sure any errors are terminating errors); if an error occurs, the subsequent steps don’t run.
Doing this isn’t a good idea
try
{
c:\Execute-Task1.ps1 -ErrorAction Stop
c:\Execute-Task2.ps1 -ErrorAction Stop
c:\Execute-Task3.ps1 -ErrorAction Stop
}
catch
{
throw
}
Why?
Because you don’t know where the errors are coming from.
When you are using try-catch blocks you want to have the minimum code in the try block. This enables you to handle the errors in a more specific way that is tailored to the commands you are running.
Your code should look more like this:
Just depends on what your requirements for the error handling / reporting are. If all you’re doing is rethrowing the error (as in my example), there’s no advantage to having three separate try/catch blocks rather than one. If you’re wrapping the error in a new object or reformatting it in some way (as your (throw # mesages relevant to task 2) example seems to imply), then it’s better to have a separate try block for each task.
As a best practice you should always have the minimum code in your try block. if you aren’t going to be using the exception catching then why bother with it in the first place.
In PowerShell, you can use try { whatever } catch { throw } to enforce consistent behavior from different sources of terminating errors; by default, some of them cause your current script or function to abort, and others just output the error and move on to the next statement. This isn’t necessary in other languages where any unhandled error automatically kills the execution of your current scope and passes the error back to the parent. PowerShell’s fairly unique in that sense, and as a result, many of the best practices that we inherit from C# or Java don’t always apply.
The PowerShell try-catch block is based on C# in that you try something and if a .NET exception is raised you can manage it in the catch block.
To that end minimising the number statements within your try block enables your catch block to specific in its exception handling
I understand that, and agree with it, if your intention is to actually handle a specific error from a specific statement.
My point is that PowerShell behavior is not consistent when it encounters an unhandled terminating error. Depending on how that terminating error was generated, sometimes PowerShell aborts the execution of your current scope (similar to an unhandled exception in C#), and sometimes it continues execution with the next statement. You can use try/catch to enforce the first behavior, if that’s what you want to happen. For example:
This has nothing to do with handling a particular error; it’s about making sure that PowerShell aborts your current function if any of those commands produce a terminating error that you haven’t handled (which can be done with smaller try/catch blocks inside the large Try block, if you like.) This is one of the little PowerShell quirks covered in the draft of the Error Handling ebook that I’m working on.
Here’s an example of a situation where PowerShell will continue execution even after a terminating error. I happened to be looking at the Add-Type cmdlet in DotPeek this morning, so it’s fresh in my memory that it throws a terminating error if both the Language and CodeDomProvider parameters are passed:
Function Test-Function
{
[CmdletBinding()]
param ( )
$provider = [System.CodeDom.Compiler.CodeDomProvider]::CreateProvider('CSharp')
'Statement before error.'
Add-Type -Language CSharp -CodeDomProvider $provider -TypeDefinition 'public class TestClass { public int TestProperty; }'
'Statement after error.'
}
Test-Function