本文介绍了“证监会"输出重定向格式问题-Powershell/Batch的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个Powershell脚本,其中几个命令输出显示在窗口中,并附加到文件或变量中.在我使用 sfc 命令之前,它一直可以正常工作.通过管道传输或重定向后,输出将断开":

I'm working on a powershell script in which several commands output are shown in the window and appended to a file or a variable. It worked correctly until I used the sfc command. When piped or redirected, the output is "broken":

> sfc /?
Vérificateur de ressources Microsoft (R) Windows (R) version 6.0[...]

> sfc /? | Tee-Object -Variable content
 V Ú r i f i c a t e u r   d e   r e s s o u r c e s   M i c r o s o f t   ( R )   W i n d o w s   ( R )   v e r s i o  á 6 . 0[...]

是否还有其他命令,例如 sfc 的格式相同,或者如果重定向,会导致输出中断?

Are there other commands like sfc that are formatted in the same way, or that will result in a broken output if redirected?

编辑

Powershell 示例代码,使用接受的答案中的代码:

Powershell sample code, using the code from the accepted answer:

# Run a command
function RunCommand([ScriptBlock] $command) {

    # Run the command and write the output to the window and to a variable ("SFC" formatting)
    $stringcommand = $command.ToString()
    if (
        $stringcommand -match "^SFC$" -or
        $stringcommand -match "^SFC.exe$" -or
        $stringcommand -match "^SFC .*$" -or
        $stringcommand -match "^SFC.exe .*$"
    ) {
        $oldEncoding = [console]::OutputEncoding
        [console]::OutputEncoding = [Text.Encoding]::Unicode
        $command = [ScriptBlock]::Create("(" + $stringcommand + ")" + " -join ""`r`n"" -replace ""`r`n`r`n"", ""`r`n""")
        & ($command) 2>&1 | Tee-Object -Variable out_content
        [console]::OutputEncoding = $oldEncoding

    # Run the command and write the output to the window and to a variable (normal formatting)
    } else {
        & ($command) 2>&1 | Tee-Object -Variable out_content
    }

    # Manipulate output variable, write it to a file...
    # ...
    return
}

# Run commands
RunCommand {ping 127.0.0.1}
RunCommand {sfc /?}
[void][System.Console]::ReadKey($true)
exit


CMD 示例代码,使用 more 格式化 sfc 输出格式:


CMD sample code, using more to format the sfcoutput:

@echo off
setlocal enabledelayedexpansion
set "tmpfile=%TEMP%\temp.txt"
set "outputfile=%TEMP%\output.txt"

REM; Run commands
call :RunCommand "ping 127.0.0.1"
call :RunCommand "sfc"
pause
exit /b

REM; Run a command
:RunCommand

    REM; Run the command and write the output to the window and to the temp file
    set "command=%~1"
    (!command! 2>&1) >!tmpfile!

    REM; Write the output to the window and to the output file ("SFC" formatting)
    set "isSFC=0"
    (echo !command!|findstr /I /R /C:"^SFC$" > NUL) && (set "isSFC=1")
    (echo !command!|findstr /I /R /C:"^SFC.exe$" > NUL) && (set "isSFC=1")
    (echo !command!|findstr /I /R /C:"^SFC .*$" > NUL) && (set "isSFC=1")
    (echo !command!|findstr /I /R /C:"^SFC.exe .*$" > NUL) && (set "isSFC=1")
    (if !isSFC! equ 1 (
        (set \n=^
%=newline=%
)
        set "content="
        (for /f "usebackq tokens=* delims=" %%a in (`more /p ^<"!tmpfile!"`) do (
            set "line=%%a"
            set "content=!content!!line!!\n!"
        ))
        echo.!content!
        (echo.!content!) >>!outputfile!

    REM; Write the output to the window and to the locked output file (normal formatting)
    ) else (
        type "!tmpfile!"
        (type "!tmpfile!") >>!outputfile!
    ))
goto :EOF

推荐答案

js2010的答案(> sfc.exe 实用程序-令人惊讶-输出的文本为 UTF-16 LE("Unicode")编码.

As noted in js2010's answer, the sfc.exe utility - surprisingly - outputs text that is UTF-16LE ("Unicode") encoded.

由于PowerShell不期望这样做,因此会误解 sfc 的输出.

Since PowerShell doesn't expect that, it misinterprets sfc's output.

解决方案是将(临时)将 [console] :: OutputEncoding 更改为UTF-16LE ,该操作告诉PowerShell/.NET外部程序需要什么字符编码,即,如何将外部程序输出解码为 .NET字符串(它们以UTF-16代码单元的形式存储在内存中).

The solution is to (temporarily) change [console]::OutputEncoding to UTF-16LE, which tells PowerShell / .NET what character encoding to expect from external programs, i.e., how to decode external-program output to .NET strings (which are stored as UTF-16 code units in memory).

但是,还有一个看起来像个错误的问题:非常, sfc.exe 使用CRCRLF(`r`r`n )序列作为行而不是Windows惯用的CRLF(`r`n )换行符.

However, there's an additional problem that looks like a bug: bizarrely, sfc.exe uses CRCRLF (`r`r`n) sequences as line breaks rather than the Windows-customary CRLF (`r`n) newlines.

PowerShell捕获外部程序的stdout输出时,将返回一个行数组而不是单个多行字符串,并且将以下换行样式可互换地处理 :CRLF(Windows风格),LF(Unix风格)和CR(过时的Mac风格-如今非常罕见).
因此,它将CRCRLF视为两条换行符,它们同时反映在四边形"和变量捕获中,然后包含多余的空行.
因此,解决方案是将数组元素与标准CRLF换行符序列-(sfc/?)-join`r`n" ,然后替换 2个连续 `r`n 只需一个,即可删除人为引入的换行符:-替换`r`n`r`n",`r`n".

PowerShell, when it captures stdout output from external programs, returns an array of lines rather than a single multi-line string, and it treats the following newline styles interchangeably: CRLF (Windows-style), LF (Unix-style), and CR (obsolete Mac-style - very rare these days).
Therefore, it treats CRCRLF as two newlines, which are reflected in both "teed" and captured-in-a-variable output then containing extra, empty lines.
The solution is therefore to join the array elements with the standard CRLF newline sequences - (sfc /?) -join "`r`n" and then replace 2 consecutive `r`n with just one, to remove the artificially introduced line breaks: -replace "`r`n`r`n", "`r`n".

将它们放在一起:

# Save the current output encoding and switch to UTF-16LE
$prev = [console]::OutputEncoding
[console]::OutputEncoding = [Text.Encoding]::Unicode

# Invoke sfc.exe, whose output is now correctly interpreted and
# apply the CRCRLF workaround.
# You can also send output to a file, but note that Windows PowerShell's
# > redirection again uses UTF-16LE encoding.
# Best to use ... | Set-Content/Add-Content -Encoding ...
(sfc /?) -join "`r`n" -replace "`r`n`r`n", "`r`n" | Tee-Object -Variable content

# Restore the previous output encoding, which is the system's
# active OEM code page, which should work for other programs such
# as ping.exe
[console]::OutputEncoding = $prev

请注意,然后 $ content 将包含一个单行多行字符串;使用 $ content -split`r`n" 拆分为行数组.

Note that $content will then contain a single, multi-line string; use $content -split "`r`n" to split into an array of lines.

至:

并不是我个人知道的;在 sfc.exe 的情况下,无条件 UTF-16LE输出使我感到异常(其他程序可能会在 opt-in 上提供该功能)>基础).

Not that I'm personally aware of; unconditional UTF-16LE output, as in sfc.exe's case, strikes me as unusual (other programs may offer that on an opt-in basis).

具有仅Windows遗产的旧版控制台程序使用(可能是固定的)OEM代码页,该页是单字节8位编码,是ASCII的超集.

Older console programs with a Windows-only heritage use a (possibly fixed) OEM code page, which is a single-byte 8-bit encoding that is a superset of ASCII.

现代的多平台控制台程序越来越多地使用UTF-8(例如Node.js CLI),它是可变宽度编码,能够编码与ASCII向后兼容的所有Unicode字符(即,7位ASCII范围UTF-8将所有字符编码为单个,与ASCII兼容的字节).

Increasingly, modern, multi-platform console programs use UTF-8 (e.g., the Node.js CLI), which is variable-width encoding capable of encoding all Unicode characters that is backward-compatible with ASCII (that is, in the 7-bit ASCII range UTF-8 encodes all characters as single, ASCII-compatible bytes).

如果您希望使PowerShell会话以及潜在的 all 控制台窗口完全支持UTF-8,请参见这个答案(但是,stil要求使用 sfc 的上述解决方法).

If you want to make your PowerShell sessions and potentially all console windows fully UTF-8 aware, see this answer (However, doing so stil requires the above workaround for sfc).

直接到控制台输出:

sfc 输出既未由PowerShell捕获,也未通过cmdlet(如 Tee-Object )进行路由时, sfc 直接将写入到控制台,大概使用 WriteConsole的Unicode版本 Windows API函数,该函数需要UTF-16LE字符串.

When sfc output is neither captured by PowerShell nor routed through a cmdlet such as Tee-Object, sfc writes directly to the console, presumably using the Unicode version of the WriteConsole Windows API function, which expects UTF-16LE strings.

通过这种方式写入控制台允许打印所有Unicode字符,而不管当前处于活动状态的代码页(反映在 chcp / [console] :: OutputEncoding 中).(尽管某些字体的 rendering 可能会由于字体支持有限以及缺乏对BMP(基本多语言平面)之外的(稀有)字符的支持而下降,控制台 buffer 会正确保留所有字符,因此在其他位置进行复制和粘贴可能会在此处正确显示-请参见此答案的底部.)

Writing to the console this way allows printing all Unicode characters, irrespective of what code page (reflected in chcp / [console]::OutputEncoding) is currently active.(While the rendering of certain characters may fall short, due to limited font support and lack of support for (the rare) characters outside the BMP (Basic Multilingual Plane), the console buffer correctly preserves all characters, so copying and pasting elsewhere may render correctly there - see the bottom section of this answer.)

因此,直接输出到控制台的输出不受错误解释的影响,并且通常会按预期打印.

Therefore, direct-to-console output is not affected by the misinterpretation and typically prints as expected.

这篇关于“证监会"输出重定向格式问题-Powershell/Batch的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 18:20