19

I have a project folder called topfolder and I want to find all files in all subfolders that match a certain pattern, e.g. when the folder contains foo anywhere in its name, I want to list all files inside it.

I tried something like:

gci .\topfolder -rec -filter *foo*

but it has two problems:

  1. Only files actually containing foo will be listed (I want any file in foo-like folder).
  2. Directories matching this filter will be part of the result set too.

Then I tried this:

gci .\topfolder\*foo* -include *.*

but that doesn't work at all - apparently wildcards match only a single segment of a path so that pattern will match topfolder\foobar but not topfolder\subfolder\foobar.

The only way I've found so far was to use Get-ChildItem twice, like this:

gci .\topfolder -rec -include *foo* | where { $_.psiscontainer } | gci

This works but it seems like a waste to call gci twice and I hope I just didn't find a right wildcard expression for something like -Path, -Filter or -Include.

What is the best way to do that?

Borek Bernard
  • 43,410
  • 50
  • 148
  • 224

1 Answers1

20

I would use the Filter parameter instead of Include, it performs much fatser

gci .\topfolder -rec -filter *foo* | where { $_.psiscontainer } | gci
Shay Levy
  • 107,077
  • 26
  • 168
  • 192
  • How is it different from my last example? Won't it be even slower than my attempt? – Borek Bernard Apr 03 '12 at 15:02
  • Sorry, I must have been blind ;) – Shay Levy Apr 03 '12 at 15:08
  • 1
    Thanks that is a good optimization tip (I was not even sure what the difference is between -Include and -Filter), however, does that also mean that this task cannot be achieved using single gci only? I basically need the `.\toplevel\*foo*` match `toplevel\subfolder\foobar`. Does PowerShell work like that? The documentation says that "star matches zero or more characters" so I was hoping that the first star would match `subfolder\` and the second `bar` so that directory name as a whole would match. However, that doesn't seem to be the case. – Borek Bernard Apr 03 '12 at 15:31
  • Sorry, I've messed the formatting. Hope you can digest what I meant. – Borek Bernard Apr 03 '12 at 15:32
  • 2
    That's the way it works. If you filter folders then you need to list them to get their content, if you filter files you need to check their fullname (path) or directoryName properties and base your criteria on them. Sometimes the first method is suitable and sometimes the latter. – Shay Levy Apr 03 '12 at 15:49
  • Thanks for a great pointer, `gci .\topfolder -r | where { $_.directoryname -like '*foo*' }` works like a charm. I think you can add that as an answer (if it has some performance implications, just mention them but it works fast enough for me). – Borek Bernard Apr 03 '12 at 16:47
  • During my experiments I found out this also works: `([io.directoryinfo](Resolve-Path .\topfolder).Path).getDirectories('*foo*','AllDirectories') | Select-Object -Property @{n='Path'; e={$_.FullName}} | gci`. Not sure how good or bad this solution is but it is another way to get the job done. – Borek Bernard Apr 03 '12 at 16:50
  • It looks like you've got this figured out, but I was wondering whether it's your intent to return files in `\topfolder\foobar\subfolder`. If for some reason you need to avoid that level of recursion, know that you can use something like `gci .\topfolder -r | where { $_.parent -match 'foo' }`. – ajk Apr 03 '12 at 22:15