为什么我可以这样做:
示例1
Get-NetIPConfiguration -Detailed |
? IPv4DefaultGateWay -NE $null
和
示例2
Get-NetIPConfiguration -Detailed |
? {$_.IPv4DefaultGateWay -NE $null -and $_.NetAdapter.Status -EQ "Up"}
但不是这个
示例3
Get-NetIPConfiguration -Detailed |
? IPv4DefaultGateWay -NE $null -and NetAdapter.Status -EQ "Up"
我得到的错误消息如下:
Where-Object : Parameter set cannot be resolved using the specified named parameters.
At line:2 char:3
+ ? IPv4DefaultGateWay -NE $null -and NetAdapter.Status -EQ "Up"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Where-Object], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.WhereObjectCommand
但很明显,Where-Object cmdlet能够通过使用-和-或来处理复合条件,因此错误消息令人困惑。
还有,为什么我可以做这个
示例4
Get-NetIPConfiguration -Detailed |
? {$_.IPv4DefaultGateWay -NE $null -and $_.NetAdapter.Status -EQ "Up"} |
% {
New-Object -TypeName PSObject -Property @{
ComputerName = $_.ComputerName
IPAddress = $_.IPv4Address.IPv4Address
}
}
但无法进行
示例5
Get-NetIPConfiguration -Detailed |
? {$_.IPv4DefaultGateWay -NE $null -and $_.NetAdapter.Status -EQ "Up"} |
Select-Object ComputerName, IPv4Address.IPv4Address
我的目标是通过使用示例4来实现,但这不是我在这里真正要求的——我在这里更关心的是寻址属性和属性的属性的约定!
这些差异最终源于PowerShell的两种基本解析模式,在这个答案中进行了解释;简而言之:
-
参数模式类似于shell,用于调用带有空格分隔的自变量的命令,并支持未加引号的字符串。
-
表达式模式与传统编程语言类似,具有带引号的字符串、运算符、循环构造。。。
在您的两个示例中,命令都被调用(更具体地说,cmdlets,即Where-Object
(其内置别名为?
和where
(和Select-Object
(其内置昵称为select
(,因此传递给它们的内容将在参数模式中解析:
-
Where-Object IPv4DefaultGateWay -NE $null
对简化语法使用参数模式,即替代表达式模式脚本块({ ... }
(的较低仪式参数模式,也可与ForEach-Object
cmdlet一起使用。-
语法更简单:
{ ... }
中无需外壳- 不需要通过自动
$_
变量引用手头的输入对象,只需使用属性名称本身就足够了
-
但它是有限的:
- 您只能在单个属性上执行单一操作[1]
- 该属性必须是立即属性(例如,
IPv4DefaultGateWay
,而不是嵌套的属性(例如NetAdapter.Status
(-详细信息如下
-
-
Select-Object
也有一个约束,即给定的属性名称必须是立即属性。- 解决这一问题的唯一方法是通过计算属性,通过哈希表实现,该哈希表的
Expression
条目包含一个脚本块,用于计算每个输入对象的属性值-请参阅此答案
- 解决这一问题的唯一方法是通过计算属性,通过哈希表实现,该哈希表的
为什么在参数解析模式中不支持嵌套属性访问(例如NetAdapter.Status
(:
参数(如NetAdapter.Status
,无论是否引用(作为字符串传递给命令,Where-Object
和Select-Object
将传递给其-Property
参数的字符串解释为属性的逐字名称,而不是嵌套的属性访问表达式。
也就是说,等效于以下命令,其中NetAdapter.Status
在参数模式中解析:
Get-NetIPConfiguration -Detailed |
Select-Object -ExpandProperty NetAdapter.Status
是以下表达式模式属性访问:
Get-NetIPConfiguration -Detailed |
ForEach-Object { $_.'NetAdapter.Status' }
请注意NetAdapter.Status
周围的'...'
,显示该名称被逐字逐句地用作输入对象上的单个直接属性名称(不能按预期工作(。
设计原理:
挑战在于,在自变量模式中,NetAdapter.Status
、'NetAdapter.Status'
和"NetAdapter.Status"
之间没有区别——目标命令在所有情况下都能看到逐字的NetAdapter.Status
,因此,与表达式不同的是,原始引用/非引用不能区分这些自变量形式。
然而,可以说,对于专门接受属性名称(参数-Property
(的cmdlet来说,将参数(如NetAdapter.Status
(解释为嵌套的属性访问器要有用得多,因为嵌入了.
字符的属性名称。是罕见的。
改变这种行为将是一个打破的改变,然而,考虑到以下目前有效,但不再有效:
PS> '{ "foo.bar": 42 }' | ConvertFrom-Json | Select-Object foo.bar
foo.bar
-------
42
[1]这两种解析模式非常不同,不可能在自变量模式下重新创建所有表达式模式特征;您无法用命令参数(参数定义(对表达式模式的复杂性进行建模。简化语法是一种折衷方案,旨在使简单但常见的用例在语法上更容易