Dela via


So many ways to take care of that poor old cat – Getting a list of just directories in PowerShell

Such a simple concept…how can we just retrieve a listing of folders instead of files and folders.  Hopefully readers of this post know already that in PowerShell (1 or 2) we use “Get-ChildItem” (many still use the alias “dir”) to retrieve a listing of files and folders.  If you didn't know that “dir” was an alias for “Get-Childitem”, now you do :)

When I first learned this many moons ago, I wondered why the actual cmdlet had the word “item” instead of “file” or “folder”.  Once I learned about PowerShell providers I realized that “get-childitem” was a more general cmdlet that can be used on all sorts of different data sources, totally dependant on what providers you have installed and loaded into your PowerShell host.  Lets get back to the point here, again, we use “get-childitem” to get a simple directory listing:

 image

No problem.  Now, how do we list just the folder or directories?  In CMD I would use a “dir /ad” to get this:

image

In the image above, you might notice a few more folders than we see in the PowerShell image above.  This is because “get-childitem” doesn't show hidden files or folders by default, but we can see them by simply adding the "-force” switch to the cmdlet:

image

Confusion over.  Now, back to just showing folders only.  If you look at the parameter help for “get-childitem” you wont find a nice simple switch to show only containers…don't get me wrong, I wish it was there.  Does this mean we are out of luck.  Of course not, if we were then why are you still reading :)

So where does this leave us?  PowerShell has so much power and grace through the use of these wonderful object rich pipelines.  Lets use them to solve this simple need.  We can leverage our old trusty object instance filtering cmdlet…”where-object”.  We see that “get-childitem” is giving us more than what we need.  Lets filter down the instances here so that we only have folders left.  Now here is where the cat gets scared.  There are a lot of ways to do this.

First my preferred way.  If you look at a “get-member” result of a “get-childitem”, or simply pipe it to a “format-list *”, you will see that both the file and directory objects have a nice property called “PSIsContainer”.  Its a Boolean (true or false) object contained in the property.  This is great.  We have a simple true or false property that lets us programmatically differentiate between folders and files.

image

In the image above you can see that clearly we are now just seeing folders.  But wait…there’s more… :)

If you didn't spot or find the PSIsContainer property, there are others ways to do this.  From a plain old “dir”, we can see the left most column is “mode”.  While I wouldn't personally prefer mode to use for a filter, it can be done.  If you send the “dir”, or “get-childitem” results to a get-member and really look at the mode member things get interesting.  I PowerShell v1, “mode” is a “scriptproperty” and you can actually see that the code is a handful of if statements that are reading attributes from the attributes property.  In PowerShell v2, it looks like “mode” was changed to a “CodeProperty”.  To be perfectly honest, I am not sure why that changed, or what the implications of that change are.  Often times in PowerShell I tell folks, you just dont have to know everything about what you are doing to be good with this :)

In the image below I will filter folders based on the mode property:

image

This works out pretty well.  This examples uses basic wildcard matching with the “–like” operator.  I am not a real fan of using text based properties for this sort of thing.  This is why my preferred method is using the Boolean “PSISContainer” as I used above.

If you notice as well, from the above images, folder appear to have a null length.  Files seem to have at least a valid size or 0.  We can filter on this as well:

image

That seems to work.  If you take a look at a “Get-Childitem” result piped to a “format-list *”, you will see that you can use the attributes property as well too.  This property is a weird one at first glance.  It turns out that this is a special object which really contains a property called “__Value” that has a bit masked value containing the attribute flags.  When we see this property during a “get-ChildItem” though, we see its “.ToString()” method representation which converts the bitmask into a comma separated strings that are more human friendly.

image

Nonetheless, we can use either the “value__” or the string representation to filter on to list only folders:

image

If that isn't enough ways to do this, I have on more that I do think is another cool way to do this.  When you pipe the results of the “Get-ChildItem” to a “get-member”, you see that there are actually two different object types that comes back.  There are different objects for files and directories.  We can use this to.  We can use the type operator “-is” to filter out object types from our pipeline:

image 

 

So you can see from this post, that when you consider such a simple need as displaying only folders, that poor old cat just doesn't have a chance.  The fact that there are so many ways to accomplish this is both a blessing and a curse for those beginning learners.  I love this flexibility as it breeds innovative ideas.  Now just for the record, of all those ways above, in real life the only two I would ever use as the first one and the last one (the “PSISContainer” and the “-is [system.io.directoryinfo]”).  They are more prone to accuracy and less chance of unexpected results…otherwise known as bugs:)

Have a good one!

 

-Gary

 

This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.