Search code examples
powershelltry-catchscriptblock

Variable = Executed script block with try/catch


I am trying to look for the presence of a specific registry property and if present set a variable to the value. I will be doing an If/Then/ElseIf sequence, so I don't want to wrap the hole thing in a Try/Catch to address the fact that in PS5.1 Get-ItemPropertyValue doesn't support -errorAction:silentlyContinue, so I really want to set the value to the execution of a code block that includes the try/catch with an empty catch, something like this...

if ($value = @{try {Get-ItemPropertyValue "Registry::$nameKey" -name:AdskProductCode}catch{}}) {

I feel like it's possible and I am close and just missing some nuance. Or perhaps this is a stupid idea and there is a better approach? They key reason for keeping the try/catch inside the if/then/else is because I will look for AdskProductCode and not finding that property I will look for AdskPackageCode, and in each case what I do with the value is different. If the try/catch wraps the iff then not finding AdskProductCode dumps me out completely and I never get to the else if looking for AdskPackageCode. Failing that there will be at least a final else, and maybe another else if, so simply looking for AdskPackageCode in the catch doesn't work. I could cascade the try/catch stuff, but good lord that's ugly.


Solution

  • to address the fact that in PS5.1 Get-ItemPropertyValue doesn't support -errorAction:silentlyContinue

    Indeed, as of PowerShell Core 7.0.0-preview.1 / Windows PowerShell v5.1, Get-ItemPropertyValue unexpectedly reports a statement-terminating rather than a non-terminating error - and only the latter kind of error can be controlled with the common
    -ErrorAction parameter
    .

    This problematic behavior - restricted to the case where the registry value (as opposed to the containing key) doesn't exist - has been reported in this GitHub issue.


    It is only terminating errors that try / catch can control, and using an empty catch block for a terminating error is the equivalent of passing -ErrorAction Ignore to a cmdlet producing a non-terminating error.

    Your only problem, as Mathias R. Jessen points out, was that you mistakenly wrapped your try / catch statement in @{ ... } - a hashtable literal - which itself caused a statement-terminating error.

    You may have been thinking of $( ... ), the subexpression operator, which would work in this case, but its use isn't necessary, so the following is enough:

    if ($value = try { Get-ItemPropertyValue "Registry::$nameKey" -name:AdskProductCode } catch{}) { ...
    

    That is, you can directly use a try / catch statement as an expression and therefore assign it to a variable.


    Given that Get-ItemPropertyValue's behavior may - and hopefully will - eventually be fixed, I suggest a different approach, however:

    Use Get-ItemProperty instead, and access the value name of interest on the resulting object as a property:

    if ($value = (Get-ItemProperty "Registry::$nameKey").AdskProductCode) { ...
    

    Note:

    • The general assumption is that key path "Registry::$nameKey" does exist (i.e., that it is only the registry value that may not exist); to ignore the non-existence of the key path too, use -ErrorAction Ignore.
    • The above assumes that either no strict mode or at most strict mode version 1 is in effect.
    • If, by contrast, Set-StrictMode -Version 2 or higher is in effect, don't use direct property access and pipe to Select-Object -ErrorAction Ignore -ExpandProperty AdskProductCode instead.