PowerShell批量处理JSON文件时提示路径不存在/非法字符报错
问题根因
- 报错核心是PowerShell默认的
-Path参数会对传入路径做通配符解析,路径里的[]、隐藏的零宽控制字符、特殊符号都会被识别为通配符语法而非普通文件名,你之前处理的文件夹内文件名没有这类特殊字符所以运行正常,换目录后碰到带特殊字符的文件就直接触发路径非法、找不到文件的报错。 - 原脚本直接在路径里拼接
*.json通配符,进一步放大了解析冲突,就是你单独传报错文件路径时看到的Illegal characters in path错误来源。 - 原脚本没有提前创建目标目录的逻辑,加上特殊字符导致的路径解析失败,部分文件根本没写入新目录,后续执行
Select-String时自然报目标文件不存在。 - 你从资源管理器复制的路径确实是真实存在的,但资源管理器不会显示文件名里的零宽控制字符,也不会提示方括号这类字符会被脚本解析器特殊处理,所以肉眼排查不出文件名差异。
修复方案
- 枚举文件时不要把通配符写在
-Path参数里,统一使用-LiteralPath参数传基础目录路径,这个参数会把传入内容完全作为字面量路径处理,不会做任何通配符转义,从根源规避特殊字符解析问题;文件后缀过滤改用-Filter参数实现。 - 写入新文件前,先检查目标文件对应的父目录是否存在,不存在则自动创建,避免因目录缺失写入失败。
- 所有文件操作cmdlet(
Get-Content/Set-Content/Test-Path/Select-String等)传文件路径时,统一使用-LiteralPath参数,不要依赖默认的-Path参数解析。 - 新文件路径不要用简单字符串替换生成,通过相对路径拼接的方式生成,避免原路径存在其他同名字符串时被误替换。
修正后的可运行代码
# 配置基础路径,不要带*.json后缀 $baseSourcePath = "C:\Users\jutrust\documents\MyFolder" $baseTargetPath = "C:\Users\jutrust\documents\MyNewFolder" # 用-LiteralPath枚举,-Filter指定json后缀,完全规避特殊字符解析问题 $files = Get-ChildItem -LiteralPath $baseSourcePath -Filter "*.json" -Recurse foreach($file in $files) { # 读取原文件内容,同样用-LiteralPath避免特殊字符问题 $content = Get-Content -LiteralPath $file.FullName -Raw | ConvertFrom-Json # 按相对路径拼接新文件路径,避免字符串硬替换导致的路径错误 $relativePath = $file.FullName.Substring($baseSourcePath.Length) $newFilePath = Join-Path -Path $baseTargetPath -ChildPath $relativePath # 提前创建新文件的父目录 $newFileDir = Split-Path -Path $newFilePath -Parent if(-not (Test-Path -LiteralPath $newFileDir)){ New-Item -ItemType Directory -Path $newFileDir -Force | Out-Null } # 写入格式化后的json ConvertTo-Json -InputObject $content -Depth 100 | Set-Content -LiteralPath $newFilePath # 检索指定文本,统一用字面量路径传参 $filename = [System.IO.Path]::GetFileNameWithoutExtension($newFilePath) $line = Select-String -AllMatches -LiteralPath $newFilePath -Pattern "mytext" }
补充排查
如果改完脚本仍有个别文件报非法路径错误,在循环内加一行命令打印文件名的字符编码,就能揪出肉眼看不到的非法控制字符:
# 打印文件名每个字符的Unicode编码,编码值小于32的就是不可见非法字符 $file.Name.ToCharArray() | ForEach-Object { [int]$_ }
找到对应文件后去掉文件名里的非法控制字符即可正常处理。
内容的提问来源于stack exchange,提问作者JuTrust
相关产品推荐
相关产品推荐

