//go:build windows package main import ( "fmt" "os" "strings" "syscall" "unsafe" ) var ( shell32 = syscall.NewLazyDLL("shell32.dll") shellExecuteW = shell32.NewProc("ShellExecuteW") isUserAnAdminProc = shell32.NewProc("IsUserAnAdmin") errCancelledByUser = uintptr(1223) ) func isElevated() bool { ret, _, _ := isUserAnAdminProc.Call() return ret != 0 } func relaunchElevated() error { exePath, err := os.Executable() if err != nil { return err } verb, err := syscall.UTF16PtrFromString("runas") if err != nil { return err } file, err := syscall.UTF16PtrFromString(exePath) if err != nil { return err } args, err := syscall.UTF16PtrFromString(joinWindowsArgs(os.Args[1:])) if err != nil { return err } ret, _, callErr := shellExecuteW.Call( 0, uintptr(unsafe.Pointer(verb)), uintptr(unsafe.Pointer(file)), uintptr(unsafe.Pointer(args)), 0, 1, ) if ret <= 32 { if ret == errCancelledByUser { return fmt.Errorf("administrator privileges were not granted") } if callErr != syscall.Errno(0) { return fmt.Errorf("ShellExecuteW failed: %w", callErr) } return fmt.Errorf("ShellExecuteW failed with code %d", ret) } return nil } func joinWindowsArgs(args []string) string { if len(args) == 0 { return "" } quoted := make([]string, 0, len(args)) for _, arg := range args { escaped := strings.ReplaceAll(arg, `"`, `\"`) quoted = append(quoted, `"`+escaped+`"`) } return strings.Join(quoted, " ") }