注意:
-
除非您准备好在每次升级到新的 PowerShell 版本时彻底测试每个现有的脚本/函数/编写的 PowerShell 模块,我建议避免
Set-StrictMode -Version Latest 在生产代码中 - 在开发过程中很好,但是在发布代码时,应该明确指定当时的最高版本,从而锁定。如果你不这样做,现有代码在更高版本的 PowerShell 中引入新的严格性检查时可能会中断。
-
底部显示了如何一般地处理使用有效的严格模式访问不存在的属性的尝试。
您可以按如下方式简化您的代码,这隐含地绕过尝试访问并非在所有输入对象上都存在的属性的问题:
$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')) { $_ } }
注意从-ErrorAction SilentlyContinue 到-ErrorAction Ignore 的切换:后者悄悄地丢弃任何错误,而前者不显示它们,但仍然将它们记录在自动$Error 集合中。
这利用了Microsoft.Win32.RegistryKey.GetValue() 方法悄悄地忽略 尝试检索不存在值的数据并返回$null 的事实。
顺便说一句:将common -ErrorAction parameter 应用于Where-Object (?) 和ForEach-Object (%) cmdlet 几乎没有意义,因为参数是不是应用于传递给这些命令的脚本块 ({ ... }) 内运行的代码。
在严格模式下访问不存在的属性时避免错误:
Set-StrictMode 和 -Version 2 或更高版本(包括 Latest)会导致尝试访问对象上不存在的属性以报告 statement-terminating 错误。
有几种方法可以避免此类错误:
-
在属性访问权限周围使用Try / Catch statement,同样如CFou's answer所示;这也使得在没有属性的情况下指定 默认值 变得很容易,但是与下面基于反射的方法相比,捕获异常是 缓慢:
$o = [pscustomobject] @{ foo = 1 }
$propValue = try { $o.NoSuchProperty } catch { 'default value' }
-
暂时在子范围中禁用严格模式(这与try / catch 方法一样慢):
$o = [pscustomobject] @{ foo = 1 }
# $propValue will effectively receive $null.
# Strictly speaking: [System.Management.Automation.Internal.AutomationNull]::Value
$propValue = & { Set-StrictMode -Off; $o.NoSuchProperty }
-
使用 reflection 测试属性的存在,通过所有对象上可用的隐藏.psobject.Properties 成员;这是最快的方法:
$o = [pscustomobject] @{ foo = 1 }
$propValue = if ($o.psobject.Properties['NoSuchProperty']) { $o.NoSuchProperty }
在 PowerShell [Core] 7.1+ 中,您可以通过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
-
自 v7.1 起的陷阱:如果您将
?. 直接应用于一个变量,您必须意外地将其名称包含在{...} 中,例如${var}?.Property; $var?.Property 没有按预期工作,因为 PowerShell 然后假定变量名称为 var? - 请参阅 GitHub issue #11379 以尝试更改它。
同样,null-coalescing operator, ??(它本身在 v7.0 中可用)可以简化提供 default 值(在早期版本中,您可以通过将 else 分支添加到 @ 987654366@以上声明):
$o = [pscustomobject] @{ foo = 1 }
# The RHS of `??` is used if the LHS evaluates to $null.
$propValue = $o.psobject.Properties['NoSuchProperty']?.Value ?? 'default value'