How to call Powershell from Go faster?

Issue

A program written in Go does certain tasks by shelling out to PowerShell. This is slow because each call to exec.Command() starts up PowerShell, runs one command, then exits. We’re running hundreds of commands and starting PowerShell hundreds of times is a large overhead.

If the commands were known ahead of time, we could simply generate powershell script and execute it. However the commands that need to be run are generated dynamically, therefore this won’t work for us.

Here’s the code we use to run command

  out, err := exec.Command("powershell", "-NoProfile", command).CombinedOutput()
  if err != nil {
    // ...
  }

Is it possible to start PowerShell once and feed it individual commands?

Update: I was asked which PS commands are being run. Some are:

  • Get-DnsServerResourceRecord -ComputerName FOO -ZoneName BAR
  • Remove-DnsServerResourceRecord -Force -ComputerName "FOO" -ZoneName "BAR" -Name "X" -RRType "Y" -RecordData "Z"
  • Add-DnsServerResourceRecordX-ComputerName FOO -ZoneName BAR ...

Update 2022-03-09: I’m embarrassed to say that I found the slowness problem and it wasn’t what I assumed when I asked the question. The PowerShell command being run was occasionally getting huge datasets that took a long time to process. So, the problem wasn’t Go or exec at all! That said, this question is still useful for people that want to batch up commands.

Solution

You can use Cmd.StdinPipe:

package main

import (
   "fmt"
   "log"
   "os/exec"
)

func main() {
   cmd := exec.Command("powershell", "-nologo", "-noprofile")
   stdin, err := cmd.StdinPipe()
   if err != nil {
      log.Fatal(err)
   }
   go func() {
      defer stdin.Close()
      fmt.Fprintln(stdin, "New-Item a.txt")
      fmt.Fprintln(stdin, "New-Item b.txt")
   }()
   out, err := cmd.CombinedOutput()
   if err != nil {
      log.Fatal(err)
   }
   fmt.Printf("%s\n", out)
}

Although, it’s a strange request, as with some work Go should pretty much be able to do anything PowerShell can do, including making Syscalls.

Answered By – Zombo

Answer Checked By – Willingham (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.