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:
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.
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:
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
- See all possible values for the flags:
- “Performing cleanup” – Excel is stuck with an old, conflicted file and will never recover. - November 12, 2024
- How to add multiple app URIs for your Entra app registration? - November 5, 2024
- How to access Environment Secrets with GitHub Actions? - October 29, 2024