Using Get-ChildItem -Exclude or -Include returns nothing

前端 未结 4 1886
醉话见心
醉话见心 2020-12-03 12:12

I have a list in my C: directory that has many files. If I try to run an -Exclude on it, I get no returns. Same with -Include. If I use filter it returns what I expected to

相关标签:
4条回答
  • 2020-12-03 12:45
    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*"
    
    0 讨论(0)
  • 2020-12-03 12:46

    This seems to be a bug (because the string version of the parent properties is empty string?). With subdirectories, it works fine:

    get-childitem c:\windows -directory -exclude *.dll
    

    You can specify the root directory in a different way, and get a strange error message:

    get-childitem Microsoft.PowerShell.Core\FileSystem::C:\ -exclude *.txt
    
    get-childitem : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
    At line:1 char:1
    + get-childitem Microsoft.PowerShell.Core\FileSystem::C:\ -exclude wind ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], PSArgumentException
        + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.GetChildItemCommand
    

    Or, in osx:

    get-childitem / -directory -exclude *.txt
    
    get-childitem : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
    At line:1 char:1
    + get-childitem / -directory -exclude var
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], PSArgumentException
    + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.GetChildItemCommand
    

    This is a workaround for powershell 6 and above:

    get-item c:\ | get-childitem -exclude *.txt
    
    0 讨论(0)
  • 2020-12-03 12:53

    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'.

    0 讨论(0)
  • 2020-12-03 13:04

    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, because C: 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.
    • 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 from Get-ChildItem to Get-Item and the * after C:\ - is needed to make your command work for the items located directly in C:\ only.

    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 and may unexpectedly match short (8.3) filenames - 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, use the following - unless you also use -Recurse, in which case this workaround isn't needed:

    # IMPORTANT: Note the appended "\*" and the switch from
    # Get-*ChildItem* to Get-*Item*
    Get-Item C:\path\to\* -Include ...
    Get-Item C:\path\to\* -Exclude ...
    

    • -Include and -Exclude do not work as one would intuitively expect:

      • -Include and -Exclude modify the leaf (last) path component of the -Path argument.

      • 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 this GitHub issue.
      • 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 replace
      Get-ChildItem C:\path\to -Include / -Exclude with
      Get-Item C:\path\to\* -Include / -Exclude - note the use of Get-Item instead of Get-ChildItem, and that \* was appended to the -Path argument.

      • By contrast, if you use Get-ChildItem and there are directories among the matches, Get-ChildItem will output their contents instead.
    • With -LiteralPath rather than -Path, -Include and -Exclude are quietly ignored - they have no effect whatsoever.


    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*
    
    0 讨论(0)
提交回复
热议问题