Windows PowerShell Tip of the Week
Here’s a quick tip on working with Windows PowerShell. These are published every week for as long as we can come up with new tips. If you have a tip you’d like us to share or a question about how to do something, let us know.
Find more tips in the Windows PowerShell Tip of the Week archive.
Using Test-Path to Verify the Existence of an Object
When you think of Windows PowerShell it’s probably safe to say that the Test-Path cmdlet isn’t the first thing that pops into your head; it’s probably also safe to say that the Test-Path cmdlet isn’t the 9th thing that pops into your head, or the 34th thing that pops into your head, or even the 258th thing that pops into your head. So does that mean that Test-Path is the Scripting Guys of PowerShell cmdlets: obscure, and largely useless? Let’s just see about that.
As the name implies (sort of), Test-Path lets you verify whether items exist at a specified path. For example, suppose you have a PowerShell script designed to delete items from the folder C:\Scripts\Archive. Before you issue the delete command, you might want to verify that this folder even exists; after all, if it doesn’t your delete command is going to raise an error. How do you verify that a folder exists? Why, by using Test-Path, of course:
Test-Path will return True if the folder exists and False if the folder doesn’t exist. See? Test-Path might be obscure, but it’s far from useless.
But wait: there’s more. It’s nice that Test-Path works with file system paths, but it can work with the paths used by other PowerShell providers as well. For example, does your computer have an environment variable named username? Hey, how are we supposed to know that? You’d be better off asking Test-Path:
Cool, huh? Test-Path also works with variables, certificates, aliases, and functions. For example:
And it works with the registry as well, albeit only with registry keys and not with the actual values contained in those keys:
Test-Path "HKCU:\Software\Microsoft\Driver Signing"
Very nice. But Test-Path can do more than simply tell you whether or not a given item exists. For example, suppose you do have the path C:\Scripts\Archive. Now, is Archive a folder or a file (that is, a file without a file extension)? Most likely it’s a folder, but how do you know that for sure? Here’s how you know that for sure:
Test-Path C:\Scripts\Archive -pathType container
What we’ve done here is tack on the –pathType parameter and assign the parameter the value container. That means that we want to know if the specified object (C:\Scripts\Archive) is a container: that is, is it capable of containing other objects. (Needless to say, a folder is capable of containing other objects.) Alternatively, we could have used the value leaf to determine if Archive was a leaf object (an object not capable of containing other objects):
Test-Path C:\Scripts\Archive -pathType leaf
Either way, we again get back the value True or False.
Let’s try another one. Suppose you want to know if there are any .PS1 files in the Archive folder; how could you figure that out? That’s easy: you can use Get-ChildItem to return a collection of all the files in the folder, filter out everything that didn’t have a .PS1 file extension, and then check to see if the number of items in the collection is greater than 0.
Good point; maybe that isn’t as easy as it first sounded. OK, then use Test-Path instead:
Nothing very complicated here: we’re simply using the wildcard syntax *.ps1 to represent any .PS1 files in the folder. As usual, Test-Path returns True if the folder contains at least one .PS1 file, and False if the folder doesn’t contain any .PS1 files.
Now let’s make this a tiny bit more complicated. What if we want to know if the Archive folder has either one or more .PS1 files or one or more .VBS files? That’s fine; in that case, we can use the –include parameter followed by the file extensions of interest:
Test-Path C:\Scripts\Archive\* -include *.ps1, *.vbs
Two things to note here. First, notice that we included a wildcard character at the end of our path: C:\Scripts\Archive\*. Is that important? No. Well, not unless you want the command to work. If you want the commands to work then, yes, make sure you tack the wildcard character onto the end.
Second, we separate the designated file extensions by using commas. And hey, you’re right: we didn’t just use file extensions, did we? Instead, we used regular wildcard syntax to indicate a file with a .PS1 or .VBS file extension:
So does that mean we could get even fancier here, and look for .PS1 or .VBS files whose file names started with the letters test? Well, there’s only one way to find out:
Test-Path C:\Scripts\Archive\* -include Test*.ps1, Test*.vbs
Now let’s try flipping this around. Suppose we need to know if there are any files in the Archive folder that don’t have a .PS1 file extension; can Test-Path help us with that?
Did you even need to ask:
Test-Path C:\Scripts\Archive\* -exclude *.ps1
This time around we used the –exclude parameter. When we use this parameter we essentially tell Test-Path, “OK, first of all, filter out all the excluded values. (In this case, that’s anything with a .PS1 file extension.) After you’ve done that, tell us if there’s anything left in the container.” If there isn’t, that means that – in this case – the only items found in the Archive folder are .PS1 files. See how that works? What if we needed to verify that we had only .GIF and .JPG files in a folder? No problem:
Test-Path C:\Scripts\Archive\* -exclude *.gif, *.jpg
If Test-Path returns True that can only mean one thing: we have at least one file in the Archive folder that has a file extension other than .GIF or .JPG.
That’s all we have time for today; we’re on a bit of a compressed schedule because of our trip to TechEd. But we’ll be back again next week. And good old, reliable Test-Path will always be there, whenever you need it.