Use PowerShell to Choose Unique Objects from a Sorted List
Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to select unique objects and properties from a sorted list.
Microsoft Scripting Guy, Ed Wilson, is here. I have been busy working on the study guide for the 2012 Scripting Games. It will look similar to the 2011 Scripting Games Guide. If you are thinking about the 2012 Scripting Games, and you really should, you would do well to review the content I created for the 2011 Scripting Games Guide. Also think about the following help to ramp up for this year’s games:
- Review the event questions and answers
- Watch the five training videos
- Take the Windows PowerShell quizzes
The Scripting Games are the best opportunity to learn Windows PowerShell.
Using the Get-Unique cmdlet
Anyway, as part of my work for the 2012 Scripting Games, I have been looking over cmdlets, examining the Help files, and in general reviewing the Windows PowerShell fundamentals. It dawned on me that I have not written very much about the Get-Unique cmdlet.
It is important to keep in mind how the Get-Unique cmdlet works, or else it can return misleading results. For example, the following code that returns the number of unique processes running on a computer appears to work just fine.
Get-Process | Get-Unique | Measure-Object
Sort the list of objects
Unfortunately, there is no guarantee that the results will be accurate. This is because the Get-Unique cmdlet compares each item in a sorted list to the next item to eliminate duplicates. Without sorting the list, the results are not necessarily going to be accurate.
There is another issue to consider: How do I determine what is unique in dealing with processes? Do I want unique process names, unique process IDs, unique memory consumption, unique executable paths, or what? The System.Diagnostics.Process .NET Framework object contains 51 properties—any one of which one could use to define “unique.” Without specifics, one cannot be certain what unique characters will return for the object.
An additional aspect of uniqueness to consider arises because of the object-oriented nature of Windows PowerShell. The Get-Unique cmdlet returns unique objects, or unique strings. Because everything in Windows PowerShell is an object, this can become an extremely short list. The following code returns only one unique object from a listing of processes on the local computer.
Get-Process | Get-Unique -OnType | Measure-Object
Specify the property upon which to sort
When examining a specific property of an object and treating the property as a string, the Get-Unique cmdlet determines the property upon which to operate based on the property that is specified to the Sort-Object cmdlet. The following code counts the number of unique processes, based on process name.
Get-Process | sort-object name | Get-Unique -asstring | Measure-Object
To identify unique processes based on the process ID, use the code that follows.
Get-Process | sort-object id | Get-Unique -asstring | Measure-Object
The commands to derive unique processes based on object type, process name, and process ID, along with the output associated with each command, appear in the image that follows.
A shortcut to uniqueness
In most cases, it is a unique property and not a unique object that is the object of a query. Because the Get-Unique cmdlet requires sorting objects prior to piping, it is possible to bypass use of the Get-Unique cmdlet by using the Unique switched parameter from the Sort-Object cmdlet. Here is an example of using the Unique parameter from the Sort-Object cmdlet.
get-service | Sort-Object status -Unique | measure
If you use the Select-Object cmdlet, it might be easier to use the Unique parameter from that cmdlet. The code to do this is shown here.
get-service | Select-object status -unique | measure
What about case sensitivity?
Nearly everything in Windows PowerShell defaults to case insensitive, therefore it might come as a surprise that the Get-Unique cmdlet and the Select-Object cmdlet are case sensitive in determining uniqueness. The Sort-Object cmdlet is not case sensitive when choosing unique objects from the list.
In the code that follows, I create an array of strings with a mixture of upper case and lowercase items in the array. I then pipe the strings to the Sort-Object cmdlet prior to piping the results to the Get-Unique cmdlet to sort the strings. Next, I pipe the strings to the Sort-Object and use the Unique parameter to obtain uniqueness. Finally, I pipe the strings to the Select-Object cmdlet, and I use the Unique parameter there also.
$a = “one”,”two”, “Two”, “three”, “Three”
$a | sort-object | Get-Unique –AsString
$a | sort-object –Unique
$a | Select-Object -Unique
The code to create the array of strings and select unique strings from the array, and the associated output are shown in the image that follows.
Well, that is about all there is to selecting unique objects from a list. There are three ways to do this: use the Get-Unique cmdlet, use the Unique parameter from the Sort-Object cmdlet, or use the Unique parameter from the Select-Object cmdlet.
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