【问题标题】:How do you export objects with a varying amount of properties?如何导出具有不同数量属性的对象?
【发布时间】:2013-01-09 03:42:48
【问题描述】:

警告 - 我过去曾询问过 similar question,但这次略有不同。

tl;博士;我想导出具有不同数量属性的对象。例如;对象 1 可能有 3 个 IP 地址和 2 个 NIC,但对象 2 有 7 个 IP 地址和 4 个 NIC(但不限于此数量 - 它可能是 N 个属性)。

我可以愉快地捕获和构建包含我需要的所有信息的对象。如果我只是将数组输出到控制台,每个对象都会显示其所有属性。如果我想 out-file 或 export-csv 我开始遇到标题周围的问题。

之前JPBlanc 建议根据属性的数量对对象进行排序 - 即,具有最多属性的对象将排在第一位,因此将输出最多属性的标题。

假设我已经构建了一个服务器对象,该对象具有基于 IP 地址和 NIC 卡的不同属性。例如;

ServerName: Mordor
IP1: 10.0.0.1
IP2: 10.0.0.2
NIC1: VMXNET
NIC2: Broadcom

ServerName: Rivendell
IP1: 10.1.1.1
IP2: 10.1.1.2
IP3: 10.1.1.3
IP4: 10.1.1.4
NIC1: VMXNET

最初,如果您要 export-csv 一个包含这些对象的数组,则标头将建立在第一个对象(也就是您只会获得 ServerName、IP1、IP2、NIC1 和 NIC2)的基础上,这意味着您将丢失任何后续 IP(例如 IP3 和 IP4)。为了纠正这个问题,在导出之前,我根据 IP 属性的数量进行排序 - tada - 现在第一个对象在数组中拥有最多的 IP,因此后续对象的 IP 都不会丢失。

缺点是当您拥有第二个可变属性时 - 例如 NIC。一旦我的排序基于 IP 完成,我们就会有标题 ServerName、IP1 - IP4 和 NIC1。这意味着 NIC2 的后续对象属性丢失。

是否有一种可扩展的方式来确保在导出此类对象时不会丢失数据?

【问题讨论】:

  • 我很幸运能与 Jeffrey Snover 交谈,他确认 Export-Csv 在这种情况下无法工作。 Jeffrey 的建议是转向 Export-CliXML 并基于此输出构建报告。叹息。
  • 你试过我的更新答案了吗?

标签: powershell


【解决方案1】:

试试:

$o1 = New-Object psobject -Property @{
ServerName="Mordor"
IP1="10.0.0.1"
IP2="10.0.0.2"
NIC1="VMXNET"
NIC2="Broadcom"
}

$o2 = New-Object psobject -Property @{
ServerName="Rivendell"
IP1="10.1.1.1"
IP2="10.1.1.2"
IP3="10.1.1.3"
IP4="10.1.1.4"
NIC1="VMXNET"
}

$arr = @()
$arr += $o1
$arr += $o2

#Creating output
$prop = $arr | % { Get-Member -InputObject $_ -MemberType NoteProperty | Select -ExpandProperty Name } | Select -Unique | Sort-Object
$headers = @("ServerName")
$headers += $prop -notlike "ServerName"

$arr | ft -Property $headers    

输出:

ServerName IP1      IP2      IP3      IP4      NIC1   NIC2    
---------- ---      ---      ---      ---      ----   ----    
Mordor     10.0.0.1 10.0.0.2                   VMXNET Broadcom
Rivendell  10.1.1.1 10.1.1.2 10.1.1.3 10.1.1.4 VMXNET         

如果您知道类型(NICS、IPS..),但不知道计数(例如多少 NICS),您可以尝试:

#Creating output
$headers = $arr | % { Get-Member -InputObject $_ -MemberType NoteProperty | Select -ExpandProperty Name } | Select -Unique
$ipcount = ($headers -like "IP*").Count
$niccount = ($headers -like "NIC*").Count

$format = @("ServerName")
for ($i = 1; $i -le $ipcount; $i++) { $format += "IP$i" }
for ($i = 1; $i -le $niccount; $i++) { $format += "NIC$i" }

$arr | ft -Property $format

【讨论】:

  • 遗憾的是,我们的目标是获得易于阅读的报告,因此列表格式并不理想。
  • 尽我所能修复它。我认为更多的操作需要在 excel 中选择、剪切和粘贴 :) 第一种方法按字母顺序对属性进行排序并将服务器名称添加为第一列。第二个是如果您知道所有类型的属性(在本例中为 IP* 和 NIC*)
  • 这看起来不错 - 进入 export-csv 我已将您的 ft 更改为简单的 select $headers。我更喜欢您的第一种方法,因为我更喜欢不需要我知道所有属性等的模块化方法。谢谢!现在在第二种情况下进行测试。
【解决方案2】:

如何获取所有唯一属性标题的列表,然后对所有对象进行选择?当您在对象上选择不存在的属性时,它将创建一个空白。

$allHeaders = $arrayOfObjects | % { Get-Member -inputobject $_ -membertype noteproperty | Select -expand Name } | Select -unique
$arrayOfObjects | Select $allHeaders

当然,您正在遍历所有对象以获取标头,因此对于大量对象可能需要一段时间。

【讨论】:

  • 这可能有效。我今天就试一试,看看它是否合理。
【解决方案3】:

这是我的解决方案尝试。我现在很累,所以希望这是有道理的。基本上我正在计算最大数量的 NIC 和 IP 注释属性,创建一个具有这些属性数量的占位符对象,将其添加为 CSV 中的第一项,然后将其从 CSV 中删除。

# Create example objects
$o1 = New-Object psobject -Property @{
  ServerName="Mordor"
  IP1="10.0.0.1"
  IP2="10.0.0.2"
  NIC1="VMXNET"
  NIC2="Broadcom"
}

$o2 = New-Object psobject -Property @{
  ServerName="Rivendell"
  IP1="10.1.1.1"
  IP2="10.1.1.2"
  IP3="10.1.1.3"
  IP4="10.1.1.4"
  NIC1="VMXNET"
}

# Add to an array
$servers = @($o1, $o2)

# Calculate how many IP and NIC properties there are
$IPColSize = ($servers | Select IP* | %{($_ | gm -MemberType NoteProperty).Count} | Sort-Object -Descending)[0]
$NICColSize = ($servers | Select NIC* | %{($_ | gm -MemberType NoteProperty).Count} | Sort-Object -Descending)[0]

# Build a place holder object that will contain enough properties to cover all of the objects in the array.
$cmd = '$placeholder = "" | Select ServerName, {0}, {1}' -f (@(1..$IPColSize | %{"IP$_"}) -join ", "), (@(1..$NICColSize | %{"NIC$_"}) -join ", ")
Invoke-Expression $cmd

# Convert to CSV and remove the placeholder
$csv = $placeholder,$servers | %{$_ | Select *} | ConvertTo-Csv -NoTypeInformation
$csv | Select -First 1 -Last ($csv.Count-2) | ConvertFrom-Csv | Export-Csv Solution.csv -NoTypeInformation

【讨论】:

  • 是的,当您知道您的房产数量时,这是一个好方法。可悲的是,它并不是真正可扩展的,而且在多个脚本中部署和使用并不容易。理想情况下,我正在寻找一些不需要基于属性进行计数或计算的神奇方法。
猜你喜欢
  • 2017-09-07
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多