You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写PowerShell脚本批量递归重命名文件/文件夹以移除隐藏字符

解决含特殊字符的百万级文件/文件夹重命名问题

问题背景

  • Windows服务器上存有近百万个文件和文件夹,文件名随机包含Apple MacOS特殊字符,导致robocopy归档时出错
  • 违规特殊字符:
    • 零宽空格(Zero Width Space,Unicode编码0x200b)
    • U+F028 Unicode字符
  • 可通过Windows文件资源管理器搜索定位这类文件:
    • 搜索零宽空格:name:~"*​*"
    • 搜索U+F028:name:~"**"

原编写的PowerShell脚本在本地小文件测试场景有效,但在外部USB驱动器的大文件集场景中失败,还存在性能隐患且缺少日志记录功能。原脚本如下:

#Set location to run from
set-location -Path "P:\"

#Rename folders containing Zero Width Spaces
$folders = Get-ChildItem -Recurse -Directory | Sort-Object
$folders | ForEach-Object {
    set-location $_.Parent.FullName
    Rename-Item $_.Name ($_.Name -replace("​", ""))
}

#Rename folders containing U+F028
$folders = Get-ChildItem -Recurse -Directory | Sort-Object
$folders | ForEach-Object {
    set-location $_.Parent.FullName
    Rename-Item $_.Name ($_.Name -replace("", ""))
}

#Rename files containing Zero Width Spaces
$files = Get-ChildItem -File -Recurse
$files | ForEach-Object {
 Rename-Item -Path $_.PSPath -NewName $_.Name.replace("​","")
}

#Rename files containing U+F028
$files = Get-ChildItem -File -Recurse
$files | ForEach-Object {
 Rename-Item -Path $_.PSPath -NewName $_.Name.replace("","")
}

优化后的脚本及说明

核心优化点

  • 仅两次递归扫描(文件夹+文件),原脚本四次扫描,大幅降低IO开销,适配百万级文件场景
  • 文件夹按路径深度倒序处理(先子文件夹后父文件夹),避免父文件夹重命名后子路径失效
  • 用Unicode编码直接定义特殊字符,避免复制粘贴时的字符丢失问题
  • 增加完整日志记录,包含操作时间、原路径、新路径及错误信息
  • 无需切换工作目录,直接使用完整路径操作,避免路径错误
  • 添加错误捕获,单个文件/文件夹重命名失败不会终止整个脚本

优化脚本

# 配置参数
$rootPath = "P:\"
$logPath = Join-Path -Path $rootPath -ChildPath "RenameLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

# 定义要移除的特殊字符(用Unicode编码确保匹配准确)
$specialChars = @([char]0x200b, [char]0xF028)
$regexPattern = [regex]::Escape(-join $specialChars)

# 先处理文件夹:递归遍历并按路径倒序(先子后父)
Get-ChildItem -Path $rootPath -Recurse -Directory | Sort-Object -Property FullName -Descending | ForEach-Object {
    $newName = $_.Name -replace $regexPattern, ""
    if ($newName -ne $_.Name) {
        $newPath = Join-Path -Path $_.Parent.FullName -ChildPath $newName
        try {
            Rename-Item -Path $_.FullName -Destination $newPath -ErrorAction Stop
            $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | 文件夹 | 原路径: $($_.FullName) | 新路径: $newPath"
            Add-Content -Path $logPath -Value $logEntry
            Write-Host $logEntry
        }
        catch {
            $errorEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | 文件夹错误 | 原路径: $($_.FullName) | 错误信息: $($_.Exception.Message)"
            Add-Content -Path $logPath -Value $errorEntry
            Write-Host $errorEntry -ForegroundColor Red
        }
    }
}

# 处理文件:递归遍历
Get-ChildItem -Path $rootPath -Recurse -File | ForEach-Object {
    $newName = $_.Name -replace $regexPattern, ""
    if ($newName -ne $_.Name) {
        $newPath = Join-Path -Path $_.Parent.FullName -ChildPath $newName
        try {
            Rename-Item -Path $_.FullName -Destination $newPath -ErrorAction Stop
            $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | 文件 | 原路径: $($_.FullName) | 新路径: $newPath"
            Add-Content -Path $logPath -Value $logEntry
            Write-Host $logEntry
        }
        catch {
            $errorEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | 文件错误 | 原路径: $($_.FullName) | 错误信息: $($_.Exception.Message)"
            Add-Content -Path $logPath -Value $errorEntry
            Write-Host $errorEntry -ForegroundColor Red
        }
    }
}

Write-Host "重命名操作完成,日志已保存至: $logPath" -ForegroundColor Green

使用提示

  • 运行前先在小范围测试文件夹验证脚本逻辑,确认无误后再全量执行
  • 确保对目标驱动器拥有足够的读写权限
  • 外部USB驱动器建议用USB3.0及以上接口,减少IO瓶颈影响性能
  • 若文件量极大,可考虑按子文件夹分区分批处理

内容的提问来源于stack exchange,提问作者mrEdge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:05:14