在 PowerShell 中导出到 CSV 时如何指定列顺序?

How can I specify the column ordering when exporting to CSV in PowerShell?

我正在 PowerShell 中编写一个脚本,用于从 Active Directory 导出所有安全组及其成员。现在我想格式化 CSV 文件的输出。

代码:

$Groups = Get-ADGroup -Properties * -Filter * -SearchBase "OU=SERVICES,DC=XXXXXX,DC=XXXXX" 

$Table = @()

$Record = @{
    "Group Name" = ""
    "Name" = ""
    "Username" = ""
}

Foreach($G In $Groups)
{
    $Arrayofmembers = Get-ADGroupMember -identity $G -recursive | select name,samaccountname
    Foreach ($Member in $Arrayofmembers) 
    {
        $Record."Group Name" = $G.Name
        $Record."Name" = $Member.name
        $Record."UserName" = $Member.samaccountname
        $objRecord = New-Object PSObject -property $Record
        $Table += $objrecord
    }
}

$Table | export-csv "C:\temp\SecurityGroups.csv" -NoTypeInformation

结果:

"Username","Name","Group Name"
"aman","Ani Manoukian","Commercial"
"adan","Aurelia Danneels","Commercial"
"kdeb","Kathleen De Backer","Commercial"
"TVGR","Thijs Van Grimbergen","Commercial"
"SVDE","Sofie Van den Eynde","Commercial"

现在我希望按以下顺序格式化输出:

"Group Name","Name","Username"

而不是: "Username","Name","Group Name"

这应该有效...

$Table |
  Select-Object "Group Name", "Name", "Username" |
  Export-Csv "C:\temp\SecurityGroups.csv" -NoTypeInformation

是一种 务实的 解决方案,可确保列以所需的顺序出现,因为您将 属性 名称传递给 Select-Object 是将属性添加到生成的 [pscustomobject] 个实例的顺序。

但是,效率低下,因为$Record定义时可以确保所需的列顺序,不需要额外的管道阶段来有效地复制结果对象:

$Record定义为有序哈希表如下(需要PSv3+ ):

$Record = [ordered] @{
    "Group Name" = ""
    "Name" = ""
    "Username" = ""
}

这保证 [pscustomobject] 稍后由 New-Object PSObject -property $Record 调用创建的实例包含与 $Record 中定义的键相同顺序的属性。

两个旁白:

  • New-Object PSObject -property $Record 可以简化为 [pscustomobject] $Record
  • 使用 [System.Collections.ArrayList] 实例可以更有效地处理递增构建大型数组,您可以使用 .Add() 添加元素,而不是使用 PowerShell 的 built-in 数组和 += ,每次都会创建数组的副本。更好的办法是让 PowerShell 为您创建数组,只需将 foreach 循环的输出捕获到一个变量中即可($Table = foreach ... - 请参阅

补充信息:

问题的根源在于常规哈希表([hashtable] 个实例)以有效不可预测 顺序 枚举它们的键(顺序是一个实现细节,不能保证),并且当您从哈希表创建 [pscustomobject] 时,不可预测的键顺序会反映在结果对象属性的顺序中.

相比之下,在 PSv3+ 中,您可以 创建一个 ordered 哈希表 通过放置 [ordered] 关键字 在哈希表文字之前,这导致 [System.Collections.Specialized.OrderedDictionary] 实例,其 键是基于排序的按照添加.
的顺序 从有序哈希表创建 [pscustomobject] 实例,然后在生成的对象的属性中保留该键排序。

请注意,PowerShell v3+ 提供了一个方便的快捷方式,用于使用 cast 从哈希表创建 [pscustomobject] 实例;例如:

PS> [pscustomobject] @{ a = 1; b = 2; c = 3 } # key order is PRESERVED

a b c
- - -
1 2 3

请注意 key-definition 命令 是如何保存的,即使 [ordered] 未指定。
换句话说:当您将哈希表文字 直接 转换为 [pscustomobject] 时,[ordered] 隐含的 ,所以上面等价于:

[pscustomobject] [ordered] @{ a = 1; b = 2; c = 3 }  # [ordered] is optional

警告:当哈希表文字是[=66时,这种隐式排序适用=]直接转换为[pscustomboject],因此key/property顺序保留在以下变体中:

New-Object PSCustomObject -Property @{ a = 1; b = 2; c = 3 } # !! order NOT preserved

$ht = @{ a = 1; b = 2; c = 3 }; [pscustomobject] $ht # !! order NOT preserved

[pscustomobject] (@{ a = 1; b = 2; c = 3 }) # !! order NOT preserved, due to (...)

因此,当不将哈希表文字 直接 转换为 [pscustomobject] 时,请使用 [ordered] 显式定义它。