PowerShell header

Properly checking if an item in a folder is a Directory or not in PowerShell

This post was most recently updated on July 27th, 2022.

3 min read.

I got a great tip from a colleague on how to properly check if an item is a file or a directory. In one case we weren’t really ever sure if another script had finished its running and unzipped a certain zip package into a folder, and we had to verify it had, before continuing the execution. Our initial implementation worked most of the time… But not quite always. The purpose of this blog post is to explain how we found a pretty well-working and elegant solution!

Problem

In this particular case, we were testing items for being directories with the following script:

$item = Get-ChildItem -Path [path_to_item]
if ($item -eq $null -or $item.Attributes -ne "Directory") {

However, that doesn’t work that well, as it breaks with whatever additional attributes are being applied to the file or folder. And there are a lot of situations, where new attributes get added to items in a folder. One good example is “NotContentIndexed”, which gets added if you (or whatever piece of automation) sets the file to be excluded from the Windows Search index. See the references for more details about the attributes!

After some back and forth, we ended up improving the script in a few ways. 

Solution

The following code example shows a rough idea of how that works. In this example, we needed to test if a zip file was unzipped by a script that ran earlier and then proceeds with the execution.

$item = Get-ChildItem -Path [path_including_name_without_extension] -Directory | select -first 1
if ($item -eq $null -or ($item.Attributes -band [IO.FileAttributes]::Directory) -ne [IO.FileAttributes]::Directory) { 
   Write-Host "The file is missing or not unzipped inside the folder, please unzip it!" -ForegroundColor Red 
}

Let’s dissect this a bit – so what are we actually doing?

In this code example, we start by getting an item from a path, where we KNOW that a zip package used to be located.

$item = Get-ChildItem -Path [path_including_name_without_extension] -Directory | select -first 1

Even if the zip package still is there, it’ll ignore it and only get the directories, and select the first one that matches the path. See for an example below:

Get-ChildItem example with -Directory flag and pipe to select
Get-ChildItem example with -Directory flag and pipe to select

This line should always only get directories, so the rest of the code wouldn’t be necessary. However, it’s included as an example of how to verify, if an item is a directory or not!

The next part will only run the code inside the IF-block if the item we have is not a directory. In this example, the whole block is just a Write-Host command with complaints about the lack of a folder.

if ($item -eq $null -or ($item.Attributes -band [IO.FileAttributes]::Directory) -ne [IO.FileAttributes]::Directory)

The first part of the clause is pretty clear – if we didn’t get anything with the Get-ChildItem, the variable is $null, and we’re going to go into the If block.

The latter part of the clause performs a “bitwise and” comparison between an enum (System.IO.FileAttributes is an enum type) and the flag (value of the enum) for Directory and will return 0 (if none of the attributes match Directory) or the flag for Directory ([IO.FileAttributes]::Directory).

The return value is then compared to [IO.FileAttributes]::Directory – this should be a pretty surefire way of making sure we’ve got the right item :)

Write-Host "The folder is missing or not unzipped, please unzip it!" -ForegroundColor Red 

In the end, if we do end up in the IF block, we complain about the folder missing. And like any good script, we complain in RED.

Get-ChildItem example with a missing Folder
Get-ChildItem example with a missing Folder

An alternative way to check if an item is a directory or not: PSIsContainer-property

(Updated on 6.9.2018)

After sharing this post on Twitter, Greg McMurray shared a really good point:

PowerShell adds a few NoteProperty properties to Get-ChildItem. You can use "dir | ? { $_.PSIsContainer }" to just get folders. No need for additional logic or file attributes.
Greg McMurray on Twitter about using dir | ? { $_.PSIsContainer }

Since “dir” is an alias to Get-ChildItem, this call gets all the items in the current working directory, and pipes them to a comparison operator that only returns the items for which the PSIsContainer property is true. This is a great shorthand call – functionally equivalent to the first line of the code example earlier in the article.

So, to just get or list all folders in the current directory, run this:

dir | ? { $_.PSIsContainer }

Due to “dir” being an alias, you can use the switches you use with Get-ChildItem – like “-Recurse”, to go through all the subdirectories, too!

dir -Recurse | ? { $_.PSIsContainer }

Good stuff!

References

mm
5 1 vote
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments