将哈希表值属性导出到 CSV 文件



我正在运行Test-AdfsServerHealth(参考)

问题是,其中一个输出值(值名称Output)是一个显示为System.Collection.Hashtable的数组,我正在尝试找到一种方法以整洁的Excel格式获取它。

例如,这是我导出时 CSV 上的实际值之一:

名称结果详细信息输出 TestServiceAccountProperties Pass " System.Collections.Hashtable

但 PowerShell 显示:

名称 : 测试服务帐户属性 结果 : 通过 细节: 输出 : {AdfsServiceAccount, AdfsServiceAccountDisabled, AdfsServiceAccountLockedOut,  AdfsServiceAccountPwdExpired...} 异常消息

:我正在运行的实际命令是:

$ServerResult = Test-AdfsServerHealth

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属性的哈希表格式的说明,请参阅我的这个答案。

以上结果:

"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

这将生成与具有固定计算属性列表的上一个命令相同的输出。

这不会很困难,只是做起来很烦人。您获得"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
}

如果您有兴趣,以下是我用来找到此答案的资源。
将哈希表转换为字符串
数组 https://devops-collective-inc.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/new-object_psobject_vs_pscustomobject.html

最新更新