powershelltry-catch-finally

Powershell finally block executed unexpectedly early


With the following script:

$ErrorActionPreference = 'Stop'

try {
  qweqweqwe
}
catch {
  Write-Error $_ #-ErrorAction Continue
}
finally {
  Read-Host -Prompt 'Press enter to continue'
}

Read-Host -Prompt 'What'

Here is the output (notice how the "finally" is executed before the "Write-Error":

Press enter to continue: 

C:\Demo.ps1 : The term 'qweqweqwe' 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 C:\Demo.ps1:7 char:3
+   Write-Error $_ #-ErrorAction Continue
+   ~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Demo.ps1

Here's the expected output when I uncomment "-ErrorAction Continue":

C:\Demo.ps1 : The term 'qweqweqwe' 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.
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Demo.ps1
 
Press enter to continue: 

What:

I can only assume that powershell, when it sees he'll "Write-Error" and exit, starts something like "ok but before that let's execute the finally block before".

Is this behavior documented somewhere?


Solution

  • Maybe this section in PowerShell's try-catch-finally documentation at least hints at the behavior you describe with

    PowerShell runs the finally block before the script terminates or before the current block goes out of scope.

    and

    A finally block runs even if you use CTRL+C to stop the script. A finally block also runs if an Exit keyword stops the script from within a catch block.

    Also, the behavior you observe seems common. For example JavaScript seems to have the same behavior when I test. And the following C# example

    using System;
                        
    public class Program
    {
        public static void Main()
        {
            try {
                Console.WriteLine("in try block");
                throw new Exception("throw in try block");
            } catch {
                Console.WriteLine("in catch block");
                throw new Exception("throw in catch block");
            } finally {
                Console.WriteLine("in finally block");
            }
        }
    }
    

    behaves the same as PowerShell; the output is

    in try block
    in catch block
    in finally block
    Run-time exception (line 12): throw in catch block
    

    Which aligns with the last paragraph in this section in the already referenced try-catch-finally documentation

    try, catch, and finally resemble the try, catch, and finally keywords used in the C# programming language.

    So maybe the documentation isn't particularly explicit because the try, catch, and finally blocks work similarly to other programming languages.