GO: Run cli command with wrong args - go

I use cobra to create CLI command tool.
everything is looking OK except the error handling
what I want that if command was sent by mistake (wrong args or wrong input) return std.err instead of std.out
to simplify the secnario I've created this which demonstrate my use-case
package main
import (
"errors"
"fmt"
"os"
"github.com/spf13/cobra"
)
var (
RootCmd = &cobra.Command{
Use: "myApp",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("ROOT verbose = %d, args = %v\n", args)
},
}
provideCmd = &cobra.Command{
Use: "provide",
Run: nil,
}
appCmd = &cobra.Command{
Use: "apps",
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
if name != "myapp" {
err := errors.New("app name doesnt exist")
return err
}
return nil
},
SilenceUsage: true,
}
)
func init() {
// Add the application command to app command
provideCmd.AddCommand(appCmd)
// add provide command to root command
RootCmd.AddCommand(provideCmd)
}
func main() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
Now if I compile the binary and run exec.Command against the binary everything is working as expected. but if I want to test the error scenario like mycli provide apps apps1
I want to see that returned in std.err and not at std.out
When I execute mycli provide apps myapp everything should be OK
but if I run mycli provide apps myapp2 I want to get std.err and not std.out , which is not the case here ...what am I missing here ?
https://play.golang.org/p/B00z4eZ7Sj-

Your sample already prints the error both to stdout and stderr.
By default the cobra package prints any errors it encounters to stderr, unless you specifically change that.
So running
./main provide apps something 2> ./stderr.txt creates a text file with the following content (this is what cobra writes to stderr without your intervention):
Error: app name doesnt exist
And running ./main provide apps something > ./stdout.txt - creates a text file with the following content (you printed that yourself with fmt.Println(err), the second line from the bottom in your code):
app name doesnt exist
Which means default behaviour prints errors both to stdout and stderr.
As Devin has advised you, changing the last line to os.Stderr.WriteString(err) or
fmt.Fprintln(os.Stderr, err) (the one I would use) will make your project to print everything to stderr only, which means printing errors twice:
Error: app name doesnt exist
app name doesnt exist
It might be useful to know that cobra allows you some control of error printing behaviour. For example, you can tell a cobra command which stream to print to:
command.SetOutput(os.Stdout) // Defaults to os.Stderr
you could also prevent printing of errors:
command.SilenceErrors = true
or prevent printing of usage text:
command.SilenceUsage = true

Related

golang: read cmd line arguments and additional parameters

I am attempting to read the extra parameter passed to go build.go build example-service using the code below -
flag.Parse()
fmt.Println(flag.Args()) // Print "[build example-service]"
for _, cmd := range flag.Args() {
switch cmd {
case "build":
log.Println("build", cmd) // Print "build build"
}
}
I am successfully able to print flag.Args() as [build example-service] which is an array object
I unable to retrieve the example-service arg inside the switch case as cmd only prints build build
What you looking for is the "Command-Line Arguments" topic. More information: https://gobyexample.com/command-line-arguments
os package can use for this purpose. By os.Args array, exe file address (first index) and arguments (other indexes) are accessible.
Also to run your file using a command like this go run test.go arg1 arg2 arg3.... Here test.go is my test filename.
package main
import (
"fmt"
"os"
)
func main() {
fmt.Printf("Input args are %v and type is %T", os.Args, os.Args)
}
The output of this code after running the go run test.go build example-service command is something like this:
Input args are [...\test.exe build example-service] and type is []string
And your code can modified to:
for _, cmd := range os.Args {
switch cmd {
case "build":
log.Println("command: ", cmd)
case "example-service":
log.Println("command: ", cmd)
}
}

Why am I getting a nil pointer error depending on where I call BindPFlag?

I've just recently started working with Go, and I've run into some
behavior working with Cobra and Viper that I'm not sure I understand.
This is a slightly modified version of the sample code you get by
running cobra init. In main.go I have:
package main
import (
"github.com/larsks/example/cmd"
"github.com/spf13/cobra"
)
func main() {
rootCmd := cmd.NewCmdRoot()
cobra.CheckErr(rootCmd.Execute())
}
In cmd/root.go I have:
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
func NewCmdRoot() *cobra.Command {
config := viper.New()
var cmd = &cobra.Command{
Use: "example",
Short: "A brief description of your application",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initConfig(cmd, config)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("This is a test\n")
},
}
cmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.example.yaml)")
cmd.PersistentFlags().String("name", "", "a name")
// *** If I move this to the top of initConfig
// *** the code runs correctly.
config.BindPFlag("name", cmd.Flags().Lookup("name"))
return cmd
}
func initConfig(cmd *cobra.Command, config *viper.Viper) {
if cfgFile != "" {
// Use config file from the flag.
config.SetConfigFile(cfgFile)
} else {
config.AddConfigPath(".")
config.SetConfigName(".example")
}
config.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := config.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", config.ConfigFileUsed())
}
// *** This line triggers a nil pointer reference.
fmt.Printf("name is %s\n", config.GetString("name"))
}
This code will panic with a nil pointer reference at the final call to
fmt.Printf:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x6a90e5]
If I move the call to config.BindPFlag from the NewCmdRoot
function to the top of the initConfig command, everything runs
without a problem.
What's going on here? According to the Viper docs regarding the use of
BindPFlags:
Like BindEnv, the value is not set when the binding method is
called, but when it is accessed. This means you can bind as early as
you want, even in an init() function.
That's almost exactly what I'm doing here. At the time I call
config.BindPflag, config is non-nil, cmd is non-nil, and the
name argument has been registered.
I assume there's something going on with my use of config in a
closure in PersistentPreRun, but I don't know exactly why that is
causing this failure.
I thought this was interesting so I did some digging and found your exact problem documented in an issue. The problematic line is this:
config.BindPFlag("name", cmd.Flags().Lookup("name"))
// ^^^^^^^
You created a persistent flag, but bound the flag to the Flags property. If you change your code to bind to PersistentFlags, everything will work as intended even with this line in NewCmdRoot:
config.BindPFlag("name", cmd.PersistentFlags().Lookup("name"))
I don't have any issue if I use cmd.PersistentFlags().Lookup("name").
// *** If I move this to the top of initConfig
// *** the code runs correctly.
pflag := cmd.PersistentFlags().Lookup("name")
config.BindPFlag("name", pflag)
Considering you just registered persistent flags (flag will be available to the command it's assigned to as well as every command under that command), it is safer to call cmd.PersistentFlags().Lookup("name"), rather than cmd.Flags().Lookup("name").
The latter returns nil, since the PersistentPreRun is only called when rootCmd.Execute() is called, which is after cmd.NewCmdRoot().
At cmd.NewCmdRoot() levels, flags have not yet been initialized, even after some were declared "persistent".
This ends up being a little more complex than it might appear at first glance, so while the other answers here helped me resolve the problem I'd like to add a little detail.
There are some nuances in the documentation that aren't particularly clear if you're just starting to work with Cobra. Let's start with the documentation for the PersistentFlags method:
PersistentFlags returns the persistent FlagSet specifically set in the current command.
The key is in ...in the current command. In my NewCmdRoot root method, we can use cmd.PersistentFlags() because the root command is the current command. We can even use cmd.PersistentFlags() in the PersistentPreRun method, as long as we're not processing a subcommand.
If we were to re-write cmd/root.go from the example so that it includes a subcommand, like this...
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
func NewCmdSubcommand() *cobra.Command {
var cmd = &cobra.Command{
Use: "subcommand",
Short: "An example subcommand",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("This is an example subcommand\n")
},
}
return cmd
}
func NewCmdRoot() *cobra.Command {
config := viper.New()
var cmd = &cobra.Command{
Use: "example",
Short: "A brief description of your application",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
initConfig(cmd, config)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Hello, world\n")
},
}
cmd.PersistentFlags().StringVar(
&cfgFile, "config", "", "config file (default is $HOME/.example.yaml)")
cmd.PersistentFlags().String("name", "", "a name")
cmd.AddCommand(NewCmdSubcommand())
err := config.BindPFlag("name", cmd.PersistentFlags().Lookup("name"))
if err != nil {
panic(err)
}
return cmd
}
func initConfig(cmd *cobra.Command, config *viper.Viper) {
name, err := cmd.PersistentFlags().GetString("name")
if err != nil {
panic(err)
}
fmt.Printf("name = %s\n", name)
if cfgFile != "" {
// Use config file from the flag.
config.SetConfigFile(cfgFile)
} else {
config.AddConfigPath(".")
config.SetConfigName(".example")
}
config.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := config.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", config.ConfigFileUsed())
}
// *** This line triggers a nil pointer reference.
fmt.Printf("name is %s\n", config.GetString("name"))
}
...we would find that it works when executing the root command:
$ ./example
name =
name is
Hello, world
But it fails when we run the subcommand:
[lars#madhatter go]$ ./example subcommand
panic: flag accessed but not defined: name
goroutine 1 [running]:
example/cmd.initConfig(0xc000172000, 0xc0001227e0)
/home/lars/tmp/go/cmd/root.go:55 +0x368
example/cmd.NewCmdRoot.func1(0xc000172000, 0x96eca0, 0x0, 0x0)
/home/lars/tmp/go/cmd/root.go:32 +0x34
github.com/spf13/cobra.(*Command).execute(0xc000172000, 0x96eca0, 0x0, 0x0, 0xc000172000, 0x96eca0)
/home/lars/go/pkg/mod/github.com/spf13/cobra#v1.1.3/command.go:836 +0x231
github.com/spf13/cobra.(*Command).ExecuteC(0xc00011db80, 0x0, 0xffffffff, 0xc0000240b8)
/home/lars/go/pkg/mod/github.com/spf13/cobra#v1.1.3/command.go:960 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
/home/lars/go/pkg/mod/github.com/spf13/cobra#v1.1.3/command.go:897
main.main()
/home/lars/tmp/go/main.go:11 +0x2a
This is because the subcommand inherits the PersistentPreRun command from the root (this is what the Persistent part means), but when this method runs, the cmd argument passwd to PersistentPreRun is no longer the root command; it's the subcommand command. When we try to call cmd.PersistentFlags(), it fails because the current command doesn't have any persistent flags associated with it.
In this case, we need to instead use the Flags method:
Flags returns the complete FlagSet that applies to this command (local and persistent declared here and by all parents).
This gives us access to persistent flags declared by parents.
An additional issue, that doesn't appear to be called out explicitly in the documentation, is that Flags() is only available after command processing has been run (that is, after you call cmd.Execute() on the command or a parent). That means we can use it in PersistentPreRun, but we can't use it in NewCmdRoot (because that method finishes before we process the command line).
TL;DR
We have to use cmd.PersistentFlags() in NewCmdRoot because we're looking for persistent flags applied to the current command, and the value from Flags() won't be available yet.
We need to use cmd.Flags() in PersistentPreRun (and other persistent commands methods) because when processing a subcommand, PersistentFlags will only look for persistent flags on the current command, but won't traverse parents. We need to use cmd.Flags() instead, which will roll up persistent flags declared by parents.

exec,Cmd.Run() does not properly run command w/arguments

go version go1.15.6 windows/amd64
dev os Windows [Version 10.0.19041.630]
I have a Go app in which I am running the AWS CLI using exec.Cmd.Run(). I build out the Cmd class and populate the arguments.
Before I run the Cmd, I use the .String() method to view the command to be ran. If I take this value, copy it to a shell, the command executes with no modifications to the output given to me with no issues reported.
However, when I run the command, it fails returning an error. When I debug the script, it is failing because it says the AWS CLI is saying a parameter is incorrect.
Questions:
Is it possible to see the 100% raw representation of what is being ran? It does not match the return value of .String()
Is there a better way to call an os level command that I am missing?
Real Example:
cmd := &exec.Cmd{
Path: awsPath,
Args: args,
Stdout: &stdout,
Stderr: &stderr,
}
fmt.Printf("Command: %s\n", cmd.String())
// c:\PROGRA~1\Amazon\AWSCLIV2\aws.exe --profile testprofile --region us-east-1 --output json ec2 describe-network-interfaces --filters Name=group-id,Values=sg-abc123
// Running above works 100% of the time if ran from a shell window
err := cmd.Run()
// always errors out saying the format is incorrect
GoPlayground Replication of Issue
https://play.golang.org/p/mvV9VG8F0oz
From cmd.String source:
// String returns a human-readable description of c.
// It is intended only for debugging.
// In particular, it is not suitable for use as input to a shell.
// The output of String may vary across Go releases.
You are seeing the reverse, but the problem is the same: eye-balling a printed command string does not show the exact executable path (is there a rogue space or unprintable character?), same with the arguments (rogue characters?).
Use fmt.Printf("cmd : %q\n", cmd.Path) to show any hidden unicode characters etc. And use the same technique with each of the arguments.
EDIT:
I have found the root cause of your problem you met: os/exec
// Path is the path of the command to run.
//
// This is the only field that must be set to a non-zero
// value. If Path is relative, it is evaluated relative
// to Dir.
Path string
// Args holds command line arguments, including the command as **Args[0]**.
// If the Args field is empty or nil, Run uses {Path}.
//
// In typical use, both Path and Args are set by calling Command.
Args []string
So if you have declare the Cmd.Path := "/usr/local/bin/aws", you have to declare Cmd. Args like this: Args: []string{"", "s3", "help"}, because the Args including the command as Args[0] in above document link.
Final, I think you can exec command like this for simple and effectively:
package main
import (
"bytes"
"fmt"
"os/exec"
)
func main() {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
name := "/usr/local/bin/aws"
arg := []string{"s3", "help"}
cmd := exec.Command(name, arg...)
cmd.Stderr = stderr
cmd.Stdout = stdout
fmt.Printf("Command: %q\n", cmd.String())
err := cmd.Run()
if err != nil {
fmt.Println("Error: ", stderr.String())
}
fmt.Println("Output: ", stdout.String())
}
=========
$ go run main.go
Command: "/usr/local/bin/aws s3 help"
Done.

How does cobra commander for go (golang) work?

I am trying to understand how to create costume commands for go using the cobra (and viper) libraries and be able to use them.
Specifically I was trying to understand and make the example they provide work. The example is the following:
import(
"github.com/spf13/cobra"
"fmt"
"strings"
)
func main() {
var echoTimes int
var cmdPrint = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdTimes = &cobra.Command{
Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing
a count and a string.`,
Run: func(cmd *cobra.Command, args []string) {
for i:=0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}
However, I have made the file for it, in package main and I can't seem to make it work properly. I do understand that the rootCmd is not suppose to be executable. However, it seems to me that the Use field behaves inconsistently (as far as I can tell). I was trying to understand how commands actually run in the command line and compile the file in different ways to experiment this.
For example I compiled this file I named as cobra.go with go build cobra.go and now I have an executable cobra.
If I do ./name it behaves the same way as ./name help and prints:
Usage:
app [command]
Available Commands:
print [string to print] Print anything to the screen
echo [string to echo] Echo anything to the screen
help [command] Help about any command
Available Flags:
--help=false: help for app
Use "app help [command]" for more information about that command.
However the description incorrectly says that to use it you must do "app help [command]".
If I do that ./app help print (with only the cobra executable of course) it prints:
zsh: no such file or directory: ./app
if I do app help print it also doesn't work (since it isn't found in PATH):
zsh: command not found: app
So my understanding is that, unless I build it with the same name as root, cobra will act funny.
So it means that the use field has to match the file name for the output of help to make sense and for us to be able to run its sub commands properly, right?
Also, how is one able to have (compile) multiple different "root" commands in the same project, if only one package main is allowed? If one has multiple "root" commands under main, it shouldn't work, right? I will try some of these ideas soon.
You could check how cobra is used is other projects (go-search).
For instance, the bitballoon-cli project defines multiple commands, each in their own file, each in the main package. Like create.go:
package main
import (
"github.com/BitBalloon/bitballoon-go"
"github.com/spf13/cobra"
"log"
)
var createCmd = &cobra.Command{
Use: "create",
Short: "create a new BitBalloon site",
Long: "creates a new BitBalloon site and returns an ID you can deploy to",
}
var siteName, customDomain, password, notificationEmail string
func init() {
createCmd.Run = create
createCmd.Flags().StringVarP(&siteName, "name", "n", "", "Name of the site (must be a valid subdomain: <name>.bitballoon.com)")
createCmd.Flags().StringVarP(&customDomain, "domain", "d", "", "Custom domain for the site (only works for premium sites)")
createCmd.Flags().StringVarP(&password, "password", "p", "", "Password for the site")
createCmd.Flags().StringVarP(&notificationEmail, "email", "e", "", "Notification email for form submissions (only works for premium sites)")
}
func create(cmd *cobra.Command, args []string) {
// your function for this command
}
You could check if that way of defining and adding a command to your project works in your case.
4 years later, see the video "justforfunc #32: CLI tools with Cobra", by Francesc Campoy.

Printing output to a command window when golang application is compiled with -ldflags -H=windowsgui

I have an application that usually runs silent in the background, so I compile it with
go build -ldflags -H=windowsgui <gofile>
To check the version at the command line, I wanted to pass a -V flag to the command line to get the string holding the version to be printed to the command prompt then have the application exit. I added the flag package and code. When I test it with
go run <gofile> -V
...it prints the version fine. When I compile the exe, it just exits, printing nothing. I suspect it's the compilation flag causing it to not access the console and sending my text into the bit bucket.
I've tried variations to print to stderr and stdout, using println and fprintf and os.stderr.write, but nothing appears from the compiled application. How should I try printing a string to the command prompt when compiled with those flags?
The problem is that when a process is created using an executable which has the "subsystem" variable in its PE header set to "Windows", the process has its three standard handles closed and it is not associated with any console—no matter if you run it from the console or not. (In fact, if you run an executable which has its subsystem set to "console" not from a console, a console is forcibly created for that process and the process is attached to it—you usually see it as a console window popping up all of a sudden.)
Hence, to print anything to the console from a GUI process on Windows you have to explicitly connect that process to the console which is attached to its parent process (if it has one), like explained here for instance. To do this, you call the AttachConsole API function. With Go, this can be done using the syscall package:
package main
import (
"fmt"
"syscall"
)
const (
ATTACH_PARENT_PROCESS = ^uint32(0) // (DWORD)-1
)
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procAttachConsole = modkernel32.NewProc("AttachConsole")
)
func AttachConsole(dwParentProcess uint32) (ok bool) {
r0, _, _ := syscall.Syscall(procAttachConsole.Addr(), 1, uintptr(dwParentProcess), 0, 0)
ok = bool(r0 != 0)
return
}
func main() {
ok := AttachConsole(ATTACH_PARENT_PROCESS)
if ok {
fmt.Println("Okay, attached")
}
}
To be truly complete, when AttachConsole() fails, this code should probably take one of these two routes:
Call AllocConsole() to get its own console window created for it.
It'd say this is pretty much useless for displaying version information as the process usually quits after printing it, and the resulting user experience will be a console window popping up and immediately disappearing; power users will get a hint that they should re-run the application from the console but mere mortals won't probably cope.
Post a GUI dialog displaying the same information.
I think this is just what's needed: note that displaying help/usage messages in response to the user specifying some command-line argument is quite often mentally associated with the console, but this is not a dogma to follow: for instance, try running msiexec.exe /? at the console and see what happens.
One problem with the solutions already posted here is that they redirect all output to the console, so if I run ./myprogram >file, the redirection to file gets lost. I've written a new module, github.com/apenwarr/fixconsole, that avoids this problem. You can use it like this:
import (
"fmt"
"github.com/apenwarr/fixconsole"
"os"
)
func main() {
err := fixconsole.FixConsoleIfNeeded()
if err != nil {
fmt.Fatalf("FixConsoleOutput: %v\n", err)
}
os.Stdout.WriteString(fmt.Sprintf("Hello stdout\n"))
os.Stderr.WriteString(fmt.Sprintf("Hello stderr\n"))
}
Answer above was helpful but alas it did not work for me out of the box. After some additional research I came to this code:
// go build -ldflags -H=windowsgui
package main
import "fmt"
import "os"
import "syscall"
func main() {
modkernel32 := syscall.NewLazyDLL("kernel32.dll")
procAllocConsole := modkernel32.NewProc("AllocConsole")
r0, r1, err0 := syscall.Syscall(procAllocConsole.Addr(), 0, 0, 0, 0)
if r0 == 0 { // Allocation failed, probably process already has a console
fmt.Printf("Could not allocate console: %s. Check build flags..", err0)
os.Exit(1)
}
hout, err1 := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
hin, err2 := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
if err1 != nil || err2 != nil { // nowhere to print the error
os.Exit(2)
}
os.Stdout = os.NewFile(uintptr(hout), "/dev/stdout")
os.Stdin = os.NewFile(uintptr(hin), "/dev/stdin")
fmt.Printf("Hello!\nResult of console allocation: ")
fmt.Printf("r0=%d,r1=%d,err=%s\nFor Goodbye press Enter..", r0, r1, err0)
var s string
fmt.Scanln(&s)
os.Exit(0)
}
The key point: after allocating/attaching the console, there is need to get stdout handle, open file using this handle and assign it to os.Stdout variable. If you need stdin you have to repeat the same for stdin.
You can get the desired behavior without using -H=windowsgui; you'd basically create a standard app (with its own console window), and hide it until the program exits.
func Console(show bool) {
var getWin = syscall.NewLazyDLL("kernel32.dll").NewProc("GetConsoleWindow")
var showWin = syscall.NewLazyDLL("user32.dll").NewProc("ShowWindow")
hwnd, _, _ := getWin.Call()
if hwnd == 0 {
return
}
if show {
var SW_RESTORE uintptr = 9
showWin.Call(hwnd, SW_RESTORE)
} else {
var SW_HIDE uintptr = 0
showWin.Call(hwnd, SW_HIDE)
}
}
And then use it like this:
func main() {
Console(false)
defer Console(true)
...
fmt.Println("Hello World")
...
}
If you build a windowless app you can get output with PowerShell command Out-String
.\\main.exe | out-string
your build command may look like:
cls; go build -i -ldflags -H=windowsgui main.go; .\\main.exe | out-string;
or
cls; go run -ldflags -H=windowsgui main.go | out-string
No tricky syscalls nor kernel DLLs needed!

Resources