Use -Include
rather than -Filter
, which makes the wildcard pattern work as intended:
Get-ChildItem -Path C:\Users\User\Downloads -Recurse -Include *.txt.*
Note: This matches files that have .txt.
anywhere in the filename, including foo.txt.csv
or "triple extensions" files such as foo.txt.txt.txt
.
*.txt.txt
would yield only filenames that end in .txt.txt
, which would still include triple-or-more .txt
-extension filenames.
Note that *.txt.txt
would work with -Filter
too.
While the -Filter
parameter has one major advantage - it makes the underlying filesystem provider perform filtering at the source which makes it much faster - it has limitations and pitfalls:
The wildcard pattern language is more limited than PowerShell's own, with legacy quirks - see this excellent answer for background information.
- In essence, only
*
and ?
are supported (not also character set/range expressions such as [0-9]
), and .*
or just .
at the end of a pattern match the empty string too (which is what you experienced).
- In Windows PowerShell (no longer a problem in PowerShell [Core] 6+), matching is unexpectedly also performed against the normally hidden short (8.3) filenames, which means that something like
*.xls
unexpectedly behaves like *.xls*
and also matches .xlsx
files, for instance.
You can only pass a single wildcard pattern to -Filter
, whereas -Include
supports multiple.
On a side note, -Include
and -Exclude
have their quirks too. Here, -Include
works as intended due to -Recurse
; without -Recurse
, you'd have to make your -Path
value end in \*
to make it work - see GitHub issue #3304.
Alternatively, if you need only a single wildcard pattern, you can get away with directly appending that pattern to the path - C:\Users\User\Downloads\*.txt.*
- as demonstrated in Matt's helpful answer.
However, the caveat is that with -Recurse
this only works as intended in PSv3 or above;
PSv2, by contrast, applies the pattern only to the immediate children (which was arguably the more sensible behavior).
On a related but distinct note, TessellatingHeckler has discovered an oddity when specifying literal paths that end in .
chars. (present since at least PSv2 and still as of PSv5.1):
PS> Get-Item -LiteralPath c:\windows\system32\cmd.exe... | Format-List Name, Extension
Name : cmd.exe...
Extension : .exe
Note how (a) cmd.exe
was still matched, despite the extraneous trailing .
chars., and (b) the .Name
property reflects those .
chars. - even though neither .Extension
nor .FullName
do.
The issue has been reported here, but since the the cause is the legacy-bound behavior of the underlying GetFileAttributes
native Windows API function, this issue will not be resolved in PowerShell.