13

Right now I updated to Windows 10 TH2 Build 10586 with PowerShell 5.0.10586.0

Now I got a problem with Get-ChildItem

$files = Get-ChildItem -LiteralPath $path -Force -Recurse -Include *.txt

This returns ALL files in $path even they are not .txt. This was working before the update. When I change it to

$files = Get-ChildItem -Path $path -Force -Recurse -Include *.txt

it works again. But that's not what I want. Is this a bug or am I doing something wrong?

Marc Fauser
  • 161
  • 1
  • 6
  • 1
    what's $path in there, does it have a \ at the end? – Adil Hindistan Nov 13 '15 at 01:30
  • I have tested both. With and without \ at the end. Doesn't make any difference. – Marc Fauser Nov 14 '15 at 00:11
  • The bug still affects _Windows PowerShell_, but has fortunately been fixed in PowerShell (Core) as of (at least) v7.0. However there is still questionable by-design behavior in the absence of `-Recurse`: `-Include` and `-Exclude` only apply to the _input_ paths, not to their _children_; the workaround is to use `Get-ChildItem * -Include ... / -Exclude ...` - see [this answer](https://stackoverflow.com/a/38308796/45375). – mklement0 Jun 13 '21 at 03:33

3 Answers3

8

Personally, I never use -Include or -Exclude anymore. I always pipe through Where-Object. I don't know if the author of -Include and -Exclude was insane or if there's a problem with the underlying .Net provider, but they're flaky as hell.

I'm on 5.0.10240.16384.

gci -Path $path -Include *.txt -Force

Returns nothing.

gci -LiteralPath $path -Include *.txt -Force

Returns everything in $path.

gci -LiteralPath $path -Include *.txt -Force -Recurse
gci -Path $path -Include *.txt -Force -Recurse

Both return *.txt in $path and all subfolders.

So what's the proper behavior supposed to be? Does the -Recurse flag modify how -Include works? I don't know. I no longer care. I'm not going to deal with that kind of behavior. I just use this:

gci -Path $path -Recurse -Force | Where-Object { $_.Extension -eq '.txt' }

I rely on Get-ChildItem to enumerate files and folders and that's it. Just give me the objects and I'll filter them. Like all the old Remove-Item -Recurse bugs, there's something there that just doesn't work the way people expect it to.

Bacon Bits
  • 30,782
  • 5
  • 59
  • 66
  • 1
    @MarcFauser Hm, you're right. [The doc](https://technet.microsoft.com/en-us/library/hh849800.aspx) also says that `-Include` modifies the `-Path` argument and says nothing at all about the `-LiteralPath` argument. Christ, why doesn't this cmdlet emit errors for unsupported syntax? And I have no idea what to make of Example 3, which explicitly talks about using `-Path` and `-Include` without `-Recurse`! Again I'm left asking, "What's the proper behavior supposed to be?" I'd probably post on Microsoft Connect, for all the good it will do. – Bacon Bits Nov 14 '15 at 15:50
  • 1
    @BaconBits probably knows this 2 years on, but for people visiting the answer is that the cmdlet doesn't know about unsupported syntax - it just passes them down to the PS Provider subsystem - wildcard behaviour for the filesystem PS Provider is different from the registry provider and from the ActiveDirectory provider, etc. And I suspect that's also why it's "flaky as hell" - because the filesystem wildcards are backwards compatible to Windows 3 or MS-DOS era. It's also why the docs can't say much but "qualifies the path" because it depends on the PSProvider implementation. – TessellatingHeckler Mar 01 '18 at 09:09
  • @TessellatingHeckler flaky as hell and probably much more efficient - especially if you have a folder with many files and you want to filter most of them out. – Ohad Schneider Oct 24 '18 at 16:39
  • I am discovering this 7 years later and this bug still exists -_- – user206904 Dec 04 '22 at 15:08
  • 1
    @user206904 Yes, even in PS v7.3 I still see unexpected behavior. – Bacon Bits Dec 06 '22 at 14:29
3

Note that -Filter does not seem to have this issue. This works:

$files = Get-ChildItem -LiteralPath $path -Force -Recurse -Filter *.txt

Filter is also more efficient, because it is used by the underlying provider (as opposed to Include which is applied by PowerShell itself, much like a where clause added by your code).

However Filter only accepts one pattern parameter, whereas Include supports multiple patterns.

Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
2

I think this is a regression. I submitted it as v5 regression: Get-ChildItem -LiteralPath -Recurse ignores -Include and gets all items

Roman Kuzmin
  • 40,627
  • 11
  • 95
  • 117