解决PowerShell统计远程服务器文件时的PathTooLongException问题
解决Win Server2012远程文件统计的路径过长问题
针对你遇到的PathTooLongException问题,结合Win Server2012(PowerShell 3.0)的环境限制,以下是几个更高效的解决方案,比你之前用\\?\UNC跨版本执行的方案耗时更少:
方案1:使用Robocopy统计(推荐)
Robocopy是Windows原生工具,Win Server2012自带,天生支持长路径,且枚举文件的速度远快于Get-ChildItem。它可以通过参数直接按修改时间筛选文件,还能输出统计结果。
修改后的脚本如下:
$servers = "server1", "server2" # 注意:$folder应为远程服务器上的本地路径(如D:\Path\to\folder),而非UNC路径 $folder = "D:\Path\to\folder" foreach ($server in $servers) { $session = New-PSSession -ComputerName $server # 统计近30天修改的文件 $folder_30 = Invoke-Command -Session $session -ScriptBlock { # /L:仅列出文件不复制;/MAXAGE:30:筛选30天内修改的文件;/NJH/NJS:去掉冗余的作业头/尾 $robocopyResult = robocopy $using:folder NULL /L /MAXAGE:30 /NJH /NJS # 提取最后一行的文件数量(格式:Total Files : X) [int]($robocopyResult | Select-Object -Last 1 | Select-String 'Total\s+Files\s+:\s+(\d+)').Matches.Groups[1].Value } # 统计30-180天修改的文件 $folder_30_180 = Invoke-Command -Session $session -ScriptBlock { $robocopyResult = robocopy $using:folder NULL /L /MINAGE:30 /MAXAGE:180 /NJH /NJS [int]($robocopyResult | Select-Object -Last 1 | Select-String 'Total\s+Files\s+:\s+(\d+)').Matches.Groups[1].Value } # 统计超过180天未修改的文件 $folder_180 = Invoke-Command -Session $session -ScriptBlock { $robocopyResult = robocopy $using:folder NULL /L /MINAGE:180 /NJH /NJS [int]($robocopyResult | Select-Object -Last 1 | Select-String 'Total\s+Files\s+:\s+(\d+)').Matches.Groups[1].Value } Remove-PSSession $session # 输出当前服务器的统计结果 Write-Host "=== $server 统计结果 ===" Write-Host "近30天修改文件数:$folder_30" Write-Host "30-180天修改文件数:$folder_30_180" Write-Host "超过180天未修改文件数:$folder_180`n" }
注意:如果你的$folder原本是UNC路径(如\\server1\share\folder),在远程会话中需要转换为远程服务器的本地路径(如C:\Shares\folder),否则Robocopy会从远程服务器访问UNC路径,反而增加耗时。
方案2:手动递归遍历(纯PowerShell实现)
如果无法使用Robocopy,可以通过.NET类手动递归枚举文件,绕过Get-ChildItem的长路径限制。这种方式直接调用底层API,支持\\?\格式的长路径。
修改后的脚本如下:
$servers = "server1", "server2" $folder = "D:\Path\to\folder" foreach ($server in $servers) { $session = New-PSSession -ComputerName $server $stats = Invoke-Command -Session $session -ScriptBlock { $localFolder = $using:folder $now = Get-Date $date30 = $now.AddDays(-30) $date180 = $now.AddDays(-180) # 定义递归统计函数 function Get-FileCountByDate { param( [string]$Path, [datetime]$LowerBound, [datetime]$UpperBound ) $count = 0 # 枚举当前目录的文件 try { foreach ($file in [System.IO.Directory]::GetFiles($Path)) { $lastWrite = [System.IO.File]::GetLastWriteTime($file) if ($lastWrite -ge $LowerBound -and $lastWrite -lt $UpperBound) { $count++ } } # 递归处理子目录,转换为长路径格式避免异常 foreach ($dir in [System.IO.Directory]::GetDirectories($Path)) { $longDir = "\\?\$dir" $count += Get-FileCountByDate -Path $longDir -LowerBound $LowerBound -UpperBound $UpperBound } } catch { # 跳过无权限或无法访问的目录 Write-Warning "无法访问目录:$Path,错误:$($_.Exception.Message)" } return $count } # 统计三类文件数量 [PSCustomObject]@{ Last30Days = Get-FileCountByDate -Path $localFolder -LowerBound $date30 -UpperBound $now Days30To180 = Get-FileCountByDate -Path $localFolder -LowerBound $date180 -UpperBound $date30 Over180Days = Get-FileCountByDate -Path $localFolder -LowerBound [datetime]::MinValue -UpperBound $date180 } } Remove-PSSession $session # 输出结果 Write-Host "=== $server 统计结果 ===" Write-Host "近30天修改文件数:$($stats.Last30Days)" Write-Host "30-180天修改文件数:$($stats.Days30To180)" Write-Host "超过180天未修改文件数:$($stats.Over180Days)`n" }
这个方案的优势是无需依赖外部工具,但枚举速度比Robocopy慢,适合需要自定义处理逻辑的场景。
方案3:启用系统级长路径支持(需修改系统设置)
如果允许修改远程服务器的系统配置,可以通过注册表启用长路径支持:
- 在远程服务器上打开注册表编辑器,定位到
HKLM\SYSTEM\CurrentControlSet\Control\FileSystem - 创建或修改
LongPathsEnabled(DWORD类型),设置值为1 - 重启服务器
启用后,系统层面的路径长度限制会放宽到32767字符,Get-ChildItem可以直接处理更长的路径(无需\\?\格式)。但此方法需要管理员权限和服务器重启,且PowerShell 3.0本身仍有部分API限制,仅作为备选方案。
内容的提问来源于stack exchange,提问作者Telvanis
相关产品推荐
相关产品推荐

