67

我需要为我们的 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   
4

18 回答 18

61

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

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

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

于 2017-02-02T16:21:58.793 回答
52

我会这样做:

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

请注意,-notmatch接受正则表达式:

https://docs.microsoft.com/powershell/module/microsoft.powershell.core/where-object#parameters

于 2013-03-08T13:31:25.893 回答
48

如果这个答案似乎与以前的答案重复,我深表歉意。我只是想展示一个更新的(通过 POSH 5.0 测试)解决这个问题的方法。之前的答案是 3.0 之前的版本,不如现代解决方案高效。

文档对此并不清楚,但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' }

注意:与 @CB相同的答案。

在 POSH 3.0+

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

注意: 来自@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参数Get-ChildItem
  2. if将第一个条件 更改为:
    • if ($_.FullName -clike $exclude) {

注意:此代码具有我永远不会在生产中实现的冗余。您应该稍微简化一下以适应您的确切需求。它很好地作为一个详细的例子。

于 2016-03-14T16:56:28.523 回答
15

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

也就是说,-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 
于 2013-03-08T13:33:01.983 回答
8

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

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

如果没有 -Exclude 子句,tmp 和 music 仍会在该列表中。如果您不使用 -Name,则 -Exclude 子句将不起作用,因为 Get-ChildItem 的详细输出。希望这可以帮助一些正在寻找一种简单方法来列出所有目录名称而不列出某些目录名称的人。

于 2016-10-17T17:46:59.393 回答
3

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

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

ls -r -dir | where fullname -notmatch 'dir1|dir2|dir3'
于 2017-08-08T19:20:37.950 回答
2

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 without extension)
|
└╴MyApplication\
  |
  ├╴BinFile.txt
  ├╴FileA.txt
  ├╴FileB.txt
  |
  └╴bin\
    |
    └╴Debug\
      |
      └╴SomeFile.txt

结果是:

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

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

于 2016-11-02T22:30:07.813 回答
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 | ....
于 2020-09-02T20:41:46.647 回答
1

基于对@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
}
于 2019-10-28T18:58:15.113 回答
1

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

$j = "Somepath"
$files = Get-ChildItem -Path $j -Include '*.xlsx','*.zip' -Recurse -ErrorAction SilentlyContinue –File | ? {$_.Directory -notlike "$j\donotwantfoldername"}
于 2020-12-03T23:57:34.757 回答
1

我是这样做的:

Get-ChildItem -Recurse -Name | ? {$_ -notmatch 'node_modules' }

这会递归地列出每个文件的完整路径,这些文件的路径中不包含 node_modules。您显然应该使用要过滤的任何字符串更改 node_modules

于 2022-01-11T15:14:03.360 回答
0

这是使用远程服务器的另一种方法。这里的任务是获取文件夹列表,但不包括远程服务器 C: 驱动器上的一些众所周知的文件夹。最后一个变量 $AllFolders 包含结果。

$Server          = "<ServerName>"
$TopFolder       = "\\$Server\C$"    
$Exclude         = @("*Inetpub*")
$Exclude        += "*Program Files*"
$Exclude        += "*Program Files (x86)*"
$Exclude        += "*Windows*"

$ServerFolders   = Get-ChildItem -Path $TopFolder -Exclude $Exclude | where {$_.PSIsContainer} 
ForEach ($ServerFolder in $ServerFolders)
{
 $CurrentFolders = Get-ChildItem -path $ServerFolder -recurse | Where-Object { $_.PSIsContainer } 
 $AllFolders     = $AllFolders + $CurrentFolders
}
于 2021-10-15T19:28:39.080 回答
0

我想要一个不涉及循环遍历每个项目并执行ifs 的解决方案。这是一个解决方案,它只是一个简单的递归函数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)
    }
}
于 2020-04-11T17:55:35.883 回答
0

我认为最简单的形式。对全名使用 -NotMatch。是的,它需要最新版本的 PowerShell,因为我使用 -Directory。

$folder = "T:\Drawings\Design\*"
$search_pro = "T:\Design Projects\Design_Admin\PowerShell\search.pro"
$archive = 'archive'

Get-ChildItem -Path $folder -Directory | Where-Object Fullname -NotMatch $archive | Select-Object Fullname | Out-File $search_pro
于 2022-01-07T23:58:19.190 回答
0

我需要排除特定路径,而不仅仅是树中任何位置的同名目录,所以我建立在Jason Brower 的答案上以匹配目录路径而不是它们的名称。

Get-Childitem filespec -Recurse | Where-Object {$_ -excludecondition}这样的解决方案确实有效,但他们在解雇之前不必要地查看排除的文件夹,这可能会变得昂贵。(使用管道:“左过滤,右处理”)

$strSearchPath = 'D:\Project'
# Files to search for
$arFilePatterns = @(
    '*.ps?',
    '*.cmd'
)

# Directories to skip
# Example: you got 'Archive', 'Archive.old', 'Archive.bak' and want to include only 'Archive' in the search

# (think) exact matches
$arSkipDirs = @(
    'D:\Project\Archive.old',
    'D:\Project\Archive.bak'
)
# (think) wildcard to the right
<#
$arSkipDirs = @(
    'D:\Project\Archive.'
)
#>

Function ListDirsSkipSome ($strPath, $strExcludeRegEx) {
    Get-ChildItem -Path $strPath -Directory | 
    ForEach-Object {
        if ($_.FullName -inotmatch $strExcludeRegEx) {
            # recurse down the tree
            ListDirsSkipSome $_.FullName $strExcludeRegEx
            return $_.FullName
        }
    }
}

#Build a regex using array of excludes
# exact matches
$strRegEx = '^{0}$' -f (($arSkipDirs | ForEach-Object { [regex]::Escape($_) }) -join ('$|^'))
# wildcards to the right
#$strRegEx = '^{0}' -f (($arSkipDirs | ForEach-Object { [regex]::Escape($_) }) -join ('|^'))

# include root of search path
$arSearchDirs = @($strSearchPath)
# add list of directories excluding some
$arSearchDirs += ListDirsSkipSome $strSearchPath $strRegEx

# save current directory
$strPWD = (Get-Location).Path

# find files in listed dirs
# set type in case there is only 1 result
[array]$arSearchResult = $arSearchDirs |
ForEach-Object {
    # dive into each directory
    Set-Location -Path $_
    # list files matching patterns
    (Get-ChildItem -File -Path $arFilePatterns).FullName
}

# return to previous directory
Set-Location -Path $strPWD

$arSearchResult

于 2022-01-15T02:49:08.127 回答
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
于 2020-01-02T03:51:01.397 回答
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
于 2021-04-01T14:14:33.317 回答
-3

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

    mv excluded_dir ..\
    ls -R 
    mv ..\excluded_dir .
于 2017-01-13T10:35:36.160 回答