How can I exclude multiple folders using Get-ChildItem -exclude?

大兔子大兔子 提交于 2019-12-17 06:06:14

问题


I need to generate a configuration file for our Pro/Engineer CAD system. I need a recursive list of the folders from a particular drive on our server. However I need to EXCLUDE any folder with 'ARCHIVE' in it including the various different cases.

I've written the following which works except it doesn't exclude the folders !!

$folder = "T:\Drawings\Design\*"
$raw_txt = "T:\Design Projects\Design_Admin\PowerShell\raw.txt"
$search_pro = "T:\Design Projects\Design_Admin\PowerShell\search.pro"
$archive = *archive*,*Archive*,*ARCHIVE*

Get-ChildItem -Path $folder -Exclude $archive -Recurse  | where {$_.Attributes -match 'Directory'}  | ForEach-Object {$_.FullName} > $search_pro   

回答1:


I'd do it like this:

Get-ChildItem -Path $folder -r  | 
          ? { $_.PsIsContainer -and $_.FullName -notmatch 'archive' }



回答2:


I apologize if this answer seems like duplication of previous answers. I just wanted to show an updated (tested through POSH 5.0) way of solving this. The previous answers were pre-3.0 and not as efficient as modern solutions.

The documentation isn't clear on this, but Get-ChildItem -Recurse -Exclude only matches exclusion on the leaf (Split-Path $_.FullName -Leaf), not the parent path (Split-Path $_.FullName -Parent). Matching the exclusion will just remove the item with the matching leaf; Get-ChildItem will still recurse into that leaf.

In POSH 1.0 or 2.0

Get-ChildItem -Path $folder -Recurse  | 
          ? { $_.PsIsContainer -and $_.FullName -inotmatch 'archive' }

Note: Same answer as @CB.

In POSH 3.0+

Get-ChildItem -Path $folder -Directory -Recurse  | 
          ? { $_.FullName -inotmatch 'archive' }

Note: Updated answer from @CB.

Multiple Excludes

This specifically targets directories while excluding leafs with the Exclude parameter, and parents with the ilike (case-insensitive like) comparison:

#Requires -Version 3.0
[string[]]$Paths = @('C:\Temp', 'D:\Temp')
[string[]]$Excludes = @('*archive*', '*Archive*', '*ARCHIVE*', '*archival*')

$files = Get-ChildItem $Paths -Directory -Recurse -Exclude $Excludes | %{ 
    $allowed = $true
    foreach ($exclude in $Excludes) { 
        if ((Split-Path $_.FullName -Parent) -ilike $exclude) { 
            $allowed = $false
            break
        }
    }
    if ($allowed) {
        $_
    }
}

Note: If you want your $Excludes to be case-sensitive, there are two steps:

  1. Remove the Exclude parameter from Get-ChildItem.
  2. Change the first if condition to:
    • if ($_.FullName -clike $exclude) {

Note: This code has redundancy that I would never implement in production. You should simplify this quite a bit to fit your exact needs. It serves well as a verbose example.




回答3:


My KISS approach to skip some folders is chaining Get-ChildItem calls. This excludes root level folders but not deeper level folders if that is what you want.

Get-ChildItem -Exclude folder1,folder2 | Get-ChildItem -Recurse | ...
  • Start excluding folders you don't want
  • Then do the recursive search with non desired folders excluded.

What I like from this approach is that it is simple and easy to remember. If you don't want to mix folders and files in the first search a filter would be needed.




回答4:


The exclusion pattern should be case-insensitive, so you shouldn't have to specify every case for the exclusion.

That said, the -Exclude parameter accepts an array of strings, so as long as you define $archive as such, you should be set.

$archive = ("*archive*","*Archive*","*ARCHIVE*");

You also should drop the trailing asterisk from $folder - since you're specifying -recurse, you should only need to give the top-level folder.

$folder = "T:\Drawings\Design\"

Fully revised script. This also changes how you detect whether you've found a directory, and skips the Foreach-Object because you can just pull the property directly & dump it all to the file.

$folder = "T:\Drawings\Design\";
$raw_txt = "T:\Design Projects\Design_Admin\PowerShell\raw.txt";
$search_pro = "T:\Design Projects\Design_Admin\PowerShell\search.pro";
$archive = ("*archive*","*Archive*","*ARCHIVE*");

Get-ChildItem -Path $folder -Exclude $archive -Recurse  | where {$_.PSIsContainer}  | select-Object -expandproperty FullName |out-file $search_pro 



回答5:


I know this is quite old - but searching for an easy solution, I stumbled over this thread... If I got the question right, you were looking for a way to list more than one directory using Get-ChildItem. There seems to be a much easier way using powershell 5.0 - example

Get-ChildItem -Path D:\ -Directory -Name -Exclude tmp,music
   chaos
   docs
   downloads
   games
   pics
   videos

Without the -Exclude clause, tmp and music would still be in that list. If you don't use -Name the -Exclude clause won't work, because of the detailed output of Get-ChildItem. Hope this helps some people that are looking for an easy way to list all directory names without certain ones...

Cheers lil




回答6:


VertigoRay, in his answer, explained that -Exclude works only at the leaf level of a path (for a file the filename with path stripped out; for a sub-directory the directory name with path stripped out). So it looks like -Exclude cannot be used to specify a directory (eg "bin") and exclude all the files and sub-directories within that directory.

Here's a function to exclude files and sub-directories of one or more directories (I know this is not directly answering the question but I thought it might be useful in getting around the limitations of -Exclude):

$rootFolderPath = 'C:\Temp\Test'
$excludeDirectories = ("bin", "obj");

function Exclude-Directories
{
    process
    {
        $allowThrough = $true
        foreach ($directoryToExclude in $excludeDirectories)
        {
            $directoryText = "*\" + $directoryToExclude
            $childText = "*\" + $directoryToExclude + "\*"
            if (($_.FullName -Like $directoryText -And $_.PsIsContainer) `
                -Or $_.FullName -Like $childText)
            {
                $allowThrough = $false
                break
            }
        }
        if ($allowThrough)
        {
            return $_
        }
    }
}

Clear-Host

Get-ChildItem $rootFolderPath -Recurse `
    | Exclude-Directories

For a directory tree:

C:\Temp\Test\
|
├╴SomeFolder\
|  |
|  └╴bin (file without extension)
|
└╴MyApplication\
  |
  ├╴BinFile.txt
  ├╴FileA.txt
  ├╴FileB.txt
  |
  └╴bin\
    |
    └╴Debug\
      |
      └╴SomeFile.txt

The result is:

C:\Temp\Test\
|
├╴SomeFolder\
|  |
|  └╴bin (file without extension)
|
└╴MyApplication\
  |
  ├╴BinFile.txt
  ├╴FileA.txt
  └╴FileB.txt

It excludes the bin\ sub-folder and all its contents but does not exclude files Bin.txt or bin (file named "bin" without an extension).




回答7:


You can exclude like this, the regex 'or' symbol, assuming a file you want doesn't have the same name as a folder you're excluding.

$exclude = 'dir1|dir2|dir3'
ls -r | where { $_.fullname -notmatch $exclude }

ls -r -dir | where fullname -notmatch 'dir1|dir2|dir3'



回答8:


Based on @NN_ comment on @Guillem answer, I came up with the below code. This allows you to exclude folders and files:

Get-ChildItem -Exclude 'folder-to-exclude','second-folder-exclude' |
foreach {
    Get-ChildItem -Path $_ -Exclude 'files-to-exclude','*.zip','*.mdmp','*.out*','*.log' -Recurse |
    Select-String -Pattern 'string-to-look-for' -List
}



回答9:


may be in your case you could reach this with the following:

    mv excluded_dir ..\
    ls -R 
    mv ..\excluded_dir .


来源:https://stackoverflow.com/questions/15294836/how-can-i-exclude-multiple-folders-using-get-childitem-exclude

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!