PowerShell 递归目录文件名冲突检查脚本(不区分大小写)
PowerShell递归目录文件名冲突检查脚本
问题背景概述
工作中改bug的时候遇到的问题,后台game played次数对不上。问题在于同一目录下不能同时存在目录名和文件名相同名字的情况,这种情况会导致平台后台计算有误。因此,需要排查资源目录下所有的同名目录和文件名。
由于资源文件庞大,查看同一目录然后逐个对比极为繁琐,因此,我选择专门设计能够递归检查目录及其所有子目录中文件名与目录名的冲突情况的PowerShell脚本运行以检查问题所在。下面,我将给出我的完整脚本:Check-Recursive-FileDir-Conflict.ps1。希望这个脚本能帮助到您。
完整脚本:Check-Recursive-FileDir-Conflict.ps1
param([string]$Path = ".",[switch]$ShowSummary,[switch]$ExportCsv,[string]$CsvPath = "file_dir_conflicts.csv"
)function Get-RecursiveFileDirConflicts {param([string]$SearchPath)$allConflicts = @()# 获取当前目录的所有直接子项$items = Get-ChildItem -Path $SearchPath# 分离当前目录下的文件和目录$currentFiles = $items | Where-Object { !$_.PSIsContainer }$currentDirs = $items | Where-Object { $_.PSIsContainer }# 创建当前目录下目录名的查找表(不区分大小写)$currentDirNames = @{}$currentDirs | ForEach-Object { $currentDirNames[$_.Name.ToLower()] = $_.FullName }# 检查当前目录下的文件名与目录名冲突foreach ($file in $currentFiles) {$fileNameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)$matchingDirPath = $currentDirNames[$fileNameWithoutExt.ToLower()]if ($matchingDirPath) {$allConflicts += [PSCustomObject]@{ConflictLocation = $SearchPathFileName = $file.NameFilePath = $file.FullNameDirName = [System.IO.Path]::GetFileName($matchingDirPath)DirPath = $matchingDirPathFileSize = "$([math]::Round($file.Length/1KB, 2)) KB"FileDate = $file.LastWriteTime.ToString('yyyy-MM-dd HH:mm')ConflictLevel = "同级目录"Depth = (Get-DirectoryDepth -Path $SearchPath)}}}# 检查当前目录下的子目录内部冲突foreach ($dir in $currentDirs) {# 递归检查子目录内部的冲突$subDirConflicts = Get-RecursiveFileDirConflicts -SearchPath $dir.FullName$allConflicts += $subDirConflicts# 检查子目录中的文件是否与当前目录中的其他子目录同名$subDirFiles = Get-ChildItem -Path $dir.FullName -File -Recurseforeach ($subFile in $subDirFiles) {$subFileNameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($subFile.Name)$matchingPeerDirPath = $currentDirNames[$subFileNameWithoutExt.ToLower()]if ($matchingPeerDirPath -and $matchingPeerDirPath -ne $dir.FullName) {$allConflicts += [PSCustomObject]@{ConflictLocation = $SearchPathFileName = $subFile.NameFilePath = $subFile.FullNameDirName = [System.IO.Path]::GetFileName($matchingPeerDirPath)DirPath = $matchingPeerDirPathFileSize = "$([math]::Round($subFile.Length/1KB, 2)) KB"FileDate = $subFile.LastWriteTime.ToString('yyyy-MM-dd HH:mm')ConflictLevel = "跨子目录"Depth = (Get-DirectoryDepth -Path $subFile.DirectoryName)}}}}return $allConflicts
}function Get-DirectoryDepth {param([string]$Path)return ($Path -split '[\\/]').Count
}function Show-ConflictDetails {param([array]$Conflicts)if ($Conflicts.Count -eq 0) {Write-Host "`n✅ 未发现任何文件名与目录名冲突!" -ForegroundColor Greenreturn 0}Write-Host "`n🚨 发现 $($Conflicts.Count) 个文件名与目录名冲突:" -ForegroundColor Red# 按冲突位置分组显示$conflictsByLocation = $Conflicts | Group-Object ConflictLocation | Sort-Object { (Get-DirectoryDepth -Path $_.Name) }$locationNumber = 1foreach ($locationGroup in $conflictsByLocation) {Write-Host "`n" + "="*70 -ForegroundColor BlueWrite-Host "📍 冲突位置 #$locationNumber : $($locationGroup.Name)" -ForegroundColor CyanWrite-Host "="*70 -ForegroundColor Blue$conflictsByType = $locationGroup.Group | Group-Object { "$($_.FileName)->$($_.DirName) ($($_.ConflictLevel))" }$conflictNumber = 1foreach ($conflictGroup in $conflictsByType) {Write-Host "`n 🔥 冲突 #$conflictNumber" -ForegroundColor Yellow$firstConflict = $conflictGroup.Group[0]Write-Host " 冲突类型: $($firstConflict.ConflictLevel)" -ForegroundColor MagentaWrite-Host " 冲突名称: '$($firstConflict.FileName)' ←→ '$($firstConflict.DirName)'" -ForegroundColor Whiteforeach ($conflict in $conflictGroup.Group) {Write-Host "`n 文件位置:" -ForegroundColor GrayWrite-Host " 📄 $($conflict.FilePath)" -ForegroundColor DarkGrayWrite-Host " 大小: $($conflict.FileSize) | 修改时间: $($conflict.FileDate)" -ForegroundColor DarkGrayWrite-Host " 目录位置:" -ForegroundColor GrayWrite-Host " 📁 $($conflict.DirPath)" -ForegroundColor DarkGray}$conflictNumber++}$locationNumber++}return $Conflicts.Count
}function Show-Summary {param([string]$SearchPath,[array]$Conflicts,[int]$totalConflicts)Write-Host "`n" + "="*80 -ForegroundColor GreenWrite-Host "📊 递归文件名与目录名冲突检查摘要" -ForegroundColor GreenWrite-Host "="*80 -ForegroundColor GreenWrite-Host "扫描目录: $(Resolve-Path $SearchPath)" -ForegroundColor WhiteWrite-Host "发现冲突总数: $totalConflicts 个" -ForegroundColor $(if ($totalConflicts -gt 0) { "Red" } else { "Green" })if ($totalConflicts -gt 0) {# 按冲突类型统计$byConflictType = $Conflicts | Group-Object ConflictLevelWrite-Host "`n按冲突类型统计:" -ForegroundColor Yellowforeach ($typeGroup in $byConflictType) {Write-Host " $($typeGroup.Name): $($typeGroup.Count) 个" -ForegroundColor Gray}# 按目录深度统计$byDepth = $Conflicts | Group-Object Depth | Sort-Object NameWrite-Host "`n按目录深度统计:" -ForegroundColor Yellowforeach ($depthGroup in $byDepth) {Write-Host " 深度 $($depthGroup.Name): $($depthGroup.Count) 个冲突" -ForegroundColor Gray}# 最常见的冲突名称$commonNames = $Conflicts | Group-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.FileName) } | Sort-Object Count -Descending | Select-Object -First 5Write-Host "`n最常见的冲突名称:" -ForegroundColor Yellowforeach ($nameGroup in $commonNames) {Write-Host " '$($nameGroup.Name)': $($nameGroup.Count) 次" -ForegroundColor Gray}Write-Host "`n💡 建议解决方案:" -ForegroundColor CyanWrite-Host " 1. 重命名文件或目录以避免冲突" -ForegroundColor DarkCyanWrite-Host " 2. 重新组织目录结构,将冲突文件移动到专用目录" -ForegroundColor DarkCyanWrite-Host " 3. 对于跨子目录冲突,考虑使用命名空间或前缀" -ForegroundColor DarkCyanWrite-Host " 4. 删除不必要的文件或目录" -ForegroundColor DarkCyan}Write-Host "="*80 -ForegroundColor Green
}function Export-ConflictsToCsv {param([array]$Conflicts,[string]$OutputPath)try {# 创建简化版本用于导出$exportData = $Conflicts | Select-Object @(@{Name="冲突位置"; Expression={$_.ConflictLocation}},@{Name="文件名"; Expression={$_.FileName}},@{Name="文件路径"; Expression={$_.FilePath}},@{Name="目录名"; Expression={$_.DirName}},@{Name="目录路径"; Expression={$_.DirPath}},@{Name="文件大小"; Expression={$_.FileSize}},@{Name="修改时间"; Expression={$_.FileDate}},@{Name="冲突类型"; Expression={$_.ConflictLevel}},@{Name="目录深度"; Expression={$_.Depth}})$exportData | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8Write-Host "`n📁 冲突报告已导出到: $OutputPath" -ForegroundColor Green}catch {Write-Host "`n❌ 导出CSV文件时出错: $($_.Exception.Message)" -ForegroundColor Red}
}# 主程序
try {# 检查路径是否存在if (-not (Test-Path $Path)) {Write-Host "错误: 路径 '$Path' 不存在!" -ForegroundColor Redexit 1}# 解析相对路径为绝对路径$Path = Resolve-Path $PathWrite-Host "开始递归检查文件名与目录名冲突..." -ForegroundColor CyanWrite-Host "根目录: $Path" -ForegroundColor CyanWrite-Host "这可能需要一些时间,请稍候..." -ForegroundColor Yellow# 执行递归冲突检查$conflicts = Get-RecursiveFileDirConflicts -SearchPath $Path# 显示冲突详情$totalConflicts = Show-ConflictDetails -Conflicts $conflicts# 显示摘要Show-Summary -SearchPath $Path -Conflicts $conflicts -totalConflicts $totalConflicts# 导出到CSV(如果指定)if ($ExportCsv -and $totalConflicts -gt 0) {Export-ConflictsToCsv -Conflicts $conflicts -OutputPath $CsvPath}} catch {Write-Host "`n❌ 发生错误: $($_.Exception.Message)" -ForegroundColor RedWrite-Host "详细错误信息:" -ForegroundColor RedWrite-Host $_.Exception.StackTrace -ForegroundColor DarkRed
}
使用方法说明
我遇到的问题
执行步骤
1,右键打开文件,点击“编辑”
执行PowerShell的时候,我遇到了如下所示问题:
.\Check-DuplicateFiles.ps1 : 无法加载文件 E:\Check-DuplicateFiles.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135
170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
+ .\Check-DuplicateFiles.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : SecurityError: (:) [],PSSecurityException+ FullyQualifiedErrorId : UnauthorizedAccess
该问题的详细分析我会另外写一篇博客,并在完成时附上链接更新在这个博客中,现在,让我们看该怎么样解决这个问题。
这个问题出现的原因可能是Win10系统下PowerShell禁止执行脚本。
2,临时绕过方法
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
执行结果如下图,点击“是”:
3 运行脚本
# 基本用法 - 检查当前目录及其所有子目录
.\Check-Recursive-FileDir-Conflict.ps1# 检查指定目录
.\Check-Recursive-FileDir-Conflict.ps1 -Path "C:\MyProject"# 显示详细摘要
.\Check-Recursive-FileDir-Conflict.ps1 -ShowSummary# 导出结果到CSV文件
.\Check-Recursive-FileDir-Conflict.ps1 -ExportCsv# 指定CSV导出路径
.\Check-Recursive-FileDir-Conflict.ps1 -ExportCsv -CsvPath "my_conflicts_report.csv"# 组合使用所有选项
.\Check-Recursive-FileDir-Conflict.ps1 -Path "C:\MyProject" -ShowSummary -ExportCsv
4 执行结果
基本用法:
导出CSV文件:
脚本功能特点
- 完全递归检查:检查目录及其所有子目录中的文件名与目录名冲突
- 多层次冲突检测:
- 同级目录冲突:同一目录下的文件与子目录同名
- 跨子目录冲突:子目录中的文件与其他子目录同名
- 深度分析:显示冲突发生的目录深度
- 详细统计:按冲突类型、目录深度、常见名称等进行统计
- 导出功能:可将结果导出为CSV文件供进一步分析
- 彩色可视化输出:清晰的层级结构和冲突信息展示
输出示例
开始递归检查文件名与目录名冲突...
根目录: C:\TestProject
这可能需要一些时间,请稍候...🚨 发现 5 个文件名与目录名冲突:======================================================================
📍 冲突位置 #1 : C:\TestProject
======================================================================🔥 冲突 #1冲突类型: 同级目录冲突名称: 'readme.txt' ←→ 'readme'文件位置:📄 C:\TestProject\readme.txt大小: 2.1 KB | 修改时间: 2024-01-15 10:30目录位置:📁 C:\TestProject\readme======================================================================
📍 冲突位置 #2 : C:\TestProject\src\components
======================================================================🔥 冲突 #1冲突类型: 跨子目录冲突名称: 'Button.js' ←→ 'Button'文件位置:📄 C:\TestProject\src\components\Form\Button.js大小: 5.2 KB | 修改时间: 2024-01-15 11:20目录位置:📁 C:\TestProject\src\components\Button📊 递归文件名与目录名冲突检查摘要
================================================================================
扫描目录: C:\TestProject
发现冲突总数: 5 个按冲突类型统计:同级目录: 3 个跨子目录: 2 个按目录深度统计:深度 2: 3 个冲突深度 4: 2 个冲突最常见的冲突名称:'readme': 2 次'Button': 1 次'config': 1 次'utils': 1 次💡 建议解决方案:1. 重命名文件或目录以避免冲突2. 重新组织目录结构,将冲突文件移动到专用目录3. 对于跨子目录冲突,考虑使用命名空间或前缀4. 删除不必要的文件或目录
================================================================================📁 冲突报告已导出到: file_dir_conflicts.csv
总结
这个脚本能够深入检查目录结构中的所有层次,找出各种类型的文件名与目录名冲突,并提供详细的报告和解决方案建议。
相关链接
解决PowerShell脚本无法加载问题