如何创建输出列表的对象(不是表)

时间:2016-10-31 00:22:54

标签: list powershell object

这是另一个问题的衍生产品,位于此处: Formatting an Object as a neatly looking list 我认为,论证的基础是错误的,因为我们之后并没有处理对象的格式化。这仅适用于控制台显示的外观,但在操作包含对象的变量时,它可能会影响对象的完整性。

我需要的是创建一个固有输出列表(而不是表)的对象。我知道这是可能的,因为我已经测试了许多我没有写过的功能,而且创建的对象实际上是列表。无需使用Format-List来扭曲或塑造已存在的内容。我只是无法弄清楚为什么有时输出是列表或表。我不确定魔法在哪里。但是我知道当我在运行包含创建对象的变量之前运行$Host时,我得到了Host生成的对象,这是一个列表,然后将对象整形为一个列表,通常会显示为一张桌子。当然,这可能会给出我想要的结果,但我并不希望显示主机信息。那么解决方案是什么,我希望有人可以解释一下。

1 个答案:

答案 0 :(得分:8)

PowerShell在向用户显示数据/对象时会执行一些默认格式设置。通常,当对象具有最多4个属性时,它们以表格形式显示;如果对象具有4个以上的属性,则以列表形式显示。

如果连续输出多个内容,PowerShell会将第一个对象的格式(列表/表)应用于所有后续对象。我不知道这种行为背后的确切原因,但可能是为了使输出更加一致。

<强>演示:

PS C:\> $o1 = New-Object -Type PSObject -Property @{a=1;b=2;c=3;d=4;e=5}
PS C:\> $o2 = New-Object -Type PSObject -Property @{x='foo';y='bar'}
PS C:\> $o1

c : 3
e : 5
d : 4
b : 2
a : 1

PS C:\> $o2

y                                    x
-                                    -
bar                                  foo

PS C:\> $o1; $o2

c : 3
e : 5
d : 4
b : 2
a : 1

y : bar
x : foo

但请注意,如果以错误的顺序输出对象,依赖此行为可能会导致意外结果:

PS C:\> $o2; $o1

y                                    x
-                                    -
bar                                  foo         # ← properties of $o2
                                                 # ← empty line for $o1!

$o1在上面的输出中显示为空行,因为输出$o2首先使用列yx建立表格输出格式,但$o1没有这些属性。缺少的属性在表格输出中显示为空值,而输出中省略了其他属性。在某些情况下,您可能会以列表形式从第二个对象/列表中获取输出(在PowerShell控制台中运行实例Get-Process; Get-ChildItem)。

您可以强制将后续对象或对象数组显示为单独的表(或列表),方法是将它们通过Format-Table(或Format-List)cmdlet进行管道处理:

PS C:\> $o2; $o1 | Format-Table

y                                    x
-                                    -
bar                                  foo


              c            e            d            b            a
              -            -            -            -            -
              3            5            4            2            1

您还可以强制PowerShell通过管道传递(例如)Out-Default来单独显示每个变量:

PS C:\> $o2 | Out-Default; $o1 | Out-Default

y   x
-   -
bar foo

c : 3
e : 5
d : 4
b : 2
a : 1

但请注意,这会写入控制台,因此无法再捕获,重定向或流水线化生成的输出。仅在您想要向用户显示内容时使用此选项。

有关PowerShell输出格式see here的其他信息。

有很多方法可以改变对象显示方式的默认行为,但不幸的是,它们并不简单。首先,您可以定义default display property set以使PowerShell不显示所有属性,而只显示特定子集。

PS C:\> $props = 'c', 'd'
PS C:\> $default = New-Object Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$props)
PS C:\> $members = [Management.Automation.PSMemberInfo[]]@($default)
PS C:\> $o1 | Add-Member MemberSet PSStandardMembers $members
PS C:\> $o1

                c                    d
                -                    -
                3                    4

您仍然可以使用Format-List *

显示所有显示的属性
PS C:\> $o1 | Format-List *

c : 3
e : 5
d : 4
b : 2
a : 1

定义默认显示属性集并不允许您定义输出格式。要做到这一点,您可能需要编写自定义formatting file。为此,您可能还需要为对象定义custom type

$formatFile = "$HOME\Documents\WindowsPowerShell\Your.Format.ps1xml"
$typeFile   = "$HOME\Documents\WindowsPowerShell\Your.Type.ps1xml"

@'
<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
  <ViewDefinitions>
    <View>
      <Name>Default</Name>
      <ViewSelectedBy>
        <TypeName>Foo.Bar</TypeName>
      </ViewSelectedBy>
      <ListControl>
        ...
      </ListControl>
    </View>
  </ViewDefinitions>
</Configuration>
'@ | Set-Content $formatFile
Update-FormatData -AppendPath $formatFile

@'
<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>Foo.Bar</Name>
    <Members>
      ...
    </Members>
  </Type>
</Types>
'@ | Set-Content $typeFile
Update-TypeData -AppendPath $typeFile

$o2.PSTypeNames.Insert(0, 'Foo.Bar')
杰弗里希克斯写了一篇你可能想要阅读的article series on the subject

尽管如此,除非你非常有充分理由这样做,否则我不建议你去这条路线。我之前尝试过解释,但是@TesselatingHeckler比我更简洁,所以我要引用他的话:

  

PowerShell不是bash,它具有内容和表示的分离,就像HTML和CSS一样。

您通常希望在PowerShell中执行的操作是将数据保存在对象中,并使这些对象的属性包含&#34; raw&#34; (即未格式化的)数据。这为您提供了处理数据的最大灵活性。格式化数据通常只会妨碍您,因为它会强制您再次解析/转换数据。仅在需要将数据显示给用户时格式化数据,并使用Format-* cmdlet执行此操作。如果您的输出是用于进一步处理:首先不要打扰它的格式。将它留给用户如何显示数据。