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>
If you need to run a PowerShell script as an administrator, you will need to open PowerShell in administrative mode. To do so, find PowerShell on the Start menu, right click on the PowerShell icon, and then select More | Run as Administrator from the shortcut menu.
To start a Windows PowerShell session in a Command Prompt window, type PowerShell . A PS prefix is added to the command prompt to indicate that you are in a Windows PowerShell session. PowerShell.exe -help PowerShell.exe -? PowerShell.exe /?
Step 1: Open the Command Prompt, and type the PowerShell as a command, then press Enter key. Step 2: Now, the command prompt will turn to Windows PowerShell. Step 3: Type the command start-process PowerShell -verb runas and press "enter" key. Step 4: It will bring up an elevated Windows PowerShell as an administrator.
Windows PowerShell is a command-line interface for Windows computers. A command-line interface (CLI) is a program for telling your computer to do tasks using typed commands, rather than by clicking pictures on the desktop as in a graphical user interface (GUI).
Fixed it.
The user Tom cannot access the C:\Stackoverflow
folder by default, in order for anything to run, I had to give Everyone access to Read/Execute items in that folder, else the start-process failed miserably
Add profilepath to the net user command. This prevented the extra folders being created that I mentioned in a comment:
net user Tom _Jerry123_ /add /expires:never /passwordchg:no /homedir:C:\Users\Tom /profilepath:C:\Users\Tom /y
Replace the Start-Process
line with:
Start-Process C:\stackoverflow\whoami.bat -WorkingDirectory C:\Users\Tom -Credential ($credentials) -Wait
Why?
With the working directory set to C:\StackOverflow, the command interpreter that is executing the batch file finds the whoami.bat
before the builtin, and all kinds of broken happens. Once I moved the working directory to Tom's folder, everything worked exactly as you wanted.
Alternative:
Don't name your batch files the same as builtin commands.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With