Working with Sort-Object Cmdlet
In this blog I will try to explain different features of sort-object(Sort) cmdlet. For the purpose of this blog, I assume the following objects exist:
MSH C:\temp\monad> $a,$b,$c,$d
Score Name
----- ----
100 John
90 Henry
90 Tom
80 David
From the definition Sort looks like:
MSH C:\temp\monad> (get-command sort-object).Definition
sort-object [[-Property] Object[]] [-Descending] [-Unique] [-InputObject MshObj
ect] [-Culture String] [-CaseSensitive] [-Verbose] [-Debug] [-ErrorAction Actio
nPreference] [-ErrorVariable String] [-OutVariable String] [-OutBuffer Int32]
The basic usage looks like:
<expression> | sort <property>
Sort works on a collection of input objects possibly coming over from a pipeline. Sort will collect all the input objects from the pipeline and then sorts the objects based on other parameters like Property, Descending, Unique etc.
Example: To sort objects based on Score
MSH C:\temp\monad> $a,$b,$c,$d | sort score
Score Name
----- ----
80 David
90 Tom
90 Henry
100 John
Example: To sort objects based on Name
MSH C:\temp\monad> $a,$b,$c,$d | sort Name
Score Name
----- ----
80 David
90 Henry
100 John
90 Tom
Example: To sort objects in descending order based on Score
MSH C:\temp\monad> $a,$b,$c,$d | sort Score -Descending
Score Name
----- ----
100 John
90 Tom
90 Henry
80 David
Ok, this is all simple and you might yourself have already explored all this. Let us get into some tricky stuff. How to sort on Score (descending order) and Name (ascending order)
Example: sort on Score descending and then Name ascending
MSH C:\temp\monad> $a,$b,$c,$d | sort @{expression="Score";Descending=$true},@{e
xpression="Name";Ascending=$true}
Score Name
----- ----
100 John
90 Henry
90 Tom
80 David
Notice the use of @{expression=…}. If you notice the definition of sort-object, the parameter Property takes in a object[]. Property parameter can take entries of form <string> or hashtable (notice @). If the input is a hashtable, then Sort cmdlet specifically looks for “expression”,”ascending”,”descending” keys. Ascending and Descending can take only Booleans ( i.e., $true or $false ). Using expression you can do many things.
For example, lets say Henry is very punctual and very dedicated and you wanted to give some additional marks (lets say 2 marks) to encourage him.
Example:
MSH C:\temp\monad> $a,$b,$c,$d | sort @{expression={if ($_.Name -eq "Henry") { $
_.Score += 2 }}},Score -Descending
Score Name
----- ----
100 John
92 Henry
90 Tom
80 David
Notice the use of Script for expression. In the above example, I changed the original object itself by using $_ and then sorted on Score
MSH C:\temp\monad> $b
Score Name
----- ----
92 Henry
Using Script block you can do many things like computing Grades and then sorting on Grade.
MSH C:\temp\monad> $a,$b,$c,$d | sort Grade,@{expression={if ($_.Score -gt 91) {
$Grade="A" } else {$Grade="B" }; add-member noteproperty "Grade" $Grade -InputOb
ject $_}} -Descending
Score Name Grade
----- ---- -----
90 Tom B
80 David B
100 John A
92 Henry A
Sort in its simplest form is very useful. Using expressions effectively makes it more powerful.
One last thing, a number of you has asked how to sort a hashtable using Sort-Object cmdlet.
MSH C:\temp\monad> $hash=@{"Tom"=90;"Henry"=90;"David"=80;"John"=100}
MSH C:\temp\monad> $hash | sort value -descending
Name Value
---- -----
Henry 90
Tom 90
David 80
John 100
This will not work as there is only one object on the pipeline and sort-object does not have anything to sort. However use GetEnumerator() on HashTable to write all the hash entries to the pipeline and then use sort.
MSH C:\temp\monad> $hash.GetEnumerator() | sort value -descending
Name Value
---- -----
John 100
Tom 90
Henry 90
David 80
-Krishna[MSFT]
Comments
- Anonymous
March 21, 2006
Shoot, now you tell me I can sort by multiple properties! That could have saved me a bit of code in my WTT script.
Seriously, thanks for the info! Very useful.