Powershell Finally the block is skipped with Ctrl-C
I am writing a monitoring script in Powershell using Try / finally to log a message at the end of the script. The script is for unlimited use, so I want to be able to track unexpected activities.
Every other StackOverflow entry and Help Page I've checked the states:
A Finally the block is executed even if you use CTRL + C to stop the script. The finally block is also executed if the Exit keyword stops the script from the Catch block.
In practice, I have not found this to be true. I use the following contrived example to test this:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
echo "goodbye!"
pause
}
The block Finally
is skipped here every time after Ctrl+ C(no echo, no pause), both when running as a saved script and when running through the built-in PowerShell ISE. The only way out I've ever gotten:
looping
looping
...(repeat until Ctrl-C)
I'm clearly missing something, but I have no idea what it is, especially in a small piece of code.
source to share
Correct answer: Ctrl+ Cbreaks the pipeline as mentioned in this link and echo
uses the pipeline to process its output. Therefore, once you Ctrl+ C, writing to the pipeline will result in a script block error and will not process further commands. Therefore, do not use commands that directly send output to stdout, and there are many that use a pipeline indirectly. Write-Host
on the other hand does not use a pipeline and thus does not throw an error.
source to share
Functional code
This will give you the behavior that I assume is after you:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
Write-Host "goodbye!"
pause
}
Links
Write-Output / echo - Short description
Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the console.
Write-Host - Short Description
Writes customized output to the host.
Try-Catch-finally - syntax note
Note that pressing CTRL + C stops the conveyor. Objects that are sent to the pipeline will not appear as output. Therefore, if you include a statement that will be displayed, such as "End Block", it will not appear after you press CTRL + C, even if the finally block was running.
Explanation
The key, as per TheIncorrigible1's comment and Vesper's answer, is that the pipeline is stopped . But this is not due to an error in the Write-Output
. And I don't think that this is a satisfactory explanation in and of itself.
- "If the command is the last command in the pipeline, the objects are displayed in the console." - it looks like this statement is false in the finally block. However, going to
Out-Host
explicitly will give the desired result. - In the comment Try-Catch-finally
- The encoded section is confusing as it applies to the raw objects sent to the pipeline.
- The objects sent to the pipeline and processed in the block
Finally
are fine. - It says "even if the finally block is running", but
pause
does not run if it is precededWrite-Output
.
More code
In the block Finally
, several actions were performed to investigate the behavior with comments on what was happening.
} Finally {
Write-Output "goodbye!" | Out-Default # works fine
pause
}
} Finally {
Write-Output "goodbye!" | Out-Host # works fine
pause
}
} Finally {
pause # works fine
Write-output "goodbye!" # not executed
}
} Finally {
try{
Write-Output "goodbye!" -ErrorAction Stop
}catch{
Write-Host "error caught" # this is not executed.
} # $error[0] after script execution is empty
pause
}
} Finally {
try{
ThisCommandDoesNotExist
}catch{
Write-Host "error caught" # this is executed
} # $error[0] contains CommandNotFoundException
pause
}
source to share