You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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块里加逻辑就行,亲测这种方式完全能满足实时处理的需求~

火山引擎 最新活动