In PowerShell, a Get-Item call inside a try block fails and prints a red error, but the catch block never runs and the script keeps going. Explain the difference between terminating and non-terminating errors, and how you make that call catchable.
answer
- two error kinds, not one
- red text is not an exception
- catch only sees the terminating kind
- one common parameter converts them
- -ErrorAction Stop on the call
basics
~20 sMost cmdlet failures are non-terminating errors: they write a record to the error stream and execution continues, so try/catch never fires. Adding -ErrorAction Stop turns that call's errors into terminating ones, which a catch block handles.
solid answer
~50 sPowerShell has two error kinds. A **terminating** error stops the current pipeline and unwinds until something catches it — `throw`, an exception from a .NET method, or a cmdlet that deliberately raises one. A **non-terminating** error is a report, not a halt: the cmdlet writes an `ErrorRecord` to the error stream, the host prints it in red, and the next statement runs. `try/catch` is exception machinery, so it reacts only to the terminating kind — which is exactly why you can see red text while `catch` stays silent. The fix is `-ErrorAction Stop` on that call, which converts that cmdlet's non-terminating errors into terminating ones. `$ErrorActionPreference = 'Stop'` does the same for a whole scope, but I prefer the per-call parameter: it is explicit and does not change behaviour for code I did not mean to affect. Be aware Stop also makes a multi-item cmdlet abort at the first failure.
code
powershell · 14 lines# Non-terminating: the catch block is never entered
try {
Get-Item 'C:\does-not-exist'
Write-Output 'try block continued'
} catch {
Write-Output 'not reached'
}
# Terminating: -ErrorAction Stop makes the same failure catchable
try {
Get-Item 'C:\does-not-exist' -ErrorAction Stop
} catch {
Write-Output "caught: $($_.Exception.Message)"
}go deeper
Recall that a red error message does not necessarily stop a PowerShell script, and that -ErrorAction Stop is what makes a failing cmdlet call reach a catch block.
Explain the two error kinds, name $ErrorActionPreference and its Continue default, and describe precisely how -ErrorAction Stop converts one call's errors into terminating ones.
Show judgment about where the lever goes: per-call -ErrorAction Stop inside try blocks rather than a blanket preference, and note that Stop makes a multi-item cmdlet abort at the first failure.
Argue for a house convention — fail fast versus attempt-everything-and-report — and be explicit about what a Stop preference does not cover, such as external programs that merely exit non-zero.
## Two error kinds, not one Every confusing `try/catch` story in PowerShell starts with a split that most other shells and languages do not have. A **terminating error** stops the current pipeline immediately and unwinds the call stack until something handles it. `throw` raises one. An exception thrown by a .NET method you called is one. A cmdlet that hits a condition it cannot continue past raises one deliberately (internally through `ThrowTerminatingError`). A **non-terminating error** is a *report*. The cmdlet writes an `ErrorRecord` object to the error stream (stream 2), the host renders it in red, `$?` becomes `$false`, the record is appended to `$Error`, and execution continues with the next input item and the next statement. `Get-ChildItem` walking a large tree and hitting one unreadable directory is the canonical case: you want the other 999 directories, not an abort. Most cmdlet failures are non-terminating. That is the design, and it is why the default value of `$ErrorActionPreference` in a fresh session is `Continue`. ## Why catch is never entered `try/catch` is exception machinery: it only sees terminating errors. A non-terminating error unwinds nothing, so control never leaves the `try` block abnormally and the `catch` block is simply skipped. ```powershell try { Get-Item 'C:\does-not-exist' # non-terminating: prints red, keeps going 'still running' # this DOES print } catch { 'never printed' } ``` The red text makes it look like an exception fired. It did not. Candidates who have only ever seen exceptions in C# or Java assume that error output implies unwinding, and write `try/catch` wrappers that quietly handle nothing. ## The lever: -ErrorAction Stop `-ErrorAction` is a *common parameter*, available on every cmdlet and on advanced functions. Setting it to `Stop` converts that one call's non-terminating errors into terminating ones: ```powershell try { Get-Item 'C:\does-not-exist' -ErrorAction Stop } catch { "handled: $($_.Exception.Message)" } ``` The full set of values is worth knowing: - `Continue` — print the error, keep going. The default. - `SilentlyContinue` — keep going without printing, but the record is still added to `$Error` (and to `-ErrorVariable` if you asked for one). - `Ignore` — discard the error entirely; it is not recorded in `$Error`. Valid only as a `-ErrorAction` argument; assigning `Ignore` to `$ErrorActionPreference` is an error. - `Stop` — make it terminating. - `Inquire` — prompt the user. - `Break` — enter the debugger (PowerShell 7.x). ## The scope lever: $ErrorActionPreference `$ErrorActionPreference` is a preference variable applying to cmdlet calls that do not specify `-ErrorAction` themselves. It is scoped like any variable: setting it at the top of a script affects that script and code called from it, and it reverts when the scope ends — it does not permanently reconfigure the user's session. `-ErrorAction` on an individual call always wins over the preference. Many teams put `$ErrorActionPreference = 'Stop'` at the top of automation scripts to get fail-fast behaviour. That is a defensible convention, but understand what it does *not* cover: errors that are already terminating (unchanged), exceptions from .NET method calls (already terminating and always catchable), and external programs that merely exit non-zero — those are not error records at all. ## The cost of Stop on a multi-item cmdlet One consequence catches people out. A cmdlet given many inputs normally reports a non-terminating error per bad item and processes the rest. Under `-ErrorAction Stop` it aborts at the first failure, leaving the remaining items untouched: ```powershell # processes every reachable path, complains about the rest Get-Item $paths # stops dead at the first missing path Get-Item $paths -ErrorAction Stop ``` If you want every item attempted *and* a record of the failures, do not use `Stop` on the bulk call — either loop with a per-item `try/catch` and `-ErrorAction Stop` inside the loop, or keep going with `SilentlyContinue` and collect the records. ## finally `finally` runs whether or not an error occurred, and runs before the error continues propagating — the place for releasing a session, closing a file handle, or restoring a changed preference. A `try` needs only one of `catch` or `finally`; `try/finally` with no catch is a legitimate cleanup pattern that lets the error escape to a caller who knows what to do with it.
- Does -ErrorAction Stop also affect an exception thrown by a .NET method call inside your script?No. `-ErrorAction` is a common parameter honoured by cmdlets and advanced functions; it means nothing to a .NET method call. But you do not need it there: a method that throws raises a terminating error already, so a surrounding `catch` handles it either way.
- What is the practical difference between -ErrorAction SilentlyContinue and -ErrorAction Ignore?Both suppress the red output and continue. `SilentlyContinue` still records the `ErrorRecord` in `$Error`, so you can inspect it afterwards; `Ignore` discards it entirely, leaving nothing to audit. `Ignore` is also legal only as a parameter argument — assigning it to `$ErrorActionPreference` fails.
- If you put $ErrorActionPreference = 'Stop' at the top of a script, does it leak into the user's session after the script ends?No. It is an ordinary variable subject to PowerShell's scoping, so the assignment lives in the script's scope and disappears when the script exits. It does apply to functions the script calls, unless they set their own value or the call passes an explicit `-ErrorAction`.
saying these in an interview costs you the question
- Believes try/catch catches every PowerShell error
- Says a red error message always stops the script
- Wraps calls in try/catch but never adds -ErrorAction Stop
- Thinks $ErrorActionPreference changes the machine permanently
- Confuses -ErrorAction with -ErrorVariable