[powershell] Recursive file search using PowerShell

I am searching for a file in all the folders.

Copyforbuild.bat is available in many places, and I would like to search recursively.

$File = "V:\Myfolder\**\*.CopyForbuild.bat"

How can I do it in PowerShell?

This question is related to powershell powershell-2.0

The answer is


Try this:

Get-ChildItem -Path V:\Myfolder -Filter CopyForbuild.bat -Recurse | Where-Object { $_.Attributes -ne "Directory"}

Here is the method that I finally came up with after struggling:

Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*

To make the output cleaner (only path), use:

(Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*).fullname

To get only the first result, use:

(Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*).fullname | Select -First 1

Now for the important stuff:

To search only for files/directories do not use -File or -Directory (see below why). Instead use this for files:

Get-ChildItem -Recurse -Path ./path*/ -Include name* | where {$_.PSIsContainer -eq $false}

and remove the -eq $false for directories. Do not leave a trailing wildcard like bin/*.

Why not use the built in switches? They are terrible and remove features randomly. For example, in order to use -Include with a file, you must end the path with a wildcard. However, this disables the -Recurse switch without telling you:

Get-ChildItem -File -Recurse -Path ./bin/* -Include *.lib

You'd think that would give you all *.libs in all subdirectories, but it only will search top level of bin.

In order to search for directories, you can use -Directory, but then you must remove the trailing wildcard. For whatever reason, this will not deactivate -Recurse. It is for these reasons that I recommend not using the builtin flags.

You can shorten this command considerably:

Get-ChildItem -Recurse -Path ./path*/ -Include name* | where {$_.PSIsContainer -eq $false}

becomes

gci './path*/' -s -Include 'name*' | where {$_.PSIsContainer -eq $false}
  • Get-ChildItem is aliased to gci
  • -Path is default to position 0, so you can just make first argument path
  • -Recurse is aliased to -s
  • -Include does not have a shorthand
  • Use single quotes for spaces in names/paths, so that you can surround the whole command with double quotes and use it in Command Prompt. Doing it the other way around (surround with single quotes) causes errors

When searching folders where you might get an error based on security (e.g. C:\Users), use the following command:

Get-ChildItem -Path V:\Myfolder -Filter CopyForbuild.bat -Recurse -ErrorAction SilentlyContinue -Force

Get-ChildItem V:\MyFolder -name -recurse *.CopyForbuild.bat

Will also work


To add to @user3303020 answer and output the search results into a file, you can run

Get-ChildItem V:\MyFolder -name -recurse *.CopyForbuild.bat > path_to_results_filename.txt

It may be easier to search for the correct file that way.


Filter using wildcards:

Get-ChildItem -Filter CopyForBuild* -Include *.bat,*.cmd -Exclude *.old.cmd,*.old.bat -Recurse

Filtering using a regular expression:

Get-ChildItem -Path "V:\Myfolder" -Recurse
| Where-Object { $_.Name -match '\ACopyForBuild\.[(bat)|(cmd)]\Z' }

I use this to find files and then have PowerShell display the entire path of the results:

dir -Path C:\FolderName -Filter FileName.fileExtension -Recurse | %{$_.FullName}

You can always use the wildcard * in the FolderName and/or FileName.fileExtension. For example:

dir -Path C:\Folder* -Filter File*.file* -Recurse | %{$_.FullName}

The above example will search any folder in the C:\ drive beginning with the word Folder. So if you have a folder named FolderFoo and FolderBar PowerShell will show results from both of those folders.

The same goes for the file name and file extension. If you want to search for a file with a certain extension, but don't know the name of the file, you can use:

dir -Path C:\FolderName -Filter *.fileExtension -Recurse | %{$_.FullName}

Or vice versa:

dir -Path C:\FolderName -Filter FileName.* -Recurse | %{$_.FullName}