tl;dr:
Test-AdfsServerHealth |
Select-Object Name, Result, Detail, @{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ExportTo-Csv out.csv
上面对每一个进行了序列化.Output
哈希表的条目由空格分隔组成的单行字符串<key>=<value>
对(PSv4+ 语法)应该在 CSV 输出中工作得相当好。
Since CSV 是一个text format, PowerShell 通过调用对象来序列化要导出的对象.ToString()
method.
复杂的对象,例如[hashtable]
实例通常只产生它们的完整类型名称(System.Collections.Hashtable
) for .ToString()
,这在 CSV 中没有用。
一个简化的例子(我正在使用ConvertTo-Csv
,但该示例同样适用于Export-Csv
):
# Create a custom object whose .col2 property is a hashtable with 2
# sample entries and convert it to CSV
PS> [pscustomobject] @{ prop1 = 1; Output = @{ name='foo'; ID=666 } } | ConvertTo-Csv
"prop1","Output"
"1","System.Collections.Hashtable"
如果所有输出对象来自Test-AdfsServerHealth
它们具有相同的哈希表结构.Output
财产,你可以尝试flatten哈希表通过使其条目拥有自己的列来创建,但听起来情况并非如此。
因此你必须手动将哈希表转换为适合单个 CSV 列的文本表示形式:
你可以这样做Select-Object
and a 计算属性它为您执行转换,但您需要决定在 CSV 文件上下文中有意义的文本表示形式。
在以下示例中,由空格分隔的单行字符串<key>=<value>
创建对(PSv4+ 语法)。
[pscustomobject] @{ prop1 = 1; Output = @{ name='foo'; ID=666 } } |
Select-Object prop1, @{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ConvertTo-Csv
For an explanation of the hashtable format that creates the calculated prop2
property, see this answer of mine.
上面的结果是:
"prop1","prop2"
"1","ID=666 name=foo"
但请注意,如果哈希表中的值又是仅序列化为其类型名称的复杂对象,则必须应用该方法递归地.
可选阅读:将哈希表属性展平为单独的列
如果要导出到 CSV 文件的对象的哈希表值属性全部具有结构相同,您可以选择使哈希表条目每个都有自己的输出列。
让我们采用以下示例输入:2 个自定义对象的集合,其.prop2
value 是一个具有一组统一的键(条目)的哈希表:
$coll = [pscustomobject] @{ prop1 = 1; prop2 = @{ name='foo1'; ID=666 } },
[pscustomobject] @{ prop1 = 2; prop2 = @{ name='foo2'; ID=667 } }
如果您预先知道(感兴趣的)关键名称,您可以简单地使用计算属性的显式列表来创建各个列:
$coll | select prop1, @{ n='name'; e={ $_.prop2.name } }, @{ n='ID'; e={ $_.prop2.ID } } |
ConvertTo-Csv
上面的结果如下,显示哈希表条目变成了自己的列,name
and ID
:
"prop1","name","ID"
"1","foo1","666"
"2","foo2","667"
需要更先进的技术如果你这样做not预先知道按键名称:
# Create the list of calculated properties dynamically, from the 1st input
# object's .prop2 hashtable.
$propList = foreach ($key in $coll[0].prop2.Keys) {
# The script block for the calculated property must be created from a
# *string* in this case, so we can "bake" the key name into it.
@{ n=$key; e=[scriptblock]::Create("`$_.prop2.$key") }
}
$coll | Select-Object (, 'prop1' + $propList) | ConvertTo-Csv
这会产生与上一个命令相同的输出,并具有固定的计算属性列表。