1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package powershell
import (
"bytes"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"github.com/crc-org/crc/v2/pkg/crc/logging"
)
var isAdminCmds = []string{
"$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())",
"$currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)",
}
func IsAdmin() bool {
cmd := strings.Join(isAdminCmds, ";")
stdOut, _, err := Execute(cmd)
if err != nil {
return false
}
if strings.TrimSpace(stdOut) == "False" {
return false
}
return true
}
func Execute(args ...string) (string, string, error) {
logging.Debugf("Running '%s'", strings.Join(args, " "))
powershell, err := exec.LookPath("powershell.exe")
if err != nil {
return "", "", err
}
args = append([]string{"-NoProfile", "-NonInteractive", "-ExecutionPolicy", "RemoteSigned", "-Command", "$ProgressPreference = 'SilentlyContinue';"}, args...)
cmd := exec.Command(powershell, args...) // #nosec G204
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
logging.Debugf("Command failed: %v", err)
logging.Debugf("stdout: %s", stdout.String())
logging.Debugf("stderr: %s", stderr.String())
}
return stdout.String(), stderr.String(), err
}
func ExecuteAsAdmin(reason, cmd string) (string, string, error) {
powershell, err := exec.LookPath("powershell.exe")
if err != nil {
return "", "", err
}
scriptContent := strings.Join(append(runAsCmds(powershell), cmd), "\n")
tempDir, err := os.MkdirTemp("", "crcScripts")
if err != nil {
return "", "", err
}
defer os.RemoveAll(tempDir)
// Write a temporary script
/* Add UTF-8 BOM at the beginning of the script so that Windows
* correctly detects the file encoding
*/
filename := filepath.Join(tempDir, "runAsAdmin.ps1")
// #nosec G306
if err := os.WriteFile(filename, append([]byte{0xef, 0xbb, 0xbf}, []byte(scriptContent)...), 0666); err != nil {
return "", "", err
}
logging.Infof("Will run as admin: %s", reason)
return Execute(filename)
}
func runAsCmds(powershell string) []string {
return []string{
`$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();`,
`$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);`,
`$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;`,
`if (-Not ($myWindowsPrincipal.IsInRole($adminRole))) {`,
` $procInfo = New-Object System.Diagnostics.ProcessStartInfo;`,
` $procInfo.FileName = "` + powershell + `"`,
` $procInfo.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden`,
` $procInfo.Arguments = "-ExecutionPolicy RemoteSigned & '" + $script:MyInvocation.MyCommand.Path + "'"`,
` $procInfo.Verb = "runas";`,
` $p = New-Object System.Diagnostics.Process`,
` $p.StartInfo = $procInfo`,
` $p.Start() | Out-Null`,
` $p.WaitForExit()`,
` if ($p.ExitCode -ne 0) {`,
` throw "Unexpected failure";`,
` }`,
` Exit;`,
`}`,
}
}
|