使用Powershell的方法Get-Childitem时排除多个子文件夹

时间:2013-11-07 17:25:23

标签: powershell foreach

我拥有什么

以下工作代码列出了放置脚本的所有子文件夹中的所有文件 它仅包含某些文件类型,并排除某个文件夹中的所有文件。到目前为止一切顺利

$fileInclude = @("*.txt", "*.hgr", "*.dat")           
$folderExclude = "C:\folder2"    
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition

gci $scriptPath -recurse -include $fileFilter | Where {$_.FullName -notlike "$folderExclude*"} 

我的测试的文件结构如图所示

C:.
│   Myscript.ps1
│
├───folder1
│   │   file1.dat
│   │   file1.hgr
│   │   file1.txt
│   │
│   └───folder3
│           file3.dat
│           file3.hgr
│           file3.txt
│
└───folder2
        file3.dat
        file3.hgr
        file3.txt

我想要什么

现在我要替换第二行

$folderExclude = "C:\folder2"

有一个数组。后来有几十条路径。

$folderExclude = @(
        "C:\folder2", 
        "C:\folder1\folder3"    
        )

显然这不起作用,因为-notlike需要字符串而不是字符串数组。

我无法理解如何实现这一点。我想我需要一个for-each循环?

2 个答案:

答案 0 :(得分:6)

你也可以走这条路:

$exclude = @('c:\folder2*', 'c:\folder1\folder3'} 
gci | Where {$fn = $_.Fullname; ($exclude | Where {$fn -like $_}).count -eq 0}

如果您使用的是V4,则可以使用方便的新常用参数-PipelineVariable:

gci -pv fse | Where {($exclude | Where {$fse.FullName -like $_}).count -eq 0}

请注意,这种方法存在一个缺陷,即如果folder1包含名为folder3foobar的文件,则该文件将被排除。要解决此问题,您需要将排除术语修改为c:\ folder1 \ folder3 *,然后在与fse.FullName进行比较时,如果fse是目录而不是文件,则需要附加反斜杠。

这是另一种基于-match允许数组在左侧工作的方法:

 gci | Where {!($exclude -match [regex]::escape($_.Fullname))}

在这种情况下,如果其中一个目录与$ exclude数组的术语匹配,那么将会有输出并且被强制转换为true但后来被!反转。

答案 1 :(得分:1)

一种方法是从$ folderExclude构建一个与任何排除字符串匹配的正则表达式(使用交替),然后使用-notmatch而不是-notlike。

$folderExclude = @(
    "C:\folder2", 
    "C:\folder1\folder3"    
    )

[regex]$Exclude_regex = ‘(?i)^(‘ + (($folderExclude |foreach {[regex]::escape($_)}) –join “|”) + ‘)’

$fileInclude = @("*.txt", "*.hgr", "*.dat")           
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition

gci $scriptPath -recurse -include $fileFilter | Where {$_.FullName -notmatch $Exclude_regex}

编辑:这可能不像嵌套的where-object那样“Posh”,但它会快得多。