theshizy
theshizy

Reputation: 545

Change order of columns in the object

How can I change the column ordering of the output my code produces:

$apps = Import-CSV apps.csv
$computers = Import-CSV compobj.csv
foreach ($computer in $computers) {    
    $computerLob = $computer.lob
    $lobApps = $apps | ? {$_.lob -eq $computerLob }
    foreach ($app in $lobApps) {
        $computerHostname = $computer.hostname
        $appLocation = $app.location
        $installed=Test-Path "\\$computerHostname\$appLocation"      
        New-Object PSObject -Property @{
            Computer=$computer.hostname
            App=$app.appname
            Installed=$installed
        }
    }

Currently it's producing the columns in the following order: Installed,App,Computer.

I'd like to have it in the following order: Computer,App,Installed.

Upvotes: 13

Views: 38899

Answers (5)

jjacenty
jjacenty

Reputation: 1

A more universal way to change the order is using the Select-Object cmdlet with the list of properties in the required order.

See the example:

PS> $ObjectList = 1..3 | 
% {New-Object psobject -Property @{P2="Object $_ property P2"; P1="Object $_ property P1"}}
PS> $ObjectList

P2                   P1
--                   --
Object 1 property P2 Object 1 property P1
Object 2 property P2 Object 2 property P1
Object 3 property P2 Object 3 property P1


PS> $ObjectList | Select-Object P1,P2

P1                   P2
--                   --
Object 1 property P1 Object 1 property P2
Object 2 property P1 Object 2 property P2
Object 3 property P1 Object 3 property P2

The full form of these commands is the following:

$ObjectList = 1..3 | 
ForEach-Object -Process {New-Object -TypeName psobject -Property @{P2="Object $_ property P2"; P1="Object $_ property P1"}}
$ObjectList | Select-Object -Property P1,P2

Upvotes: 0

Emiliano Poggi
Emiliano Poggi

Reputation: 24816

Format-Table it's a good solution when you need to display your object fields in a specific order, but it will change the obect and you won't be able to pipe your object, for example when exporting to csv (Export-Csv).

In the case you just want to change "the order of the fields in the object" use Select-Object. This will preserve object type and fields, and still you will be able to pipe the object to other cmdlets.

Upvotes: 6

mjolinor
mjolinor

Reputation: 68243

Powershell V3 added a type accelerator for [PSCustomObject] that creates objects using an ordered hash table, so the properties stay in the order they're declared:

[PSCustomObject] @{
  Computer=$computer.hostname
  App=$app.appname
  Installed=$installed
}

Upvotes: 24

Keith Hill
Keith Hill

Reputation: 201602

If you want to ensure the output of an object occurs in a certain order i.e. formatted a certain way then use PowerShell's formatting commands.

$obj = [pscustomobject]@{Computer=$computer.hostname;App=$app.appname;Installed=$installed} 
$obj | Format-Table Computer,App,Installed

What's more you can better control the output e.g.:

$obj | Format-Table Computer,App,Installed -AutoSize

Or control field width & alignment:

$obj | Format-Table @{label='Computer';expression={$_.Computer};width=20;alignment='right'},App,Installed

Frankly I think it is a better practice to use the formatting commands to get the output order you want rather than to rely upon the order in which the properties are created.

Upvotes: 19

Adi Inbar
Adi Inbar

Reputation: 12323

The problem is that you're adding the properties using a hashtable, and hashtables don't preserve order. You can do one of two things:

1. Add the properties in a manner that will set the order (the last line is to output the object to the pipeline):

$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $computer.hostname
$obj | Add-Member -MemberType NoteProperty -Name App -Value $app.appname
$obj | Add-Member -MemberType NoteProperty -Name Installed -Value $installed
$obj

2. Determine the order at the time you output the object to the pipeline using Select-Object:

New-Object PSObject -Property @{
  Computer=$computer.hostname
  App=$app.appname
  Installed=$installed
} | select Computer,App,Installed

Which one is preferable depends on how much you'll be working with the object. If, as your question implies, you're only using the PSObject in order to display the information in tabular format, the second method is quicker. If you're going to output the object multiple times in different parts of the script, the first method allows you to simply output it as $obj rather than having to pipe to select every time.

Note also that the second method can be split up like this if you don't want to output the object immediately after populating it:

$obj = New-Object PSObject -Property @{
   Computer=$computer.hostname
    App=$app.appname
    Installed=$installed
} 

[...do other stuff...]

$obj | select Computer,App,Installed

Upvotes: 6

Related Questions