[powershell] Recursive file search using PowerShell

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