dst2017 2018-06-12 05:22
浏览 492
已采纳

Golang调用PowerShell.exe总是返回ASCII字符

I am using PowerShell from an application written in Go, but am unable to get it to return non-ASCII characters. At first I used go-powershell, but experience the same issue: https://github.com/gorillalabs/go-powershell/issues/10 and now using a slightly more basic approach:

package main

import (
        "bytes"
        "fmt"
        "os/exec"
)

type PowerShell struct {
        powerShell string
}

func New() *PowerShell {
        ps, _ := exec.LookPath("powershell.exe")
        return &PowerShell{
                powerShell: ps,
        }
}

func (p *PowerShell) Execute(args ...string) (stdOut string, stdErr string, err error) {
        args = append([]string{"-NoProfile", "-NonInteractive"}, args...)
        cmd := exec.Command(p.powerShell, args...)

        var stdout bytes.Buffer
        var stderr bytes.Buffer
        cmd.Stdout = &stdout
        cmd.Stderr = &stderr

        err = cmd.Run()
        stdOut, stdErr = stdout.String(), stderr.String()
        return
}

func main() {
        posh := New()
        stdout, stderr, err := posh.Execute("$OutputEncoding = [Console]::OutputEncoding; (Get-VMSwitch).Name")

        fmt.Println(stdout)
        fmt.Println(stderr)

        if err != nil {
                fmt.Println(err)
        }
}

but the same happens. Instead of gettting Przełąś, it returns Przelas. This will result in issues when further in the code a VM is created using this Virtual Switch name. It does not get recognized and errors.

Note: $OutputEncoding = [Console]::OutputEncoding; did not have any effect. It does get changed, but the result remains the same.

Note 2: invoking the same command directly from the command prompt does NOT have issues: powershell.exe -NoProfile -NonInteractive $OutputEncoding = [Console]::OutputEncoding; (Get-VMSwitch).Name") or even powershell.exe -NoProfile -NonInteractive (Get-VMSwitch).Name"). In other words, it does this only from Go when using exec.Command.

Note 3: this is for fixing an issue with a virtual machine driver when it comes to the localized names. Yes, it could work with an GUID (.Id) instead, but this issue persists in different parts of the system.

  • 写回答

1条回答 默认 最新

  • douou1872 2018-06-12 18:49
    关注

    Man, Powershell is interesting. This was mostly the result of a bunch of trial and error.

    Basically, you want to set [Console]::OutputEncoding, not capture it.

    However, to clean up after yourself, it doesn't hurt to set it back to it's original value. I haven't fully wrapped my head around it, but the change persists through multiple exec() calls.

    Here's an example:

    <... everything else is as above ...>
    
    func main() {
            posh := New()
    
            fmt.Println("With encoding change:")
            stdout, stderr, err := posh.Execute(
                    "$test = \"Przełąś\"
    " +
                    "$old = [Console]::OutputEncoding
    " +
                    "[Console]::OutputEncoding = [Text.Encoding]::UTF8
    " +
                    "[Console]::OutputEncoding
    " +
                    "$test
    " +
                    "[Console]::OutputEncoding = $old")
            fmt.Println(stdout)
            fmt.Println(stderr)
            if err != nil {
                    fmt.Println(err)
            }
    
            fmt.Println("Without encoding change:")
            stdout, stderr, err = posh.Execute(
                    "$test = \"Przełąś\"
    " +
                    "[Console]::OutputEncoding
    " +
                    "$test")
            fmt.Println(stdout)
            fmt.Println(stderr)
            if err != nil {
                    fmt.Println(err)
            }
    }
    

    Output:

    $ ./exec-powershell.exe
    With encoding change:
    
    
    BodyName          : utf-8
    EncodingName      : Unicode (UTF-8)
    HeaderName        : utf-8
    WebName           : utf-8
    WindowsCodePage   : 1200
    IsBrowserDisplay  : True
    IsBrowserSave     : True
    IsMailNewsDisplay : True
    IsMailNewsSave    : True
    IsSingleByte      : False
    EncoderFallback   : System.Text.EncoderReplacementFallback
    DecoderFallback   : System.Text.DecoderReplacementFallback
    IsReadOnly        : False
    CodePage          : 65001
    
    Przełąś
    
    
    
    
    Without encoding change:
    
    
    IsSingleByte      : True
    BodyName          : IBM437
    EncodingName      : OEM United States
    HeaderName        : IBM437
    WebName           : IBM437
    WindowsCodePage   : 1252
    IsBrowserDisplay  : False
    IsBrowserSave     : False
    IsMailNewsDisplay : False
    IsMailNewsSave    : False
    EncoderFallback   : System.Text.InternalEncoderBestFitFallback
    DecoderFallback   : System.Text.InternalDecoderBestFitFallback
    IsReadOnly        : True
    CodePage          : 437
    
    Przelas
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况
  • ¥15 画两个图 python或R
  • ¥15 在线请求openmv与pixhawk 实现实时目标跟踪的具体通讯方法
  • ¥15 八路抢答器设计出现故障
  • ¥15 opencv 无法读取视频
  • ¥15 用matlab 实现通信仿真
  • ¥15 按键修改电子时钟,C51单片机
  • ¥60 Java中实现如何实现张量类,并用于图像处理(不运用其他科学计算库和图像处理库))
  • ¥20 5037端口被adb自己占了