Paolo Tedesco
Paolo Tedesco

Reputation: 57202

Format-List: sort properties by name

Is it possible to sort the output of the Format-List cmdlet by property name?
Suppose that I have an object $x with two properties "A" and "B", and when I run Format-List with it I get

(PS) > $x | Format-List
B : value b
A : value a

I would like to have

(PS) > $x | Format-List 
A : value a
B : value b

NOTE: I should have specified from the beginning that, unlike in the example with "A" and "B" properties, the real object I have to deal with has quite a lot of properties, and new ones could be added in the future, so I don't know all the property names in advance.

Upvotes: 15

Views: 29076

Answers (9)

Victor
Victor

Reputation: 19

I don't have enough reputation to comment, so I add my variation on the answer of Roman Kuzmin here.

I use disks in my example. Start with:

Get-Disk|Select-Object FriendlyName,SerialNumber
$CIMInstance=Get-Disk -SerialNumber A1B2C3D4E5
$DiskNumber=$CIMInstance.DiskNumber 

The following may look familiar

$Partition=Get-Partition -DiskNumber $DiskNumber      
foreach($P in $Partition){$P|Format-List -Property $($P|Get-Member -MemberType Property|Sort-Object Name).Name}

Now, use Select-Object to get all properties

$Partition=$(Get-Partition -DiskNumber $DiskNumber|Select-Object *) 
foreach($P in $Partition){$P|Format-List -Property $($P|Get-Member -MemberType NoteProperty|Sort-Object Name).Name}

The Select-Object puts obejcts of type Selected.Microsoft.Management.Infrastructure.CimInstance in $Partition. These objects have NoteProperties instead of Properties.

Upvotes: 0

DarkLite1
DarkLite1

Reputation: 14705

By using Select-Object with a calculated property (@{}) and then excluding it (-ExcludeProperty) you can also order the properties as you want. This works even when you don't know what's coming upfront.

@(
    [PSCustomObject]@{
        Color   = 'Green'
        Type    = 'Fruit'
        Name    = 'kiwi'
        Flavour = 'Sweet'
    }
) | Select-Object @{Name = 'Flavour'; Expression = { $_.Flavour } },
@{Name = 'Name'; Expression = { $_.Name } }, * -ExcludeProperty Name, Flavour |
Format-List

Output:

Flavour : Sweet
Name    : kiwi
Color   : Green
Type    : Fruit

Upvotes: 0

jimbobmcgee
jimbobmcgee

Reputation: 1721

Nothing wrong with the accepted answer, but a really quick-and-dirty option for a one-off—that doesn't require having the collection already in a variable—might be...

... | Format-List | Out-String -Stream | Sort-Object

...which does a sort on each line of the output of Format-List.

Note that any property values that go onto the next line will be broken (and probably appear at the top of the output), but this could be fixed by the slightly-less-memorable...

... | Format-List | Out-String -Stream -Width ([Int32]::MaxValue) | Sort-Object

...at the expense of column indentation.

Of course, all object/pipeline info is lost by that Out-String call, although—considering the same is true of Format-List—you probably aren't going to care by that point.

Upvotes: 15

John Anson
John Anson

Reputation: 131

Expanding on Christopher's idea, using get-member and format-list -Property:

$x | fl -property ($x| gm | sort name).name

Upvotes: 6

George Howarth
George Howarth

Reputation: 2903

This seems to work OK (edited so it accepts pipeline input):

function Format-SortedList
{
    param (
        [Parameter(ValueFromPipeline = $true)]
        [Object]$InputObject,
        [Parameter(Mandatory = $false)]
        [Switch]$Descending
    )

    process
    {
        $properties = $InputObject | Get-Member -MemberType Properties

        if ($Descending) {
            $properties = $properties | Sort-Object -Property Name -Descending
        }

        $longestName = 0
        $longestValue = 0

        $properties | ForEach-Object {
            if ($_.Name.Length -gt $longestName) {
                $longestName = $_.Name.Length
            }

            if ($InputObject."$($_.Name)".ToString().Length -gt $longestValue) {
                $longestValue = $InputObject."$($_.Name)".ToString().Length * -1
            }
        }

        Write-Host ([Environment]::NewLine)

        $properties | ForEach-Object { 
            Write-Host ("{0,$longestName} : {1,$longestValue}" -f $_.Name, $InputObject."$($_.Name)".ToString())
        }
    }
}

$Host, $MyInvocation | Format-SortedList
$Host, $MyInvocation | Format-SortedList -Descending

Upvotes: 1

Roman Kuzmin
Roman Kuzmin

Reputation: 42033

AFAIK, Format-List does not provide such an option.

For your particular example this should work:

$x | Select-Object A, B | Format-List

If the property set is not fixed/known then the procedure will be more tricky with use of Get-Member and some preprocessing making sorted parameter array for Select-Object.

EDIT:

Here it is (let's use $host instead of $x):

$host | Select-Object ([string[]]($host | Get-Member -MemberType Property | %{ $_.Name } | Sort-Object)) | Format-List

Christopher is right, Select-Object is not absolutely needed:

$host | Format-List ([string[]]($host | Get-Member -MemberType Property | %{ $_.Name } | Sort-Object))

Upvotes: 14

Keith Hill
Keith Hill

Reputation: 201682

The closest I can think of is to create a new psobject based off the old one but with the properties sorted e.g.:

$x | %{$obj = new-object psobject; `
       $_.psobject.properties | Sort Name | `
           %{Add-Member -Inp $obj NoteProperty $_.Name $_.Value}; $obj} | fl

You could get fancier and give the new psobject a typename that matches the old one, etc.

Upvotes: 4

Christopher
Christopher

Reputation: 412

If you are dealing with a small number of properties, you can specify their order with the -Property parameter.

Here is an example:

Format-List -Property Owner, Path

If you have a lot of properties, I am not sure there is any easy way to sort them in Format-List, like Roman said.

Upvotes: 1

Guy Thomas
Guy Thomas

Reputation: 933

I feel sure that you can achieve the desired output. I suggest that you experiment with both Sort-Object (or plain Sort) and also Group-Object (plain Group)

My idea is to place the sort, or group before | format-list

Thus $x | sort-object -property xyz | Format-List

Upvotes: 0

Related Questions