【问题标题】:Dynamically generating columns when summarizing PowerShell objects to the console将 PowerShell 对象汇总到控制台时动态生成列
【发布时间】:2017-11-10 23:35:34
【问题描述】:

我有这个 PowerShell cmdlet,它返回零个或多个自定义对象;每个返回的对象都有一个 TypeIDStatus 属性,因此将 cmdlet 的输出发送到控制台会产生如下结果:

Type      ID      Status
----      --      ------
Foo       1       Active
Foo       3       Active
Baz       1       Inactive
Baz       2       Active
Baz       3       Broken
Bar       4       Active

使用 PowerShell 格式化文件,我尝试生成以下输出:

ID    Foo     Baz       Bar
--    ---     ---       ---
1     Active  Inactive  
2             Active
3     Active  Broken
4                       Active

这可能吗?按 ID 对项目进行分组似乎很简单,但我不知道如何为每个 Type 动态生成列?

请注意,我不能对 cmdlet 的输出类型进行任何更改,因为这会破坏我可能希望通过管道输出的其他 cmdlet - 这就是为什么我认为理想的解决方案应该只涉及格式化。

编辑 考虑这个问题的另一种方式可能是:“在处理完管道中的最后一项后,您可以使用 PowerShell 格式化文件打印一种页脚吗?”我猜这假设每个单独项目的处理可以以某种方式缓冲该项目,然后可以使用总结缓冲项目的脚本块构建页脚。

【问题讨论】:

  • 您需要使用group-object 来收集id,然后遍历每个组。您需要提前做的另一件事是收集所有类型,以便知道您正在制作多少个属性。您是否有任何尝试让它发挥作用?
  • 感谢您的回复,@Matt!我知道如何通过将输出传递到其他(内置)PowerShell cmdlet 来重塑我的数据来达到预期的结果 - 我认为这就是您所指的?这是否也可以从 inside PowerShell 格式化文件 (.Format.ps1xml) 以某种方式进行?重新表述我所追求的: MyCmdlet # 将 summarized (参见原始问题)输出发送到控制台; MyCmdlet | SomeOtherCmdlet # 与以前相同的旧对象沿管道发送
  • @JanHoek 不依赖“默认”输出来显示数据,如果您需要添加“虚拟”列,我相信 Select-Object 会在明确命名时做到这一点?跨度>
  • 我一定跳过了使用 PowerShell 格式化文件.. 我认为这不是 ps1xml 文件的用途,但我可能错了。我认为您在解释上迷失了我,但让我尝试改写一下。您是否只是说您不想更改原始数据,因为它需要作为另一个 cmdlet 的输入?您可以控制这些 cmdlet 吗?所以你可以将结果保存在一个变量中,并将按摩结果发送到控制台,并将原始结果发送到下一步?您也可以使用 tee-object 来实现这一点
  • @Matt 如有任何困惑,我们深表歉意! :-) 据我了解,格式化文件可用于从根本上改变输出的外观而不影响实际对象(例如,在 Get-ChildItem 的情况下)。也许你和 ConnorLSW 是对的,我应该简单地使用 Tee-Object 将对象存储在一个变量中并“按摩”这些(使用 Group-Object 等)以满足我的需要。再次感谢你们!

标签: powershell


【解决方案1】:

PowerShell 格式文件在这里无法为您提供帮助。例如,格式文件确定在您运行 Get-ChildItemGet-Process 时显示哪些字段及其顺序。您在这里所做的是动态转换。在 SQL 中,此操作称为 PIVOT。 PIVOT 通常是一种痛苦——动态 PIVOT 更是如此——因为它们从根本上转换数据。您将不得不手动完成。

也就是说,这并不难做到:

$Data = [PSCustomObject]@{Type = 'Foo'; ID = 1; Status = 'Active'  },
[PSCustomObject]@{Type = 'Foo'; ID = 3; Status = 'Active'  },
[PSCustomObject]@{Type = 'Baz'; ID = 1; Status = 'Inactive'},
[PSCustomObject]@{Type = 'Baz'; ID = 2; Status = 'Active'  },
[PSCustomObject]@{Type = 'Baz'; ID = 3; Status = 'Broken'  },
[PSCustomObject]@{Type = 'Bar'; ID = 4; Status = 'Active'  }

function Get-PivotedObject {
    param (
        [Parameter(Mandatory = $true)]
        $Data,
        [Parameter(Mandatory = $true)]
        [string]$Entity,
        [Parameter(Mandatory = $true)]
        [string]$Attribute,
        [Parameter(Mandatory = $true)]
        [string]$Value
    )

    $PivotHeaders = $Data | Select-Object -ExpandProperty $Attribute -Unique;

    $Data | Select-Object -ExpandProperty $Entity -Unique | ForEach-Object {
        $Record = [ordered]@{
            $Entity = $_;
        }
        foreach ($Header in $PivotHeaders) {
            $Record.$Header = $Data | Where-Object { 
                ($_.$Entity -eq $Record.$Entity) -and ($_.$Attribute -eq $Header)
            } | Select-Object -ExpandProperty $Value -First 1;
            # Notice this only returns the first value it finds for a given entity and attribute

        }

        [PSCustomObject]$Record;
    }
}

Get-PivotedObject -Data $Data -Entity 'ID' -Attribute 'Type' -Value 'Status'

【讨论】:

  • 太糟糕了,这种效果无法“本地”实现,但有一个很好的通用解决方法是件好事! :-)
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 2018-05-13
  • 1970-01-01
  • 2016-08-17
  • 2021-09-07
  • 2016-04-30
  • 2020-06-08
  • 1970-01-01
相关资源
最近更新 更多