将哈希表值 属性 导出到 CSV 文件
Export a hashtable-valued property to a CSV file
我是 运行 Test-AdfsServerHealth
(Ref.)
问题是,其中一个输出值(值名称 Output
)是一个显示为 System.Collection.Hashtable
的数组,我正试图找到一种方法使它整洁Excel格式。
例如,这是我导出时 CSV 上的实际值之一:
Name Result Detail Output
TestServiceAccountProperties Pass "" System.Collections.Hashtable
但 PowerShell 显示:
Name : TestServiceAccountProperties
Result : Pass
Detail :
Output : {AdfsServiceAccount, AdfsServiceAccountDisabled, AdfsServiceAccountLockedOut,
AdfsServiceAccountPwdExpired...}
ExceptionMessage :
我运行的实际命令是:
$ServerResult = Test-AdfsServerHealth
这不会很困难,只是会很烦人。你得到 "System.collections.hashtable" 的原因是因为无法以这样的单一格式显示 属性 中的所有内容,所以有很多信息。您将不得不创建另一个对象并在其中放入您想要的任何信息。
这个概率不会像你想要的那样工作,但通过一些调整它应该让你到达那里。
$ServerResult = Test-ADFSServerHealth
$Object = New-PSObject -Property @{
'Name' = $ServerResult.name
'Result' = $ServerResult.Result
'Detail' = $ServerResult.Detail
'Output' = ($ServerResult.Output | out-string -stream)
'ExceptionMessage' = $ServerResult.ExceptionMessage
}
如果您感兴趣,这里是我用来找到这个答案的资源。
Converting hashtable to array of strings
https://devops-collective-inc.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/new-object_psobject_vs_pscustomobject.html
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
哈希表的条目序列化为 single-line 字符串,该字符串由 space-separated <key>=<value>
对(PSv4+ 语法)组成,在 CSV 输出中应该可以很好地工作。
由于 CSV 是一种 文本 格式,PowerShell 通过调用 .ToString()
方法.
诸如 [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
属性 中具有相同的哈希表结构,您可以尝试 展平 哈希表通过将其条目列在自己的权利中,但听起来并非如此。
因此,您必须手动将哈希表转换为适合单个 CSV 列的文本表示形式:
您可以使用 Select-Object
和 计算的 属性 执行此转换,但您需要确定一种文本表示形式在 CSV 文件的上下文中有意义。
在下面的示例中,创建了一个由 space-separated <key>=<value>
对组成的 single-line 字符串(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
有关创建计算的 prop2
属性 的哈希表格式的说明,请参阅我的 。
以上结果:
"prop1","prop2"
"1","ID=666 name=foo"
但是请注意,如果哈希表中的值再次是仅序列化为其类型名称的复杂对象,则您必须递归地应用该方法。
可选阅读:将哈希表属性展平为单独的列
如果要导出到 CSV 文件的对象的 hashtable-valued 属性都具有 相同的结构,您可以选择 制作哈希表每个条目都有自己的输出列。
让我们采用以下示例输入:2 个自定义对象的集合,其 .prop2
值是具有一组统一键(条目)的哈希表:
$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
和 ID
:
"prop1","name","ID"
"1","foo1","666"
"2","foo2","667"
需要更高级的技术如果您不知道预先知道键名:
# 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
这会产生与上一个命令相同的输出,其中包含固定的计算属性列表。
我是 运行 Test-AdfsServerHealth
(Ref.)
问题是,其中一个输出值(值名称 Output
)是一个显示为 System.Collection.Hashtable
的数组,我正试图找到一种方法使它整洁Excel格式。
例如,这是我导出时 CSV 上的实际值之一:
Name Result Detail Output TestServiceAccountProperties Pass "" System.Collections.Hashtable
但 PowerShell 显示:
Name : TestServiceAccountProperties Result : Pass Detail : Output : {AdfsServiceAccount, AdfsServiceAccountDisabled, AdfsServiceAccountLockedOut, AdfsServiceAccountPwdExpired...} ExceptionMessage :
我运行的实际命令是:
$ServerResult = Test-AdfsServerHealth
这不会很困难,只是会很烦人。你得到 "System.collections.hashtable" 的原因是因为无法以这样的单一格式显示 属性 中的所有内容,所以有很多信息。您将不得不创建另一个对象并在其中放入您想要的任何信息。
这个概率不会像你想要的那样工作,但通过一些调整它应该让你到达那里。
$ServerResult = Test-ADFSServerHealth
$Object = New-PSObject -Property @{
'Name' = $ServerResult.name
'Result' = $ServerResult.Result
'Detail' = $ServerResult.Detail
'Output' = ($ServerResult.Output | out-string -stream)
'ExceptionMessage' = $ServerResult.ExceptionMessage
}
如果您感兴趣,这里是我用来找到这个答案的资源。
Converting hashtable to array of strings
https://devops-collective-inc.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/new-object_psobject_vs_pscustomobject.html
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
哈希表的条目序列化为 single-line 字符串,该字符串由 space-separated <key>=<value>
对(PSv4+ 语法)组成,在 CSV 输出中应该可以很好地工作。
由于 CSV 是一种 文本 格式,PowerShell 通过调用 .ToString()
方法.
诸如 [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
属性 中具有相同的哈希表结构,您可以尝试 展平 哈希表通过将其条目列在自己的权利中,但听起来并非如此。
因此,您必须手动将哈希表转换为适合单个 CSV 列的文本表示形式:
您可以使用 Select-Object
和 计算的 属性 执行此转换,但您需要确定一种文本表示形式在 CSV 文件的上下文中有意义。
在下面的示例中,创建了一个由 space-separated <key>=<value>
对组成的 single-line 字符串(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
有关创建计算的 prop2
属性 的哈希表格式的说明,请参阅我的
以上结果:
"prop1","prop2"
"1","ID=666 name=foo"
但是请注意,如果哈希表中的值再次是仅序列化为其类型名称的复杂对象,则您必须递归地应用该方法。
可选阅读:将哈希表属性展平为单独的列
如果要导出到 CSV 文件的对象的 hashtable-valued 属性都具有 相同的结构,您可以选择 制作哈希表每个条目都有自己的输出列。
让我们采用以下示例输入:2 个自定义对象的集合,其 .prop2
值是具有一组统一键(条目)的哈希表:
$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
和 ID
:
"prop1","name","ID"
"1","foo1","666"
"2","foo2","667"
需要更高级的技术如果您不知道预先知道键名:
# 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
这会产生与上一个命令相同的输出,其中包含固定的计算属性列表。