I wish to run a Windows batch script from go, under a different user to the user running the go program. The user running go has more privileges than the user that should run the batch script.
From go there are several options for executing a process under a different user on Windows, such as writing windows calls directly using the syscall package in go. I have not attempted this yet, but I have tried both using PsExec and also Powershell. Powershell is preferred since it comes installed as standard on Windows 2008 R2.
The following code demonstrates the problem I have. In the following demo, I run a batch script. This batch script calls a Powershell script directly, and then calls it from a go program. The results are different. The Powershell script outputs 3 files, yet when called from go, only outputs 2 files.
For the sake of completeness, I also show how the user was created.
C:\stackoverflow\demo.bat:
::::: create a new user for the demo :::::
:: first create a home directory
mkdir C:\Users\Tom
:: remove Users group
icacls C:\Users\Tom /remove:g Users
:: remove Everyone
icacls C:\Users\Tom /remove:g Everyone
:: create user Tom and set his home directory
net user Tom _Jerry123_ /add /expires:never /passwordchg:no /homedir:C:\Users\Tom /y
:: Give Tom access to his home directory
icacls C:\Users\Tom /grant:r Tom:(CI)F SYSTEM:(CI)F Administrators:(CI)F
:: give him access to Remote Desktop
net localgroup "Remote Desktop Users" /add Tom
::::: now call powershell directly :::::
powershell -command C:\stackoverflow\demo.ps1
:: show which files were created
dir C:\Users\Tom
:: cleanup
del /f /q C:\Users\Tom\*
::::: run the go version to do the same thing :::::
go run C:\stackoverflow\demo.go
:: compare results
dir C:\Users\Tom
:: cleanup
del /f /s /q C:\Users\Tom
rmdir /s /q C:\Users\Tom
:: delete user
net user Tom /delete
C:\stackoverflow\demo.ps1
write-output "test output" | out-file C:\Users\Tom\started.txt
$credentials = New-Object System.Management.Automation.PSCredential -ArgumentList @("Tom",(ConvertTo-SecureString -String "_Jerry123_" -AsPlainText -Force))
Start-Process C:\stackoverflow\whoami.bat -WorkingDirectory C:\stackoverflow -Credential ($credentials) -Wait
write-output "test output" | out-file C:\Users\Tom\finished.txt
C:\stackoverflow\demo.go
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
run(exec.Command("PowerShell", "-Command", "C:\\stackoverflow\\demo.ps1"))
}
func run(cmd *exec.Cmd) {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
err := cmd.Start()
if err != nil {
panic(err)
}
err = cmd.Wait()
if err != nil {
panic(err)
}
fmt.Println("Done")
}
C:\stackoverflow\whoami.bat:
whoami > C:\Users\Tom\whoami.txt
And now, the results - here you see when called from batch script, files started.txt, whoami.txt, finished.txt all get created. When called from go, only started.txt and finished.txt get created. Why is that?
Output:
C:\stackoverflow>demo.bat
C:\stackoverflow>mkdir C:\Users\Tom
C:\stackoverflow>icacls C:\Users\Tom /remove:g Users
processed file: C:\Users\Tom
Successfully processed 1 files; Failed processing 0 files
C:\stackoverflow>icacls C:\Users\Tom /remove:g Everyone
processed file: C:\Users\Tom
Successfully processed 1 files; Failed processing 0 files
C:\stackoverflow>net user Tom _Jerry123_ /add /expires:never /passwordchg:no /homedir:C:\Users\Tom /y
The command completed successfully.
C:\stackoverflow>icacls C:\Users\Tom /grant:r Tom:(CI)F SYSTEM:(CI)F Administrators:(CI)F
processed file: C:\Users\Tom
Successfully processed 1 files; Failed processing 0 files
C:\stackoverflow>net localgroup "Remote Desktop Users" /add Tom
The command completed successfully.
C:\stackoverflow>powershell -command C:\stackoverflow\demo.ps1
C:\stackoverflow>dir C:\Users\Tom
Volume in drive C is OSDisk
Volume Serial Number is CCD6-C9E7
Directory of C:\Users\Tom
06/18/2015 06:36 AM <DIR> .
06/18/2015 06:36 AM <DIR> ..
06/18/2015 06:36 AM 28 finished.txt
06/18/2015 06:36 AM 28 started.txt
06/18/2015 06:36 AM 55 whoami.txt
3 File(s) 111 bytes
2 Dir(s) 16,489,889,792 bytes free
C:\stackoverflow>del /f /q C:\Users\Tom\*
C:\stackoverflow>go run C:\stackoverflow\demo.go
Done
C:\stackoverflow>dir C:\Users\Tom
Volume in drive C is OSDisk
Volume Serial Number is CCD6-C9E7
Directory of C:\Users\Tom
06/18/2015 06:36 AM <DIR> .
06/18/2015 06:36 AM <DIR> ..
06/18/2015 06:36 AM 28 finished.txt
06/18/2015 06:36 AM 28 started.txt
2 File(s) 56 bytes
2 Dir(s) 16,489,889,792 bytes free
C:\stackoverflow>del /f /s /q C:\Users\Tom
Deleted file - C:\Users\Tom\finished.txt
Deleted file - C:\Users\Tom\started.txt
C:\stackoverflow>rmdir /s /q C:\Users\Tom
C:\stackoverflow>net user Tom /delete
The command completed successfully.
C:\stackoverflow>