首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >PowerShell输出的UTF-8

PowerShell输出的UTF-8
EN

Stack Overflow用户
提问于 2014-03-12 10:49:56
回答 3查看 130.2K关注 0票数 50

我试图使用带有重定向I/O的Process.Start调用带有字符串的PowerShell.exe,并将输出返回到UTF-8中。但我似乎无法做到这一点。

我试过的是:

  • 传递要通过-Command参数运行的命令
  • 使用UTF-8编码将PowerShell脚本作为文件写入磁盘。
  • 使用UTF-8使用PowerShell编码将PowerShell脚本作为文件写入磁盘
  • 使用UTF-16将PowerShell脚本作为文件写入磁盘
  • 在我的控制台应用程序和PowerShell脚本中设置PowerShell
  • $OutputEncoding中设置PowerShell
  • 设置Process.StartInfo.StandardOutputEncoding
  • 所有这些都是用Encoding.Unicode而不是Encoding.UTF8来完成的

在任何情况下,当我检查给定的字节时,都会得到与原始字符串不同的值。我真的很想解释一下为什么这不管用。

这是我的代码:

代码语言:javascript
运行
复制
static void Main(string[] args)
{
    DumpBytes("Héllo");

    ExecuteCommand("PowerShell.exe", "-Command \"$OutputEncoding = [System.Text.Encoding]::UTF8 ; Write-Output 'Héllo';\"",
        Environment.CurrentDirectory, DumpBytes, DumpBytes);

    Console.ReadLine();
}

static void DumpBytes(string text)
{
    Console.Write(text + " " + string.Join(",", Encoding.UTF8.GetBytes(text).Select(b => b.ToString("X"))));
    Console.WriteLine();
}

static int ExecuteCommand(string executable, string arguments, string workingDirectory, Action<string> output, Action<string> error)
{
    try
    {
        using (var process = new Process())
        {
            process.StartInfo.FileName = executable;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.WorkingDirectory = workingDirectory;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            process.StartInfo.StandardErrorEncoding = Encoding.UTF8;

            using (var outputWaitHandle = new AutoResetEvent(false))
            using (var errorWaitHandle = new AutoResetEvent(false))
            {
                process.OutputDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        outputWaitHandle.Set();
                    }
                    else
                    {
                        output(e.Data);
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        errorWaitHandle.Set();
                    }
                    else
                    {
                        error(e.Data);
                    }
                };

                process.Start();

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit();
                outputWaitHandle.WaitOne();
                errorWaitHandle.WaitOne();

                return process.ExitCode;
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception(string.Format("Error when attempting to execute {0}: {1}", executable, ex.Message),
            ex);
    }
}

更新1

我发现如果我做这个剧本:

代码语言:javascript
运行
复制
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Write-Host "Héllo!"
[Console]::WriteLine("Héllo")

然后通过以下方式调用它:

代码语言:javascript
运行
复制
ExecuteCommand("PowerShell.exe", "-File C:\\Users\\Paul\\Desktop\\Foo.ps1",
  Environment.CurrentDirectory, DumpBytes, DumpBytes);

第一行已损坏,但第二行未损坏:

代码语言:javascript
运行
复制
H?llo! 48,EF,BF,BD,6C,6C,6F,21
Héllo 48,C3,A9,6C,6C,6F

这表明我的重定向代码运行良好;当我在Console.WriteLine中使用PowerShell时,我得到了UTF-8。

这意味着PowerShell的Write-OutputWrite-Host命令必须对输出执行不同的操作,而不是简单地调用Console.WriteLine

更新2

我甚至尝试使用以下方法将PowerShell控制台代码页强制到UTF-8,但是Write-HostWrite-Output[Console]::WriteLine工作时继续产生坏结果。

代码语言:javascript
运行
复制
$sig = @'
[DllImport("kernel32.dll")]
public static extern bool SetConsoleCP(uint wCodePageID);

[DllImport("kernel32.dll")]
public static extern bool SetConsoleOutputCP(uint wCodePageID);
'@

$type = Add-Type -MemberDefinition $sig -Name Win32Utils -Namespace Foo -PassThru

$type::SetConsoleCP(65001)
$type::SetConsoleOutputCP(65001)

Write-Host "Héllo!"

& chcp    # Tells us 65001 (UTF-8) is being used
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-03-12 20:57:18

这是.NET中的一个bug,当PowerShell启动时,它会缓存输出句柄(Console.Out)。该文本写入器的“编码”属性不会获取值StandardOutputEncoding属性。

在PowerShell中更改它时,缓存输出写入器的编码属性将返回缓存的值,因此输出仍然使用默认编码进行编码。

作为解决办法,我建议不要更改编码。它将作为Unicode字符串返回给您,此时您可以自己管理编码。

缓存示例:

代码语言:javascript
运行
复制
102 [C:\Users\leeholm]
>> $r1 = [Console]::Out

103 [C:\Users\leeholm]
>> $r1

Encoding                                          FormatProvider
--------                                          --------------
System.Text.SBCSCodePageEncoding                  en-US



104 [C:\Users\leeholm]
>> [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

105 [C:\Users\leeholm]
>> $r1

Encoding                                          FormatProvider
--------                                          --------------
System.Text.SBCSCodePageEncoding                  en-US
票数 23
EN

Stack Overflow用户

发布于 2017-01-05 02:16:47

[Console]::OuputEncoding设置为任意编码,并使用[Console]::WriteLine打印出来。

如果powershell ouput方法有问题,那么就不要使用它。它感觉有点糟糕,但效果就像一种魅力:)

票数 2
EN

Stack Overflow用户

发布于 2018-05-13 00:23:41

花了一些时间来解决我的问题,并认为这可能是有意义的。我遇到了一个问题,试图在Windows8上使用PowerShell 3.0自动生成代码。目标IDE是使用MDK基本工具链5.24.1的Keil编译器。与OP有一点不同,因为我在构建前的步骤中本机使用PowerShell。当我试图包含生成的文件时,我收到了错误

致命错误: UTF-16 (LE)字节顺序标记检测到'..\GITVersion.h‘,但不支持编码。

通过更改生成输出文件的行,我解决了这个问题:

代码语言:javascript
运行
复制
out-file -FilePath GITVersion.h -InputObject $result

至:

代码语言:javascript
运行
复制
out-file -FilePath GITVersion.h -Encoding ascii -InputObject $result
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22349139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档