powershell - select cmdlet 不接受计算属性中生成的字符串名称

标签 powershell select-object

我想生成下表:

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

但是我收到以下错误,指出名称不是字符串:

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

问题是:$_ 已经是一个字符串。为什么我必须再次将其转换为字符串?为什么 select 认为 namePSObject

为了确认它已经是一个字符串,我编写了以下代码来打印name的类型:

$property = @('AAA', 'BBB', 'CCC') | foreach {
    @{ name = $_; expression = { 10 } }
}
$property | foreach { $_.name.GetType() }

以下结果确认它已经是一个字符串:

IsPublic IsSerial Name                                     BaseType            
-------- -------- ----                                     --------            
True     True     String                                   System.Object       
True     True     String                                   System.Object       
True     True     String                                   System.Object       

我知道还有许多其他更简单的方法来生成表格。但我想了解为什么我必须将 string 转换为 string 才能使代码正常工作,以及为什么 select 不认为字符串是一个字符串。就其值(value)而言,我的 $PSVersionTable.PSVersion 是:

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      18362  1474    

最佳答案

您会看到 PowerShell 在幕后使用的偶然的、通常不可见[psobject]包装器带来的不幸影响。

在您的情况下,由于输入字符串是通过管道提供的,因此它们会被包装并存储为哈希表中的[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] 实例毫无意义,它始终 $true(自定义对象位于Essential [psobject] 实例,没有 .NET 基础对象 - 它们仅具有动态属性)。

通常不可见的 [psobject] 包装器在特定情况下,模糊地导致行为差异,这可以说是一个错误,并且是GitHub issue #5579


更简单、更快的替代方案,使用 .ForEach() array method :

$property = ('AAA', 'BBB', 'CCC').ForEach({
  @{ name = $_; expression = { 10 } }
})
1..5 | select -Property $property

与管道不同,.ForEach() 方法不会将 $_ 包装在[psobject],因此不会出现问题,也不需要解决方法。

使用该方法也更快,但请注意,与管道不同,它必须预先收集内存中的所有输入(显然这不是数组文字的问题)。

关于powershell - select cmdlet 不接受计算属性中生成的字符串名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67843055/

相关文章:

linux - Azure Add-AzureProvisioningConfig ssh key 或 key 对上传

Powershell 选择语句

powershell - 选择对象 - 首先影响管道中的先前 cmdlet

json - 从成功的 Invoke-RestMethod 中选择对象数据失败

Powershell 正则表达式不排除方括号

Powershell-更新属性 "departmentNumber"

powershell - 在PowerShell中选择带有变量的属性或参数

powershell - 使用 Select-Object 在非默认属性之间指定

powershell - 在Powershell中使用行来更改列

powershell - 如何使用 &$var 继续调用可执行文件时出现错误