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.

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