Powershell:将哈希表值属性导出为CSV文件

时间:2018-03-14 11:20:51

标签: powershell csv hashtable

我正在运行Test-AdfsServerHealthRef.

问题是,其中一个输出值(值名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

2 个答案:

答案 0 :(得分:3)

<强> TL;博士

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输出中运行得相当好。

由于 CSV是文本格式 PowerShell通过调用.ToString()方法来序列化要导出的对象。

[hashtable]个实例等复杂对象通常只生成System.Collections.Hashtable的完整类型名称(.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文件的上下文中有意义的文本表示

在以下示例中,创建了由空格分隔的<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

有关创建计算prop2属性的哈希表格式的说明,请参阅我的this answer

以上产量:

"prop1","prop2"
"1","ID=666 name=foo"

但是,请注意,如果哈希表中的值又是仅序列化为其类型名称的复杂对象,则必须以递归方式应用方法。

可选读取:将哈希表属性展平为单个列

如果要导出到CSV文件的对象的哈希表值属性都具有相同的结构,则可以选择使哈希表条目各自成为自己的输出列。

让我们采用以下示例输入: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

以上显示以下内容,显示哈希表条目成为他们自己的列nameID

"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

这产生与上一个命令相同的输出和固定的计算属性列表。

答案 1 :(得分:1)

这不会非常困难,只会令人讨厌。您获得“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