Note:
Unless you're prepared to thoroughly test and each every existing script / function / written-in-PowerShell module every time you upgrade to a new PowerShell version, I suggest avoiding
Set-StrictMode -Version Latest
in production code - it's fine during development, but when it comes to publishing code, the then-current highest version should be specified explicitly and thereby locked in. If you don't do that, existing code can break when a new strictness check is introduced in a later PowerShell version.
The bottom section shows how to generally deal with attempts to access nonexistent properties with strict mode in effect.
You can streamline your code as follows, which implicitly bypasses the problem of trying to access a property not present on all input objects:
$rootKey = 'hklm:\SYSTEM\ControlSet001\Control\Class'
# Find all keys that have a 'EeeLinkAdvertisement' value.
$findEeeLinkAd =
Get-ChildItem -LiteralPath $rootKey -Recurse -ErrorAction Ignore |
ForEach-Object { if ($null -ne $_.GetValue('EeeLinkAdvertisement')) { $_ } }
Note the switch from -ErrorAction SilentlyContinue
to -ErrorAction Ignore
: the latter quietly discards any errors, whereas the former doesn't display them, but still records them in the automatic $Error
collection.
This takes advantage of the fact that the Microsoft.Win32.RegistryKey.GetValue()
method quietly ignores attempts to retrieve data for a nonexistent value and returns $null
.
As an aside: It is virtually pointless to apply the common -ErrorAction
parameter to the Where-Object
(?
) and ForEach-Object
(%
) cmdlets, because the parameter is not applied to the code that runs inside the script blocks ({ ... }
) passed to these commands.
Avoiding errors when accessing non-existent properties in strict mode:
Set-StrictMode
with -Version 2
or higher (including Latest
) causes attempts to access a nonexistent property on an object to report a statement-terminating error.
Do note that this means that by default only the statement at hand is terminated, whereas overall script execution continues.
Also note that -Off
is the default value; that is, no strictness checks are performed by default, which means that even attempts to reference nonexistent variables do not trigger an error by default; Set-StrictMode -Version 1
checks for nonexistent variables, but not for nonexistent properties.
There are several ways of avoiding such errors:
Use a Try
/ Catch
statement around the property access, as also shown in CFou's answer; this also makes it easy to specify a default value in the absence of the property, but catching the exception is slow compared to the reflection-based approach below:
$o = [pscustomobject] @{ foo = 1 }
$propValue = try { $o.NoSuchProperty } catch { 'default value' }
Temporarily disable strict mode in a child scope (this is about as slow as the try
/ catch
approach):
$o = [pscustomobject] @{ foo = 1 }
# $propValue will effectively receive $null.
# Strictly speaking: [System.Management.Automation.Internal.AutomationNull]::Value
$propValue = & { Set-StrictMode -Off; $o.NoSuchProperty }
Use reflection to test a property's existence, via the hidden .psobject.Properties
member available on all objects; this is the fastest approach:
$o = [pscustomobject] @{ foo = 1 }
$propValue = if ($o.psobject.Properties['NoSuchProperty']) { $o.NoSuchProperty }
In PowerShell [Core] 7.1+, you can do this more succinctly, via the null-conditional operator ?.
:
$o = [pscustomobject] @{ foo = 1 }
# Note the `?.`, which only tries to access the property if the expression
# to the left isn't $null.
$propValue = $o.psobject.Properties['NoSuchProperty']?.Value
- Pitfall as of v7.1: If you apply
?.
directly to a variable, you must unexpectedly enclose its name in {...}
, e.g. ${var}?.Property
; $var?.Property
does not work as intended, because PowerShell then assumes the variable name is var?
- see GitHub issue #11379 for an attempt to change that.
Similarly, the null-coalescing operator, ??
(which itself became available in v7.0) can simplify providing a default value (which in earlier versions you can achieve by adding an else
branch to the if
statement above):
$o = [pscustomobject] @{ foo = 1 }
# The RHS of `??` is used if the LHS evaluates to $null.
$propValue = $o.psobject.Properties['NoSuchProperty']?.Value ?? 'default value'