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

我需要为我们的 Pro/Engineering CAD 系统生成一个配置文件。我需要我们服务器上某个驱动器的文件夹的递归列表。然而,我需要排除任何文件夹与’档案’在其中包括各种不同的情况下。

我已经写了下面的工作,除了它不排除的文件夹! !

$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
196000 次浏览

我会这样做:

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

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

Https://learn.microsoft.com/powershell/module/microsoft.powershell.core/where-object#parameters

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

也就是说,-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

如果这个答案看起来像是之前答案的重复,我道歉。我只是想展示一个更新(通过 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' }

注: < em > 同样的 答案是@CB

在 POSH 3.0 + 中

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

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

注意: 这段代码有冗余,我永远不会在生产环境中实现。您应该将这个过程简化一些,以满足您的确切需要。它是一个很好的详细示例。

我知道这是相当古老的-但寻找一个简单的解决方案,我绊倒了这个线程..。 如果我的问题是正确的,您正在寻找一种使用 Get-ChildItem 列出多个目录的方法。使用 Powershell 5.0似乎有一个更简单的方法——示例

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

如果没有排除子句,tmp 和 music 仍然会在那个列表中。如果不使用-Name-Excluse 子句,那么将无法工作,因为 Get-ChildItem 的详细输出。 希望这可以帮助一些人,他们正在寻找一种简单的方法来列出所有目录名,而不需要特定的名称。

VertigoRay 在他的回答中解释说-Excluse 只能在路径的叶级上工作(对于一个文件,去掉了路径的文件名; 对于一个子目录,去掉了路径的目录名)。因此,看起来-Excluse 不能用于指定一个目录(例如“ bin”)并排除该目录中的所有文件和子目录。

这里有一个函数用于排除一个或多个目录的文件和子目录(我知道这不能直接回答这个问题,但我认为它可能有助于绕过-Excluse 的限制) :

$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”但没有扩展名的文件)。

也许在你的情况下,你可以通过以下方式达到这一点:

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

我跳过一些文件夹的 亲一个方法是链接 Get-ChildItem调用。这将排除根级别文件夹,但不排除更深级别文件夹(如果需要的话)。

Get-ChildItem -Exclude folder1,folder2 | Get-ChildItem -Recurse | ...
  • 启动不需要的 不包括文件夹
  • 然后排除不需要的文件夹进行 递归的搜索。

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

您可以像这样排除 regex‘ or’符号,假设您想要的文件与您排除的文件夹的名称不同。

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


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

基于@NN _ comments on@Guillem 的回答,我想出了以下代码。这允许您排除文件夹和文件:

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
}
#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

我想要一个解决方案,不涉及循环每一个项目和做 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)
}
}

对我来说,最简单的短语是这样的:

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

你也可以在一个简单的声明中做到这一点:

$j = "Somepath"
$files = Get-ChildItem -Path $j -Include '*.xlsx','*.zip' -Recurse -ErrorAction SilentlyContinue –File | ? {$_.Directory -notlike "$j\donotwantfoldername"}
$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

下面是使用远程服务器的另一种方法。这里的任务是获取文件夹列表,但排除远程服务器 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
}

我认为是最简单的形式。使用-全名上的 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

我是这么做的:

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

这将递归地列出每个不在其路径中包含 node _ module 的文件的完整路径。 显然,应该使用要筛选的任何字符串更改 node _ module

我需要排除特定的路径,而不仅仅是树中任何地方的同名目录,所以我构建在 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