dst2017
2018-06-12 05:22 阅读 343
已采纳

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 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
    
    点赞 评论 复制链接分享

相关推荐