Where Is the File: Using Get-FileItem

And we’re back with our look at a couple of command line utility items. In part one, I discussed how to use Where.exe, which can locate files and return the full file name. There’s nothing wrong with the utility because it gets the job done efficiently. However, it really is a legacy command line tool and as such has some limitations, especially if you want to do anything with the results.
It is possible to run it in PowerShell, although you have to be explicit to avoid confusing it with the Where alias for Where-Object.

​PS C:\> where.exe calc.exe

It certainly makes it easier to find and execute the file.

PS C:\> where.exe calc.exe | invoke-item

But anything more complicated, especially once you start adding directories and parameters gets a little messy. If you are going to be using this in PowerShell (and why wouldn’t you?) then it would seem to make sense to use a PowerShell version of WHERE.EXE. So I wrote one for us!

Using Get-FileItem

My version is an advanced function called Get-FileItem. I wanted to stick with a conventional naming scheme, but the script file will also define an alias called pswhere. The where alias is already in use from Where-Object so I had to come up with something else. The function acts just like a cmdlet and includes complete help and examples as you can see in Figure 1.
Help for Get-FileItem
Figure 1 Help for Get-FileItemI tried to stick to the same syntax and features as the original WHERE.EXE, but I tweaked a few parameter names to make them more PowerShell-like and added a few features. The basic syntax and usage is the same.

​PS C:\> pswhere notepad.exe

Using Regex with pswhere

One new feature is the addition of regular expression support. In the CLI version, you were limited to wildcards. Now you can specify your search pattern as a regular expression.

​PS C:\> pswhere "^\d+\S+\.((txt)|(xml))" -Regex -path c:\work,c:\scripts -recurse

In this expression, I am searching for any .xml or txt file that begins with a number in the C:\work and C:\Scripts directory. I’m even searching recursively, although I don’t have any matching files.
The default output is the full file name, but if you need to compare files or want detailed information, I decided to write the full file object to the pipeline.

​PS C:\> pswhere notepad.exe -full
    Directory: C:\Windows\system32
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         7/13/2009   9:39 PM     193536 notepad.exe
    Directory: C:\Windows
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         7/13/2009   9:39 PM     193536 notepad.exe

Of course, this means you can do further sorting, exporting or filtering as needed.
My PowerShell version of WHERE.EXE uses –Quiet but writes $True or $False, which makes it much easier to work with.

​PS C:\> if (pswhere vboxmanage.exe -quiet) { "Found file" } else {"File not found"}
Found file

Finally, I decided to add one more feature. It is possible that you may search for a pattern and get many results back but perhaps all you care about is if you find at least one result. I added a –First parameter, which will skip searching any other folders as soon as a match is made. This can be helpful if searching a deep directory structure and you know you can stop after the first file is found.

​PS C:\> pswhere winword.exe -path c:\ -recurse -first -EA SilentlyContinue
C:\Program Files\Microsoft Office\Office14\WINWORD.EXE
PS C:\>

There’s no reason to keep searching the C: drive once I’ve found the file. In fact, this is a handy way to create some shortcuts in the shell.

​PS C:\> $wd=pswhere winword.exe -path "c:\program files" -recurse -first -ea silentlycontinue

Now, whenever I need to launch Microsoft Word, I don’t have to take my hands off the keyboard!

​PS C:\> &wd

You can download the script file here: Get-FileItem. Rename it with a .ps1 file extension. You will need to dot source the file in your shell or profile script. The file includes the pswhere alias. Once loaded, be sure to look at full help and examples before you try it out.
I’ll post any future updates on this script to my blog (http://jdhitsolutions.com/blog). If you have questions on how the function is written or other issues, feel free to use my Q&A forum at http://bit.ly/AskJeffHicks.