PowerShell中Get-ChildItem搜索网络共享文件过慢求优化
优化网络共享文件夹PDF搜索的PowerShell方案
我花了一周时间(参考Stack Overflow)编写了一段PowerShell代码,用于按名称搜索PDF文件。代码在本地C:\temp文件夹测试时表现良好,但在包含15万+文件的网络共享文件夹(路径\\networkshare)中执行时,Get-ChildItem的搜索速度极慢,现寻求更高效的实现方案。
原代码及运行示例
原代码
$fileName = Read-Host -Prompt 'Enter a File Name' # Set the path to the folder you want to search $folderPath = '\\networkshare' if ($pdfFile = Get-ChildItem -Path $folderPath -Filter "*$fileName*.pdf" -File -Recurse ) { & { for ($i = 0; $i -lt $pdfFile.Count; $i++) { [pscustomobject]@{ $('#' + (' ' * $pdfFile.Count.Length)) = $i + 1 PDFName = '{0}' -f $pdfFile[$i].BaseName Created = '{0}' -f $pdfFile[$i].CreationTime } } } | Out-String -Stream $selection = (Read-Host -Prompt 'Enter PDF(s) to open') -split ',' | %'Trim' foreach ($selected in $selection) { $pdf = $pdfFile[$selected - 1] Start-Process -FilePath "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" $pdf.FullName Write-Host $pdf pause 10 } } else { Write-Host -Object "No file with name `"$fileName`" found." }
代码功能与运行示例
代码功能:提示用户输入要搜索的文件名(仅匹配PDF文件),返回匹配结果后允许用户选择打开指定文件。
示例运行效果:
输入文件名:1234 # PDFName Created -- ------- ------- 1 TK1234 12/14/2022 6:19:45 AM 2 TK5467-5001234215 12/24/2022 10:57:36 AM
高效优化方案
优化后代码
$fileName = Read-Host -Prompt 'Enter a File Name' $folderPath = '\\networkshare' $searchPattern = "*$fileName*.pdf" # 使用.NET流式API高效搜索网络共享文件 $pdfFiles = [System.IO.Directory]::EnumerateFiles($folderPath, $searchPattern, [System.IO.SearchOption]::AllDirectories) | ForEach-Object { $file = Get-Item $_ [PSCustomObject]@{ FullName = $file.FullName BaseName = $file.BaseName CreationTime = $file.CreationTime } } if ($pdfFiles) { # 格式化输出搜索结果 $pdfFiles | ForEach-Object -Begin { $index = 1 } -Process { [PSCustomObject]@{ '#' = $index++ PDFName = $_.BaseName Created = $_.CreationTime.ToString() } } | Format-Table -AutoSize | Out-String -Stream # 处理用户选择并打开文件 $selection = (Read-Host -Prompt 'Enter PDF(s) to open') -split ',' | ForEach-Object { $_.Trim() } foreach ($selected in $selection) { if ($selected -match '^\d+$' -and $selected -ge 1 -and $selected -le $pdfFiles.Count) { $targetFile = $pdfFiles[$selected - 1] Start-Process -FilePath "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" -ArgumentList $targetFile.FullName Write-Host "Opening: $($targetFile.BaseName)" Start-Sleep -Seconds 10 } else { Write-Host "Invalid selection: $selected" } } } else { Write-Host "No file with name `"$fileName`" found." }
优化说明
- 改用.NET流式搜索API:
[System.IO.Directory]::EnumerateFiles采用流式返回结果,无需一次性将所有文件对象加载到内存,在大网络目录场景下大幅降低内存占用并提升搜索速度; - 精简属性加载:仅获取
FullName、BaseName、CreationTime三个必要属性,避免默认加载大量无关文件属性,减少网络传输开销; - 优化输出与输入校验:用
Format-Table -AutoSize自动调整列宽,同时增加用户输入的有效性校验,避免无效选择导致的错误; - 简化逻辑:重构序号生成与结果输出逻辑,代码更易维护。
额外优化建议
- 如果目标网络共享已启用Windows索引服务,可以使用
Get-CimInstance Win32_IndexedFile查询索引数据库,搜索速度会进一步提升; - 若知晓PDF文件的存储子目录范围,可缩小搜索路径,避免全目录递归遍历;
- 对于频繁搜索的场景,可将搜索结果缓存到本地JSON文件,定期更新,减少重复搜索的网络开销。
内容的提问来源于stack exchange,提问作者TMC FAMILY
相关产品推荐
相关产品推荐

