Golang 调用 PowerShell.exe 始终返回 ASCII 字符

问题描述 投票:0回答:3

我在用 Go 编写的应用程序中使用 PowerShell,但无法让它返回非 ASCII 字符。起初我使用 go-powershell,但遇到了同样的问题:https://github.com/gorillalabs/go-powershell/issues/10 现在使用稍微更基本的方法:

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)
        }
}

但同样的情况也会发生。它没有得到

Przełąś
,而是返回
Przelas
。当进一步在代码中使用此虚拟交换机名称创建虚拟机时,这将导致问题。它无法被识别并出现错误。

注意:

$OutputEncoding = [Console]::OutputEncoding;
没有任何效果。它确实发生了变化,但结果保持不变。

注 2:直接从命令提示符调用相同的命令不会出现问题:

powershell.exe -NoProfile -NonInteractive $OutputEncoding = [Console]::OutputEncoding; (Get-VMSwitch).Name")
甚至
powershell.exe -NoProfile -NonInteractive (Get-VMSwitch).Name")
。换句话说,只有在使用
exec.Command
时,它才会在 Go 中执行此操作。

注 3:这是为了修复虚拟机驱动程序的本地化名称问题。是的,它可以使用 GUID (

.Id
),但这个问题在系统的不同部分仍然存在。

powershell go
3个回答
5
投票

伙计,Powershell 很有趣。这主要是一系列试验和错误的结果。

基本上,您想要设置

[Console]::OutputEncoding
,而不是捕获它。

但是,为了自己清理,将其设置回原来的值也没有什么坏处。我还没有完全理解它,但通过多次

exec()
调用,这种变化仍然存在。

这是一个例子:

<... everything else is as above ...>

func main() {
        posh := New()

        fmt.Println("With encoding change:")
        stdout, stderr, err := posh.Execute(
                "$test = \"Przełąś\"\n" +
                "$old = [Console]::OutputEncoding\n" +
                "[Console]::OutputEncoding = [Text.Encoding]::UTF8\n" +
                "[Console]::OutputEncoding\n" +
                "$test\n" +
                "[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łąś\"\n" +
                "[Console]::OutputEncoding\n" +
                "$test")
        fmt.Println(stdout)
        fmt.Println(stderr)
        if err != nil {
                fmt.Println(err)
        }
}

输出:

$ ./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

0
投票

我使用类似的方法,只是为每个命令建立代码页:

cmd := exec.Command("powershell.exe", "-c", "chcp", "65001", ">", "$null", ";", command)
out, err := cmd.CombinedOutput()

0
投票

在开头添加这个。

[Console]::OutputEncoding = [Text.Encoding]::UTF8

示例

package main

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

func main() {
    script := fmt.Sprintf(`
# chcp 65001 > $null; # <-- not working;
[Console]::OutputEncoding = [Text.Encoding]::UTF8; # 👈 add this at begin;
Get-NetAdapter | foreach { $_ | Select-Object -Property ifAlias, InstanceID } | ConvertTo-Json`, // 👈 your script content
    )
    cmd := exec.Command("powershell", script)
    buf := bytes.NewBuffer(nil)
    cmd.Stdout = buf
    if err := cmd.Run(); err != nil {
        panic(err)
    }
    fmt.Printf("%s", buf.Bytes())
}
© www.soinside.com 2019 - 2024. All rights reserved.