Happy Monday everyone! I thought it might be a fun way to start the week by sharing my favorite PowerShell one-liner. One-liners are nostalgic for me, because I learned a lot of cool programming tricks from one-liners in issues of Compute magazine a long time ago. The PowerShell one-liners that grab my interest the most are those that can do many different things in the simplest pipeline possible.
So far, eight years into using PowerShell, this is my favorite PowerShell one-liner:
At first glance, can you tell what this does? Take a minute to think about it, I’ll wait.
Ok, now that you’ve thought about it a bit, you might have realized that it is not that easy to figure out everything that this does, so let me break it down into parts.
gci –r -force
If your familiar with PowerShell, this part is pretty straightforward. gci is an alias for Get-ChildItem, and this command tells PowerShell to get a recursive (-r) directory listing of all files and folders, including any hidden files or folders (-force), starting from the current location.
measure -sum PSIsContainer,Length -ea 0
measure is an alias for Measure-Object, a cmdlet that can perform calculations on a collection of objects that it is passed from a pipeline. In this case, we’re going to aggregate (-sum) two values from properties in this collection: PSIsContainer and Length. We’re also going to hide any errors we get from trying to access folders that we don’t have access to (-ea 0). How Measure-Object measures the objects it receives is the most interesting part of this pipeline.
You can probably guess why we would want to calculate the sum of the Length property, but why would you want to calculate the sum of the PSIsContainer property? PSContainer is a boolean value that indicates whether or not an item returned from Get-ChildItem is a container. A value of $true indicates it is a folder, and a value of $false indicates it is a file. When you calculate the sum of a bunch of boolean values in PowerShell, PowerShell first converts those boolean values into their integer equivalent. $false implictly converts into a value of 0, and $true implicitly converts into a value of 1. Given this is the case, by aggregating the PSIsContainer property, you’re effectively calculating a sum of the number of containers in the result set.
PowerShell allows you to assign a multi-valued result set to different variables by separating the variables with a comma. In such an assignment, the first object returned will be assigned to the first variable, the second assigned to the second variable, and so on until the last variable which will contain all remaining objects. In this case, we’re assigning two variables, and each will contain a single value. Since we’re aggregating two properties (PSIsContainer and Length), Measure-Object will return two objects containing measurement information: one for PSIsContainer and one for Length. The measurement information for PSIsContainer will be assigned to $di and the measurement information for Length will be assigned to $fi.
Also, in addition to calculating the aggregate for the two properties, Measure-Object also counts the number of objects that it processes to perform that calculation and includes that count in the result as well. In cases where an object does not have a property that is being measured, that object will not be included in the count, so folders, which do not have a Length property, will not influence the values returned in the second measurement information object that is assigned to $fi.
Putting it all together
When I run the aforementioned one-liner on my PowerShell folder, here are the values I get from $di and $fi, respectively:
Count : 6516
Sum : 2012
Property : PSIsContainer
Count : 4504
Sum : 917710488
Property : Length
For the $di object, the Sum property identifies how many directories were found in the search. This was determined by aggregating the integer value of the PSIsContainer property on the objects that were measured. The Count property identifies how many items altogether were processed (directories and files, both of which have a PSIsContainer property).
For the $fi object, the Sum property identifies the total size of all files that were found in the search, and the Count property identifies how many files were found in the search.
Put this all together, and you have a PowerShell one-liner that gives you folder stats, identifying the number of files and folders in a folder as well as the total size of all files in that folder. Neat, huh? I think the reason why I like this PowerShell one-liner the most is because it demonstrates how a little creativity can be applied to get useful information that is not available in a native cmdlet from several sources in a simple and elegant manner.
What’s your favorite one-liner, and why?
Maybe I should start a meme with this. Jeffrey Hicks, Shay Levy, Ed Wilson, June Blender, and Hal Rottenberg, tag, you’re it!
11 thoughts on “My favorite PowerShell one-liner”
This is my favorite one-liner (it’s safe):
iex (New-Object Net.WebClient).DownloadString(“http://bit.ly/e0Mw9w”)
Definitely a classic!
I’m having trouble coming up with an all-time favorite but here’s one I’ve been using a lot in the last few months:
Get-xDscOperation -Newest 3 | select -ExpandProperty allevents | select timecreated, message | Out-GridView
If it’s not obvious to you what this does, it pops up a searchable window that has all of the events from the last 3 times PowerShell Desired State Configuration (DSC) has checked configuration data or applied changes.
I love using Out-GridView for this because I can quickly use the filter box to search for specific things in the logs. You can also view the entire message field which in the console can sometimes be a pain with long entries.
Very useful Jonathan, thanks for sharing. Out-GridView is indeed highly useful, especially in situations like this.
I am getting this when I run the line:
gci -r -Force | measure -Sum PSIsContainer,lenght -ea 0
Count : 114
Sum : 2
Property : PSIsContainer
SO then when I run:
$di,$fi = gci -r -Force | measure -Sum PSIsContainer,lenght -ea 0
and check the variables:
Count : 114
Sum : 2
Property : PSIsContainer
and $fi is empty? what did I miss?
Try with “length”, not “lenght” (spelled incorrectly). Then it will work.
I don’t see what the difference is? Maybe someone can help?
gci –r -force | measure -sum PSIsContainer, Length -ea 0 #working
gci -r -Force | measure -sum PSIsContainer, Lenght -ea 0 #Not Working
Your second line has a typo (“Lenght” should be “Length”). That’s why it isn’t working.
My new favorite one-liner is this:
ghy | select -exp commandline | ogv -outp M | iex
Multi-select commands from your history and run them.
Get-History | Select-Object -ExpandProperty commandline | Out-GridView -OutputMode Multiple | Invoke-Expression #long version
Nice! That would probably a good challenge to put on Code-Golf. And it probably points to something that should be improved in PowerShell Core — I never liked that Invoke-History takes pipeline input but only accepts a single history command.