如何在PowerShell脚本中获取Robocopy的Unicode编码输出?
如何在PowerShell脚本中获取Robocopy的Unicode编码输出?
我太懂你这种乱码的糟心感了——用Robocopy加了/UNICODE参数后,输出要么存成UTF8乱码,要么控制台显示一团糟,还想实时过滤处理输出对吧?我之前踩过这个坑,给你分享两个靠谱的解决方案:
一、实时处理输出+正确保存日志(兼顾实时显示与编码正确)
问题的核心是:Robocopy加/UNICODE后会输出UTF-16LE编码的内容,PowerShell默认会用[Console]::OutputEncoding解码外部程序的stdout,只要我们把这个编码改成和Robocopy匹配的,再实时读取处理,就能避免乱码。
直接上可运行的脚本,我给你加了注释:
$sourcedir = $env:PUBLIC $destdir = $env:TEMP $logpath = Join-Path $env:USERPROFILE "test-robo-uni.txt" # 先保存原始的控制台编码,最后要恢复,别影响后续操作 $originalEncoding = [Console]::OutputEncoding try { # 把控制台输出编码改成UTF-16LE(和Robocopy的/UNICODE输出匹配) [Console]::OutputEncoding = [System.Text.Encoding]::Unicode # 启动Robocopy,用管道实时读取每一行输出 robocopy.exe "$sourcedir" "$destdir" /E /L /S /DCOPY:DA /COPY:DAT /NP /R:1 /W:1 /UNICODE | ForEach-Object { # 这里加你的实时过滤逻辑!比如只显示包含"Copied"的行: # if ($_ -match 'Copied') { Write-Host $_ } # 我这里先默认把非空行都输出到控制台 if ($_ -ne '') { Write-Host $_ } # 同时把行追加到日志文件,用UTF-8编码保存(自动转码,不会乱) $_ | Add-Content -Path $logpath -Encoding UTF8 } } finally { # 不管脚本执行成啥样,都把控制台编码恢复成原来的 [Console]::OutputEncoding = $originalEncoding }
为啥这个方法管用?
- 我们先临时把
[Console]::OutputEncoding改成UTF-16LE,让PowerShell用正确的编码解码Robocopy的输出,从根源避免乱码; - 用
ForEach-Object实时处理每一行,既能在控制台实时看到输出,又能随时加过滤规则(比如只保留错误行、复制成功的行); - 保存日志时用
Add-Content -Encoding UTF8,PowerShell会把已经正确解码的字符串转成UTF-8保存,完全不会二次乱码。
二、直接让Robocopy生成UTF-16LE日志(最省心的方案)
如果你不需要实时处理输出,只是想得到正确编码的日志文件,那直接让Robocopy自己写日志就完了——这是最不容易出问题的方法,完全绕开PowerShell的编码转换坑:
$sourcedir = $env:PUBLIC $destdir = $env:TEMP $logpath = Join-Path $env:USERPROFILE "test-robo-uni.txt" # Robocopy会直接生成UTF-16LE编码的日志文件,无需PowerShell中转 robocopy.exe "$sourcedir" "$destdir" /E /L /S /DCOPY:DA /COPY:DAT /NP /R:1 /W:1 /UNICODE /LOG:"$logpath"
加了/LOG:"$logpath"参数后,Robocopy会把所有输出直接写入指定的日志文件,编码就是UTF-16LE,打开完全正常,还省得你自己处理编码。
踩坑提醒
你之前的代码为啥乱码?大概率是先把Robocopy的输出用错误编码解码成了乱码字符串,之后再转存成任何编码都是乱的——解码这一步必须先做对,后续的保存/处理才会正常。
如果你的实时过滤逻辑比较复杂,比如要筛选特定关键字、统计行数,直接在ForEach-Object块里加逻辑就行,亲测这种方式完全能满足实时处理的需求~




