3

The following code works (i.e. returns the expected data from the registry), however it throws a non-terminating error due to a lack of permissions to one of the target key's subkeys, which is benign for this use case.

$adapterKeys = $null
$adapterKeys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}"
$adapters = $null
$adapters = $adapterKeys | Get-ItemProperty
$adapters | Select -First 1

When specifying -ErrorAction "Stop", a terminating error is thrown, but no data is returned:

$adapterKeys = $null
$adapterKeys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}" -ErrorAction "Stop"
$adapters = $null
$adapters = $adapterKeys | Get-ItemProperty
$adapters | Select -First 1

So I can catch the error with ErrorAction "Stop" and try{} catch{}, but this defeats the purpose since the data is no longer returned.

So with these constraints, how can I return the necessary data, but also catch and ignore the error? Note that I don't want to ignore ALL errors, otherwise I would just use -ErrorAction "SilentlyContinue".

Is this expected behavior for Get-ChildItem and/or -ErrorAction "Stop"? I don't recall ever running into such an issue before.

Just for reference, the error thrown is:

Get-ChildItem : Requested registry access is not allowed.
At line:2 char:16
+ … apterKeys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Control\Cla …
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (HKEY_LOCAL_MACHINE\…BE10318}\Properties:String) [Get-ChildItem], SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShell.Commands.GetChildItemCommand

This is due to the Properties subkey of the target registry key being permissioned such that it is inaccessible to even local administrators. As noted, this is irrelevant for this use case because I don't need the data from this Properties subkey; only from the other subkeys.

One workaround would be to use Get-ItemProperty directly on all of the target subkeys, thus never encountering the Properties key or this specific error at all. However I cannot know how many subkeys there will be, and while they likely will always have a consistent, numerical naming convention, I would like to avoid making these assumptions. Also this question is more about what I'm misunderstanding about the behavior of Get-ChildItem and/or terminating errors.

Edit: some related questions and info I've come across:

  • This question suggests using -ErrorAction "SilentlyContinue" and -ErrorVariable for post-processing errors, however this doesn't make a lot of sense to me.
  • This question suggests that there is a poorly-documented "semi-terminating" error type, though I suspect that's not applicable here. Also discusses the trap keyword, which I've never heard of, nor had a use for before.

FWIW, my target environment is Windows PowerShell 5.1, although I have the same issue on PowerShell 7+, and on the latest versions of both Win10 and Win11.

1
  • As for the "semi-terminating" errors: they are statement-terminating errors, as opposed to a script-terminating (runspace-terminating ones), and the difference is explained in this answer. However, both these types of terminating errors can be caught with try { ... } catch { ... } (and also by the obsolescent trap statement). This GitHub docs issue tries to provide a comprehensive overview of PowerShell's - bewilderingly complex - error handling. Commented Mar 15 at 22:37

1 Answer 1

2

Is this expected behavior for Get-ChildItem and/or -ErrorAction "Stop"?

Yes: -ErrorAction Stop by design raises a script-terminating (runspace-terminating) error upon encountering a non-terminating error and therefore implicitly aborts the pipeline that the command is a part of, resulting in no captured output.

That is, if you try to assign the output from your pipeline to a variable, that variable is never assigned to, even if you catch (trap) the script-terminating error via a try ... catch statement.[1]


This question suggests using -ErrorAction "SilentlyContinue" and -ErrorVariable for post-processing errors, however this doesn't make a lot of sense to me.

It is, however, the only way to:

  • (a) let your pipeline run to completion and therefore collect its output in a variable
  • and (b) determine after the fact whether only expected errors occurred:
# Silence errors, but collect them in self-chosen variable $errs,
# while collecting all successfully enumerated items in $adapterKeys.
$adapterKeys =
  Get-ChildItem -ErrorAction SilentlyContinue -ErrorVariable errs "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}" 

# See if any *unexpected* errors occurred, i.e. errors other than permission-denied ones.
$unexpectedErrors = 
  $errs | Where-Object { $_.CategoryInfo.Category -ne 'PermissionDenied' }

# Act on unexpected errors
if ($unexpectedErrors) {
  throw "Unexpected errors occurred: $unexpectedErrors"
}

[1] Note that, without a variable assignment, partial results print to the host (display) before the first error is encountered and the pipeline is aborted; however, a variable assignment of necessity needs to collect all pipeline output, and this process of collecting is aborted along with the pipeline, and no assignment takes place.
Compare Get-Item ., NoSuch -ErrorAction Stop with $var = Get-Item ., NoSuch -ErrorAction Stop: the former prints the output from Get-Item . to the display and then fails, whereas the latter never completes the assignment to $var, because the script-terminating error occurs before the pipeline runs to completion.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, the question I referenced just suggested the -ErrorVariable solution without an example, so your demonstration of how to perform the error handling after the fact made it click. I'm a little surprised I've never run into this before, but in other instances I likely just never happened to run into errors, or didn't care as much about letting the benign errors leak into the output.
Glad to hear it helped, @mmseng. Indeed, how to perform post-processing of the collected errors isn't exactly obvious, and suppressing all errors is a convenient - if not robust - way around that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.