我使用的是一个用Go编写的应用程序的PowerShell,但我无法让它返回非ASCII字符。起初我使用了go-powershell,但遇到了同样的问题:more现在使用稍微更基本的方法:
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
。这将导致在使用此虚拟交换机名称创建VM的代码中进一步出现问题。它不会被识别和错误。
注意:$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
),但是这个问题在系统的不同部分仍然存在。
答案 0 :(得分:2)
男人,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
答案 1 :(得分:0)
我使用类似的方法,只是为每个命令建立代码页:
cmd := exec.Command("powershell.exe", "-c", "chcp", "65001", ">", "$null", ";", command)
out, err := cmd.CombinedOutput()