Summary: Much of the time, there is no guarantee to the order in which Windows PowerShell returns objects. This blog explains how to fix that issue.
Hey, Scripting Guy! I have a problem with Windows PowerShell. It seems that it deliberately randomizes the output. I mean, there seems to be no rhyme or reason to the way that information is returned from a cmdlet. Am I alone in this frustration, or is there some secret sauce that I am missing? Windows PowerShell is cool, but if I always have to put data into an Excel spreadsheet just to sort it, then it is not much better than VBScript in my mind. Help me, oh fount of Windows PowerShell wisdom.
Microsoft Scripting Guy, Ed Wilson, is here. The other day, the Scripting Wife and I were at the first ever Windows PowerShell User Group meeting in Charlotte, North Carolina. It was really cool. We love being able to interact with people who love Windows PowerShell as much as we do. Next month, we are having a script-club type of meeting; we encourage people to show up with the Windows PowerShell scripts they are working on, so it will be a show-and-tell type of meeting.
Use Sort-Object to organize output
Anyway, after the user group meeting, when we were all standing around, one of the attendees came up to me and asked me in what order Windows PowerShell returns information. The answer is that there is no guarantee of return order in most cases. The secret sauce is to use the built-in sorting mechanism from Windows PowerShell itself. In the image that follows, the results from the Get-Process cmdlet appear to sort on the ProcessName property.
One could make a good argument that the processes should sort on the process ID (PID) or on the amount of CPU time consumed, or on the amount of memory utilized. In fact, it is entirely possible that for each property supplied by the Process object, someone has a good argument for sorting on that particular property. Luckily, custom sorting is easy to accomplish in Windows PowerShell. To sort returned objects in Windows PowerShell, pipe the output from one cmdlet to the Sort-Object cmdlet. This technique is shown here where the Sort-Object cmdlet sorts the Process objects that are returned by the Get-Process cmdlet.
Get-Process | Sort-Object id
The command to sort the Process objects on the ID property and the output associated with that command are shown in the image that follows.
Reversing the sort order
By default, the Sort-Object cmdlet performs an ascending sort—the numbers range from small to large. To perform a descending sort requires utilizing the Descending switch.
Note: There is no Ascending switch for the Sort-Object cmdlet because that is the default behavior.
To arrange the output from the Get-Process cmdlet such that the Process objects appear from largest process ID to the smallest (the smallest PID is always 0—the Idle process), choose the ID property to sort on, and use the Descending switch as shown here:
Get-Process | Sort-Object id –Descending
The command to perform a descending sort of processes based on the process ID, and the output associated with that command are shown in the image that follows.
When you use the Sort-Object cmdlet to sort output, keep in mind that the first position argument is the property or properties upon which to sort. Because Property is the default means that using the name Property in the command is optional. Therefore, the following commands are equivalent:
Get-Process | Sort-Object id –Descending
Get-Process | Sort-Object -property id –Descending
In addition to using the default first position for the Property argument, the Sort-Object cmdlet is aliased by sort. By using gps as an alias for the Get-Process cmdlet, sort as an alias for Sort-Object, and a partial parameter of des for Descending, the syntax of the command is very short. This short version of the command is shown here.
gps | sort id –des
Sorting multiple properties at once
The Property parameter of the Sort-Object cmdlet accepts an array (more than one) of properties upon which to sort. This means that I can sort on the process name, and then sort on the working set of memory that is utilized by each process (for example). When supplying multiple property names, the first property sorts, then the second property sorts.
The resulting output may not always meet expectations, and therefore, may require a bit of experimentation. For example, the command that follows sorts the process names in a descending order. When that sort completes, the command does an additional sort on the WorkingSet (ws is the alias) property. However, this second sort is only useful when there happen to be multiple processes with the same name (such as the svchost process). The command that is shown here is an example of sorting on multiple properties.
Get-Process | Sort-Object -Property name, ws –Descending
The figure that is shown here illustrates the output from the command to sort Process objects based on name and ws properties.
When the name and ws properties reverse order in the command, the resulting output is not very useful because the only sorting of the name property happens when multiple processes have an identical working set of memory. The command that is shown here reverses the order of the WorkingSet and the process name properties.
Get-Process | Sort-Object -Property ws, name –Descending
The output that is shown here shows that there is very little grouping of process names. In this example, adding the name property does not add much value to the command.
Sorting and returning unique items
At times, I might want to see how many different processes are running on a system. To do this, I can filter duplicate process names by using the Unique switch. To count the number of unique processes that are running on a system, I pipe the results from the Sort-Object cmdlet to the Measure-Object cmdlet. This command is shown here.
Get-Process | Sort-Object -Property name -Descending -Unique | measure-object
To obtain a baseline that enables me to determine the number of duplicate processes, I drop the Unique switch. This command is shown here.
Get-Process | Sort-Object -Property name -Descending | measure-object
Performing a case sensitive sort
One last thing to discuss when sorting items is the CaseSensitive switch. When used, the CaseSensitive switch sorts lowercase letters first, then uppercase. The following commands illustrate this.
$a = "Alpha","alpha","bravo","Bravo","Charlie","charlie","delta","Delta"
$a | Sort-Object –CaseSensitive
When the two previous commands run, the output places the lowercase version of the word prior to the uppercase version. This output appears in the figure that follows.
CD, that is all there is to sorting with Windows PowerShell. Pipeline Week will continue tomorrow when I will talk about grouping things with Windows PowerShell.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy