Using Get-ChildItem -Exclude or -Include returns nothing
To summarize and complement gravity's and Brian Reynolds's helpful answers:
There are two distinct problems with your approach:
-
Targeting
C:
probably doesn't (always) do what you want, becauseC:
refers to whatever happens to be the current location (working dir.) on drive C: at the moment.- To target the root folder of drive C:, you must use
C:\
, which I'll assume is what you meant in the remainder of this answer.
- To target the root folder of drive C:, you must use
-
Using the
-Exclude
(and also-Include
) parameter with neither-Recurse
nor a-Path
value ending in\*
often yields NO results. Unexpected? Indeed - see below for more.- Thus,
Get-Item -Path C:\* -Exclude *.txt
- note the switch fromGet-ChildItem
toGet-Item
and the*
afterC:\
- is needed to make your command work for the items located directly inC:\
only.
- Thus,
Background information:
Using the provider-native -Filter
parameter is generally preferable to -Include
, because:
-
it is much faster than
-Include
due to the provider itself performing the filtering at the source, as opposed to letting PowerShell apply the filter later, after all objects have been received. -
it doesn't require you to switch to
Get-Item
and append\*
to the-Path
parameter value.-
Get-ChildItem -Path C:\ -Filter *.txt
works fine for matching all*.txt
files in the root directory of C:, for instance.
-
That said, there are caveats:
-
The wildcard pattern language supported by
-Filter
has fewer features than PowerShell's - notably, it doesn't support character sets/ranges such as[0-9]
- may unexpectedly match short (8.3) filenames, and has other legacy quirks - see this well-researched answer for the gory details. -
-Filter
supports only a single pattern, whereas-Include
supports multiple ones (an array of patterns).
Unfortunately, -Filter
is always a positive (inclusionary) filter and therefore cannot be used to provide the functionality of -Exclude
.
The implementation of -Include
/ -Exclude
with Get-ChildItem
is unintuitive and has pitfalls:
Side note: if you only use one -Include
pattern (as opposed to -Exclude
), it's easier to append the pattern directly to the -Path
argument; e.g.: Get-ChildItem C:\*.txt
tl;dr:
To get predictable behavior with -Include
/ -Exclude
if you're not also using -Recurse
(if you are using -Recurse
this workaround is not needed):
# IMPORTANT: Workaround isn't needed if you're using -Recurse.
# * "\*" was appended to the input path
# * Get-*ChildItem* was switched to Get-*Item*
Get-Item C:\path\to\* -Include ...
Get-Item C:\path\to\* -Exclude ...
In PowerShell (Core) v7+, if your input paths are literal ones, you can alternatively use Get-ChildItem
with -LiteralPath
rather than (possibly positionally implied) -Path
(use .
for the current dir.):
# IMPORTANT: Works in PowerShell (Core) only.
# Note the use of -LiteralPath.
Get-ChildItem -LiteralPath C:\path\to -Include ...
Get-ChildItem -Literalpath C:\path\to -Exclude ...
-
There's an outright bug in Windows PowerShell where, when
-LiteralPath
is used,-Include
/-Exclude
are quietly ignored. This has been fixed in PowerShell (Core) as of (at least) v7.0 (and it's fair to assume that it will not be fixed in Windows PowerShell, which will only receive critical fixes going forward). -
-Include
and-Exclude
do not work as one would intuitively expect, which is the subject of GitHub issue #3304:-
-Include
and-Exclude
modify the leaf (last) path component of the-Path
argument, i.e. file or directory names in the case of file-system paths. -
That means that the patterns are first applied to the leaf component of the specified folder path itself, before getting applied to the child items, if at all.
-
If the input path doesn't end in
\*
and-Recurse
is not specified, the implications are as follows:-
-Include
: If the input path's last path component does not match the-Include
pattern(s), the input path itself is excluded (not included), and the path's child items are never looked at - nothing is output. -
-Exclude
: Analogously, if the input path's last path component does match the-Exclude
pattern(s), the input path itself is excluded, and the path's child items are never looked at - nothing is output.-
Targeting a root directory - e.g.,
Get-ChildItem -Path C:\ -Exclude Windows
) appears to be broken altogether as of v7.0: it either produces no output at all, or fails on Unix-like platforms, both with-Include
and-Exclude
, irrespective of the patterns used - see GitHub issue #11649.
-
Targeting a root directory - e.g.,
-
As stated, the problem doesn't surface if
-Recurse
is used, because that forces descending into the input path's subtree, even if the input path itself is not included / excluded.
-
-
-
Unless
-Recurse
is needed, the only way to get expected behavior is to replaceGet-ChildItem C:\path\to -Include / -Exclude
withGet-Item C:\path\to\* -Include / -Exclude
- note the use ofGet-Item
instead ofGet-ChildItem
, and that\*
was appended to the-Path
argument.- By contrast, if you use
Get-ChildItem *
in combination with-Exclude
and there are directories among the non-excluded item,Get-ChildItem
will unexpectedly output their contents instead; this does not happen with-Include
and generally doesn't happen with subdirectory matches by a wildcard expression (-Path
argument and/or-Filter
argument).
- By contrast, if you use
-
A summary of the problems as of PowerShell 7.2:
-
GitHub issue #3304 (discussed above): counterintuitive application of
-Include
/-Exclude
patterns only to the input themselves rather than to their children. -
GitHub issue #11649:
Get-ChildItem -Path <rootPath> -Exclude <anyPattern>
unexpectedly produces no output (even though nothing should be excluded, given that the exclusion pattern is normally applied to the input paths, such as/
orc:\
). -
GitHub issue #9126: -Include / -Exclude unexpectedly follow symlinks when -Recurse is used.
-
GitHub issue #8662: performance problem:
-Include
/-Exclude
are slower(!) than after-the-fact filtering withWhere-Object
. -
A related feature request is GitHub issue #15159, which suggests introducing the ability to exclude subfolder subtrees (as opposed to just excluding the items matching the patterns themselves, but not their children), with a new parameter such as
-ExcludeSubtree
.
-
Examples: problematic uses of -Include
/ -Exclude
Note: To make all commands below work as one would intuitively expect, replace Get-ChildItem C:\Windows
with Get-Item C:\Windows\*
- note the use of a different cmdlet, Get-Item
, and the appended \*
.
# HAPPENS TO WORK, BUT IS NOT ROBUST:
# Matches all w* items *inside* C:\Windows, but
# ONLY because w* happens to match 'Windows' - the last input
# path component - too.
Get-ChildItem C:\Windows -Include w*
# HAPPENS TO WORK, BUT IS NOT ROBUST:
# Matches all items whose names *don't* start with a-v *inside* C:\Windows, but
# ONLY because [a-v]* happens not to exclude 'Windows' - the last input
# path component - too.
Get-ChildItem C:\Windows -Exclude [a-v]*
# OUTPUTS NOTHING:
# Because t* doesn't match 'Windows', the child items of
# 'C:\Windows' are not considered.
Get-ChildItem C:\Windows -Include t*
# OUTPUTS NOTHING:
# Because w* matches 'Windows', it is excluded, and
# the child items of 'C:\Windows' are not considered.
Get-ChildItem C:\Windows -Exclude w*
Get-ChildItem -Path "C:\*" -Include "*.txt"
This example, of how -Include
should work, will give you the results you were expecting. Note that I provided a wildcard in the path parameter as well, to explicitly define the path as "any file in the root C:" as opposed to "C:" itself.
Source: https://technet.microsoft.com/library/hh849800.aspx
Example 3 from this link, in case it goes defunct (note the wildcard in path here, as well):
C:\> Get-ChildItem –Path "C:\Windows\Logs\*" -Include "*.txt" -Exclude "A*"
Using 'C:' with no slash after it is the reason you're not getting the results you want. This is being interpreted as a relative path to the current directory instead of the root of the C drive. (See: Path with no slash after drive letter and colon - what does it point to?)
If you use 'C:\' instead it should work as expected.
Edit: My mistake; I was responding specifically to the examples which only use '-exclude'.