Column ordering when exporting to CSV in PowerShell - controlling the property enumeration order of custom objects created from hashtables

◇◆丶佛笑我妖孽 提交于 2019-11-30 01:50:41

问题


I'm writing a script in Powershell that exports all securitygroups and their members from Active Directory. Now I want to format the output of the .csv.

The Code:

$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

The Result:

"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"

Now I want the output formatted as:

"Group Name","Name","Username" instead of "Username","Name","Group Name"

Can anyone help me please?

Thanks in advance.


回答1:


This should work...

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



回答2:


gvee's helpful answer is a pragmatic solution that ensures that the columns appear in the desired order, because the order in which you pass property names to Select-Object is the order in which the properties are added to the resulting [pscustomobject] instances.

It is, however, inefficient, because the desired column order can be ensured at the time $Record is defined, without needing an additional pipeline stage that effectively duplicates the result objects:

Define $Record as an ordered hashtable as follows (requires PSv3+):

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

This guarantees that the [pscustomobject] instances later created by the New-Object PSObject -property $Record calls contain properties in the same order as the keys were defined in $Record.

Two asides:
* New-Object PSObject -property $Record could be simplified to [pscustomobject] $Record
* Building up a large array incrementally is more efficiently handled with a [System.Collections.ArrayList] instance to which you add elements with .Add() rather than using PowerShell's built-in arrays with +=, which creates a copy of the array every time. Even better is to et PowerShell create the array for you, simply by capturing the output from your foreach loop in a variable ($Table = foreach ... - see this answer)


Supplemental information:

The source of the problem is that regular hashtables ([hashtable] instances) enumerate their keys in an effectively random order (the order is an implementation detail), and when you create a [pscustomobject] from a hashtable, that unpredictable key ordering is reflected in the ordering of the resulting object's properties.

By contrast, in PSv3+ you can create an ordered hashtable by placing the [ordered] keyword before a hashtable literal, which results in a [System.Collections.Specialized.OrderedDictionary] instance whose keys are ordered based on the order in which they were added.
Creating a [pscustomobject] instance from an ordered hashtable then preserves that key ordering in the resulting object's properties.

Note that PowerShell v3+ offers a convenient shortcut for creating a [pscustomobject] instance from a hashtable using a cast; e.g.:

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

a b c
- - -
1 2 3

Note how the key-definition order was preserved, even though [ordered] was not specified.
In other words: When you cast a hashtable literal directly to [pscustomobject], [ordered] is implied, so the above is equivalent to:

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

Caveat: This implicit ordering only applies when a hashtable literal is directly cast to [pscustomboject], so the key/property order is not preserved in the following variations:

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 (...)

Therefore, when not casting a hashtable literal directly to [pscustomobject], define it with [ordered] explicitly.



来源:https://stackoverflow.com/questions/42090900/column-ordering-when-exporting-to-csv-in-powershell-controlling-the-property-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!