select cmdlet 不接受计算属性中生成的字符串名称
Generated string names in Calculated Properties aren't accepted by select cmdlet
我想生成以下内容 table:
AAA BBB CCC
--- --- ---
10 10 10
10 10 10
10 10 10
10 10 10
10 10 10
所以我使用 foreach
循环编写了以下代码来生成列名:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
@(1..5) | select -Property $property
但是我收到以下错误消息说 name
不是 string
:
select : The "name" key has a type, System.Management.Automation.PSObject, that is not valid; expected type is System.String.
At line:4 char:11
+ @(1..5) | select -Property $property
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupportedException
+ FullyQualifiedErrorId : DictionaryKeyIllegalValue2,Microsoft.PowerShell.Commands.SelectObjectCommand
为了使代码正常工作,我必须将 $_
转换为 string
,如下所示:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = [string]$_; expression = { 10 } }
}
@(1..5) | select -Property $property
或如下所示:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
$property | foreach { $_.name = [string]$_.name }
@(1..5) | select -Property $property
问题是:$_
已经是 string
。为什么我必须再次将其转换为 string
?为什么 select
认为 name
是 PSObject
?
为了确认它已经是一个string
,我写了下面的代码来打印name
的类型:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
$property | foreach { $_.name.GetType() }
以下结果证实它已经是 string
:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
True True String System.Object
True True String System.Object
我知道还有许多其他更简单的方法可以生成 table。但我想了解为什么我必须将 string
转换为 string
才能使代码正常工作,以及为什么 select
不认为 string
是 string
。对于它的价值,我的 $PSVersionTable.PSVersion
是:
Major Minor Build Revision
----- ----- ----- --------
5 1 18362 1474
您看到了 偶然的不幸影响,通常 不可见 [psobject]
包装器 PowerShell 在幕后使用。
在您的情况下,因为输入字符串是通过管道提供的,所以它们被包装并存储为 作为 [psobject]
个实例 在您的哈希表中,这就是原因的问题。
解决方法——既不明显也不必要——是 通过访问 .psobject.BaseObject
:
丢弃包装器
$property = 'AAA', 'BBB', 'CCC' | ForEach-Object {
@{ name = $_.psobject.BaseObject; expression = { 10 } }
}
1..5 | select -Property $property
注:
在您的情况下,.psobject.BaseObject
的更简单替代方法(请参阅概念性 about_Intrinsic Members 帮助主题)应该是调用 .ToString()
,因为您想要一个字符串。
要测试给定值/变量是否存在此类包装器,请使用 -is [psobject]
;使用您的原始代码,以下生成 $true
,例如:
$property[0].name -is [psobject]
- 但是请注意,此测试对
[pscustomobject]
个实例没有意义,它是 always $true
(自定义对象本质上是 [psobject]
没有 .NET 基础对象的实例 - 它们只有动态属性)。
通常不可见的 [psobject]
包装器 在特定情况下,模糊地 导致行为差异可以说是一个 bug 和 GitHub issue #5579.
的主题
更简单、更快速的替代方法,使用 .ForEach()
array method:
$property = ('AAA', 'BBB', 'CCC').ForEach({
@{ name = $_; expression = { 10 } }
})
1..5 | select -Property $property
与管道不同,.ForEach()
方法不将$_
包装在[psobject]
,因此不会出现问题,也不需要解决方法。
使用该方法也更快,但请注意,与管道不同,它必须预先将所有输入收集到内存中(数组文字显然不是问题) .
我想生成以下内容 table:
AAA BBB CCC
--- --- ---
10 10 10
10 10 10
10 10 10
10 10 10
10 10 10
所以我使用 foreach
循环编写了以下代码来生成列名:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
@(1..5) | select -Property $property
但是我收到以下错误消息说 name
不是 string
:
select : The "name" key has a type, System.Management.Automation.PSObject, that is not valid; expected type is System.String.
At line:4 char:11
+ @(1..5) | select -Property $property
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupportedException
+ FullyQualifiedErrorId : DictionaryKeyIllegalValue2,Microsoft.PowerShell.Commands.SelectObjectCommand
为了使代码正常工作,我必须将 $_
转换为 string
,如下所示:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = [string]$_; expression = { 10 } }
}
@(1..5) | select -Property $property
或如下所示:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
$property | foreach { $_.name = [string]$_.name }
@(1..5) | select -Property $property
问题是:$_
已经是 string
。为什么我必须再次将其转换为 string
?为什么 select
认为 name
是 PSObject
?
为了确认它已经是一个string
,我写了下面的代码来打印name
的类型:
$property = @('AAA', 'BBB', 'CCC') | foreach {
@{ name = $_; expression = { 10 } }
}
$property | foreach { $_.name.GetType() }
以下结果证实它已经是 string
:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
True True String System.Object
True True String System.Object
我知道还有许多其他更简单的方法可以生成 table。但我想了解为什么我必须将 string
转换为 string
才能使代码正常工作,以及为什么 select
不认为 string
是 string
。对于它的价值,我的 $PSVersionTable.PSVersion
是:
Major Minor Build Revision
----- ----- ----- --------
5 1 18362 1474
您看到了 偶然的不幸影响,通常 不可见 [psobject]
包装器 PowerShell 在幕后使用。
在您的情况下,因为输入字符串是通过管道提供的,所以它们被包装并存储为 作为 [psobject]
个实例 在您的哈希表中,这就是原因的问题。
解决方法——既不明显也不必要——是 通过访问 .psobject.BaseObject
:
$property = 'AAA', 'BBB', 'CCC' | ForEach-Object {
@{ name = $_.psobject.BaseObject; expression = { 10 } }
}
1..5 | select -Property $property
注:
在您的情况下,
.psobject.BaseObject
的更简单替代方法(请参阅概念性 about_Intrinsic Members 帮助主题)应该是调用.ToString()
,因为您想要一个字符串。要测试给定值/变量是否存在此类包装器,请使用
-is [psobject]
;使用您的原始代码,以下生成$true
,例如:$property[0].name -is [psobject]
- 但是请注意,此测试对
[pscustomobject]
个实例没有意义,它是 always$true
(自定义对象本质上是[psobject]
没有 .NET 基础对象的实例 - 它们只有动态属性)。
通常不可见的 [psobject]
包装器 在特定情况下,模糊地 导致行为差异可以说是一个 bug 和 GitHub issue #5579.
更简单、更快速的替代方法,使用 .ForEach()
array method:
$property = ('AAA', 'BBB', 'CCC').ForEach({
@{ name = $_; expression = { 10 } }
})
1..5 | select -Property $property
与管道不同,.ForEach()
方法不将$_
包装在[psobject]
,因此不会出现问题,也不需要解决方法。
使用该方法也更快,但请注意,与管道不同,它必须预先将所有输入收集到内存中(数组文字显然不是问题) .