提取文件元数据时如何跳过指定子文件夹?
修改PowerShell脚本实现跳过指定子文件夹
你的脚本依赖robocopy扫描文件,而robocopy本身支持/XD参数排除目录,不需要用continue语句,直接扩展参数并修改命令即可解决问题。
具体修改步骤
1. 添加排除文件夹的参数
在函数的Param块中,新增ExcludeFolder参数,放在ExcludeFile参数下方:
[parameter(ParameterSetName='Exclude')] [string[]]$ExcludeFolder,
2. 修改robocopy命令构建逻辑
替换原脚本中构建robocopy命令的代码,同时处理文件排除和文件夹排除:
# 初始化基础robocopy命令 $Script = "robocopy \`"$item\`" NULL $Filter $params" # 添加文件排除参数 If ($PSBoundParameters['ExcludeFile']) { $Script += " /XF $($ExcludeFile -join ',')" } # 添加文件夹排除参数 If ($PSBoundParameters['ExcludeFolder']) { $Script += " /XD $($ExcludeFolder -join ',')" }
3. 修改后的完整脚本
Function Get-FolderItem { [cmdletbinding(DefaultParameterSetName='Filter')] Param ( [parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)] [Alias('FullName')] [string[]]$Path = $PWD, [parameter(ParameterSetName='Filter')] [string[]]$Filter = '*.*', [parameter(ParameterSetName='Exclude')] [string[]]$ExcludeFile, [parameter(ParameterSetName='Exclude')] [string[]]$ExcludeFolder, [parameter()] [int]$MaxAge, [parameter()] [int]$MinAge ) Begin { $params = New-Object System.Collections.Arraylist $params.AddRange(@("/L","/E","/NJH","/BYTES","/FP","/NC","/XJ","/R:0","/W:0","T:W","/UNILOG:c:\temp\test.txt")) If ($PSBoundParameters['MaxAge']) { $params.Add("/MaxAge:$MaxAge") | Out-Null } If ($PSBoundParameters['MinAge']) { $params.Add("/MinAge:$MinAge") | Out-Null } } Process { ForEach ($item in $Path) { Try { $item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop)) { Write-Warning ("{0} is not a directory and will be skipped" -f $item) Return } # 构建robocopy命令,同时处理文件和文件夹排除 $Script = "robocopy \`"$item\`" NULL $Filter $params" If ($PSBoundParameters['ExcludeFile']) { $Script += " /XF $($ExcludeFile -join ',')" } If ($PSBoundParameters['ExcludeFolder']) { $Script += " /XD $($ExcludeFolder -join ',')" } Write-Verbose ("Scanning {0}" -f $item) Invoke-Expression $Script | Out-Null get-content "c:\temp\test.txt" | ForEach { Try { If ($_.Trim() -match "^(?<Children>\d+)\s(?<FullName>.*)") { $object = New-Object PSObject -Property @{ FullName = $matches.FullName #Extension = $matches.fullname -replace '.*\.(.*)','$1' #FullPathLength = [int] $matches.FullName.Length #FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash #Created = ([System.IO.FileInfo] $matches.FullName).creationtime #Created = ([System.IO.FileInfo] "\\?\$($matches.FullName)").creationtime #LastWriteTime = ([System.IO.FileInfo] "\\?\$($matches.FullName)").LastWriteTime #Characters = (Get-Content -LiteralPath "\\?\$($matches.FullName)" | Measure-Object -ignorewhitespace -Character).Characters #Size = ([System.IO.FileInfo] "\\?\$($matches.FullName)").length #Access = ((Get-Acl -LiteralPath "\\?\$($matches.FullName)") |Select -Expand AccessToString)-replace '[\r\n]',' ' #$permission = (Get-Acl $Folder).Access | ?{$_.IdentityReference -match $User} | Select IdentityReference,FileSystemRights #Owner = (Get-ACL $matches.Fullname).Owner } $object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo') Write-Output $object } Else { Write-Verbose ("Not matched: {0}" -f $_) } } Catch { Write-Warning ("{0}" -f $_.Exception.Message) Return } } } Catch { Write-Warning ("{0}" -f $_.Exception.Message) Return } } } } # 调用示例:跳过指定子文件夹 $a = Get-FolderItem "C:\Temp\ExtractMetadata" -ExcludeFolder "C:\Temp\ExtractMetadata\Folder_to_Skip" | Export-Csv -Path C:\Temp\2023-12-12Testing.csv -Encoding Unicode
调用说明
现在可以直接使用-ExcludeFolder参数指定要跳过的子文件夹路径,支持多个路径(用逗号分隔):
# 跳过单个文件夹 Get-FolderItem "C:\Temp\ExtractMetadata" -ExcludeFolder "C:\Temp\ExtractMetadata\Folder_to_Skip" # 跳过多个文件夹 Get-FolderItem "C:\Temp\ExtractMetadata" -ExcludeFolder "C:\Temp\ExtractMetadata\Folder1","C:\Temp\ExtractMetadata\Folder2"
原方法失效原因
- 用
-ExcludeFile指定文件夹:/XF参数仅对文件生效,无法排除目录,所以该方法无效。 - 用
-Filter指定文件夹下的文件:robocopy的Filter参数是匹配文件名,而非完整路径,所以路径格式的过滤条件无法匹配任何文件,导致输出为空。
内容的提问来源于stack exchange,提问作者oymonk
相关产品推荐
相关产品推荐

