如何使用Get-ChildItem -exclude排除多个文件夹?

时间:2013-03-08 13:15:20

标签: list powershell directory

我需要为我们的Pro / Engineer CAD系统生成配置文件。我需要一个来自我们服务器上特定驱动器的文件夹的递归列表。但是我需要在其中排除任何带有“ARCHIVE”的文件夹,包括各种不同的情况。

我写了以下哪些有效但除了它不排除文件夹!!

$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   

14 个答案:

答案 0 :(得分:32)

我会这样做:

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

答案 1 :(得分:25)

如果这个答案看起来像以前的答案重复,我道歉。我只是想展示一个更新的(通过POSH 5.0测试)解决这个问题的方法。之前的答案是3.0之前的,并不像现代解决方案那样有效。

The documentation对此并不清楚,但Get-ChildItem -Recurse -Exclude仅匹配叶子上的排除(Split-Path $_.FullName -Leaf),而不是父路径(Split-Path $_.FullName -Parent)。匹配排除将只删除具有匹配叶子的项目; Get-ChildItem仍然会进入那片叶子。

在POSH 1.0或2.0

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

注意: 相同answer as @CB

在POSH 3.0 +

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

注意: 已更新answer from @CB

多个排除

这专门针对目录,同时排除具有Exclude参数的叶子,以及具有ilike(不区分大小写的)比较的父级:

#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) {
        $_
    }
}

注意:如果您希望$Excludes区分大小写,则有两个步骤:

  1. Exclude
  2. 中删除Get-ChildItem参数
  3. 将第一个if条件更改为:
    • if ($_.FullName -clike $exclude) {
  4. 注意:此代码具有我永远不会在生产中实现的冗余。您应该简化这一点以满足您的确切需求。它可以作为一个冗长的例子。

答案 2 :(得分:22)

我的 KISS 跳过某些文件夹的方法是链接Get-ChildItem次来电。如果你想要的话,这将排除根级文件夹,但不包括更深层次的文件夹。

Get-ChildItem -Exclude folder1,folder2 | Get-ChildItem -Recurse | ...
  • 开始排除您不想要的文件夹
  • 然后执行递归搜索,排除不需要的文件夹。

我喜欢这种方法,它简单易记。如果您不想在第一次搜索中混合文件夹和文件,则需要使用过滤器。

答案 3 :(得分:14)

排除模式应该不区分大小写,因此您不必指定排除的每个案例。

也就是说,-Exclude参数接受一个字符串数组,因此只要您定义$archive,就应该设置它。

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

您还应该从$folder删除尾随的星号 - 因为您指定了-recurse,所以您只需要提供顶级文件夹。

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

完全修改过的脚本。这也会改变您检测是否找到目录的方式,并跳过Foreach-Object,因为您可以直接提取该属性&将它全部转储到文件中。

$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 

答案 4 :(得分:5)

我知道这已经很老了 - 但是在寻找一个简单的解决方案时,我偶然发现了这个问题...... 如果我的问题是正确的,那么您正在寻找一种使用Get-ChildItem列出多个目录的方法。使用PowerShell 5.0似乎有一种更简单的方法 - 例如

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

如果没有-Exclude子句,tmp和音乐仍然会在该列表中。如果您不使用-Name,则由于Get-ChildItem的详细输出,-Exclude子句无法正常工作。 希望这有助于一些人在寻找一种简单的方法来列出所有目录名称而没有某些目录...

干杯 律

答案 5 :(得分:2)

对我来说,最简单的简短形式是:

#find web forms in my project except in compilation directories
(gci -recurse -path *.aspx,*.ascx).fullname -inotmatch '\\obj\\|\\bin\\'

如果您需要更复杂的逻辑,请使用过滤器:

  filter Filter-DirectoryBySomeLogic{
  
      param(
      [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
      $fsObject,
      [switch]$exclude
      )
          
      if($fsObject -is [System.IO.DirectoryInfo])
      {
          $additional_logic = $true ### replace additional logic here
  
          if($additional_logic){
              if(!$exclude){ return $fsObject }
          }
          elseif($exclude){ return $fsObject }
      }
          
  }
  
  gci -Directory -Recurse | Filter-DirectoryBySomeLogic | ....

答案 6 :(得分:1)

VertigoRay在他的回答中解释说,-Exclude仅适用于路径的叶级(对于文件,路径被剥离的文件名;对于子目录,路径被剥离的目录名)。所以看起来-Exclude不能用于指定目录(例如" bin")并排除该目录中的所有文件和子目录。

这里有一个排除一个或多个目录的文件和子目录的功能(我知道这不是直接回答问题,但我认为它可能有助于解决-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

对于目录树:

C:\Temp\Test\
|
|_SomeFolder\
|  |
|  |_bin (file)
|
|_MyApplication\
  |
  |_BinFile.txt
  |_FileA.txt
  |_FileB.txt
  |
  |_bin\
    |
    |_Debug\
      |
      |_SomeFile.txt

结果是:

C:\Temp\Test\
|
|_SomeFolder\
|  |
|  |_bin (file)
|
|_MyApplication\
  |
  |_BinFile.txt
  |_FileA.txt
  |_FileB.txt

它排除了bin \子文件夹及其所有内容,但不排除文件Bin.txt或bin(文件名为" bin"没有扩展名)。

答案 7 :(得分:0)

可能在您的情况下,您可以通过以下方式达到此目的:

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

答案 8 :(得分:0)

您可以像这样排除正则表达式'或'符号,假设您想要的文件与您要排除的文件夹名称相同。

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

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

答案 9 :(得分:0)

基于对@Guillem答案的@NN_评论,我想到了以下代码。这使您可以排除文件夹和文件:

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
}

答案 10 :(得分:0)

#For brevity, I didn't define a function.

#Place the directories you want to exclude in this array.
#Case insensitive and exact match. So 'archive' and
#'ArcHive' will match but 'BuildArchive' will not.
$noDirs = @('archive')

#Build a regex using array of excludes
$excRgx = '^{0}$' -f ($noDirs -join ('$|^'))

#Rather than use the gci -Recurse option, use a more
#performant approach by not processing the match(s) as
#soon as they are located.
$cmd = {
  Param([string]$Path)
  Get-ChildItem $Path -Directory |
  ForEach-Object {
    if ($_.Name -inotmatch $excRgx) {
      #Recurse back into the scriptblock
      Invoke-Command $cmd -ArgumentList $_.FullName;
      #If you want all directory info change to return $_
      return $_.FullName
    }
  }
}

#In this example, start with the current directory
$searchPath = .
#Start the Recursion
Invoke-Command $cmd -ArgumentList $searchPath

答案 11 :(得分:0)

我想要一个不涉及遍历每个项目并执行if的解决方案。这是一个仅基于Get-ChildItem的简单递归函数的解决方案。我们只是循环遍历目录。


function Get-RecurseItem {
    [Cmdletbinding()]
    param (
        [Parameter(ValueFromPipeline=$true)][string]$Path,
        [string[]]$Exclude = @(),
        [string]$Include = '*'
    )
    Get-ChildItem -Path (Join-Path $Path '*') -Exclude $Exclude -Directory | ForEach-Object {
        @(Get-ChildItem -Path (Join-Path $_ '*') -Include $Include -Exclude $Exclude -File) + ``
        @(Get-RecurseItem -Path $_ -Include $Include -Exclude $Exclude)
    }
}

答案 12 :(得分:0)

您也可以在单个语句中执行此操作:

[[k+[weights[i]] for k in j] for i,j in enumerate(points)]

答案 13 :(得分:0)

$CurrentPath = (Get-Location -PSProvider FileSystem).ProviderPath # Or your favorite path
$IncludeNames = "okFolder1", "okFolder2"  # Items names to search
$ExcludeNames = "koFolder1", "koFolder2"  # Items names not to search
$depth = 3                                # Max level of depth to search

$FoldersToRemove = Get-ChildItem .\ -include $IncludeNames -Recurse -Depth $depth 
-Attributes D                             # If you want only directories, change it as you desire
| ? { $_.fullname -inotmatch ($ExcludeNames -join '|') }  #case insensitive or use -cnotmatch for case sensitive comparison
| foreach {$_.fullname}                   # If you want to project only full path information of matches