/home/josephspurrier

Prevent Escaping exec.Command Arguments in Go

In Go, I was trying to add the ability to run administrative installations in my project on GitHub: Portable App Creator.

The actual command I need the Go application to run on Windows is:

msiexec /a "package.msi" TARGETDIR="C:\test folder"

Edit on 5/6/2016: It looks like there are applications that parse arguments differently depending on the compiler. Source. The application, msiexec.cmd (and cmd.exe), handle spaces and quotes differently than how Go escapes them.

In Go, the exec package references the syscall package that escapes the arguments using this func: EscapeArg().

Luckily, there is a way around that escape func. Look at the note for SysProcAttr.CmdLine:

type SysProcAttr struct {
	HideWindow    bool
	CmdLine       string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
	CreationFlags uint32
}

We can manually set CmdLine and then assign it to Cmd.SysProcAttr like this:

// Set the file and directory name
msiFile := `package.msi`
targetDir := `C:\test folder`

// Set to the misexec application, but don't pass command line arguments
cmd := exec.Command("msiexec")

// Manually set the command line arguments so they are not escaped
cmd.SysProcAttr = &syscall.SysProcAttr{
    HideWindow:    false,
    CmdLine:       fmt.Sprintf(` /a "%v" TARGETDIR="%v"`, msiFile, targetDir), // Leave a space at the beginning
    CreationFlags: 0,
}

// Run the install
err := cmd.Run()
if err != nil {
    log.Fatalln(err)
}

I submitted an issue to Go for clarification: 15566

Here are other articles for reference:

#go #code