Go对windows的相关操作

2024/5/8 windows

# golang windows程序获取管理员权限

在windows上执行有关系统设置命令的时候需要管理员权限才能操作,比如修改网卡的禁用、启用状态。双击执行是不能正确执行命令的,只有右键以管理员身份运行才能成功,解决这个问题操作如下:

  1. 下载rsrc

    #项目的terminal执行
    Go get github.com/akavel/rsrc
    
    1
    2
  2. 把nac.manifest 文件拷贝到当前windows项目根目录

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
    <requestedPrivileges>
    <requestedExecutionLevel level="requireAdministrator"/>
    </requestedPrivileges>
    </security>
    </trustInfo>
    </assembly>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  3. 安装rsrc

    #安装完成后在GOPATH的bin下面会有一个rsrc.exe的可执行文件
    go install github.com/akavel/rsrc
    #执行命令出现内容说明安装成功
    rsrc
    
    1
    2
    3
    4
  4. 生成nac.syso

    #执行完成后项目中会出现nac.syso文件
    rsrc -manifest nac.manifest -o nac.syso
    
    1
    2
  5. 正常打包即可

# golang 安装证书

// 安装证书---需要管理员权限
func installCa() {
	//获取要安装的证书位置
	caPath := "/rootCA.pem"
	//执行命令
	err := cmd.Run("certutil", "-addstore", "root", caPath)
	if err != nil {
		log.Error("certutil---v%", err)
	}
}
1
2
3
4
5
6
7
8
9
10
// 运行命令
func Run(name string, arg ...string) error {
	cmd := exec.Command(name, arg...)
	log.Debug("run cmd: %v", cmd.Args)
	cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	stdout := new(bytes.Buffer)
	stderr := new(bytes.Buffer)
	writer := io.MultiWriter(stdout, stderr)
	reader := io.MultiReader(stdout, stderr)
	cmd.Stdout = writer
	cmd.Stderr = writer
	decoder := simplifiedchinese.GBK.NewDecoder()
	err := cmd.Run()
	buf := make([]byte, 4096)
	n, _ := reader.Read(buf)
	outMsg, _ := decoder.Bytes(buf[:n])
	if err != nil {
		log.Error("run cmd error: %v, %s", err, outMsg)
	} else {
		log.Debug("%s", outMsg)
	}
	return err
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# golang注册系统服务

参考文档:https://cloud.tencent.com/developer/article/2370130

官网文档:https://www.nssm.cc/

# 1、使用nssm安装

  1. 下载nssm.exe文件,放入项目中

  2. main方法中进行安装

  3. demo地址

    链接:https://pan.baidu.com/s/16cv5eUIJbuEGQ542Es2giQ?pwd=alte 
    提取码:alte
    
    1
    2
    package main
    
    import (
    	"os"
    	"os/exec"
    	"os/signal"
    	"svc-demo/log"
    	"syscall"
    	"time"
    )
    
    const (
    	SVC_NAME = "服务名称"
    	SVC_DESC = "服务说明"
        NSSM     = "nssm.exe的路径"
    )
    
    func main() {
    	if len(os.Args) > 1 {
    		if os.Args[1] == "serve" {
                //运行程序
    			serve()
    		} else {
    			log.Errorf("invalid running mode %s", os.Args[1])
    		}
    	} else { 
            // 注册系统服务
    		install()
    	}
    }
    
    func install() {
    	log.Info("install service...")
    	executable, _ := os.Executable()
    	// nssm.exe stop svc-demo
    	err := runCommand(NSSM, "stop", SVC_NAME)
    	if err != nil {
    		log.Warnf("stop service failed: %v", err)
    	}
    	// nssm.exe remove svc-demo confirm
    	err = runCommand(NSSM, "remove", SVC_NAME, "confirm")
    	if err != nil {
    		log.Warnf("remove service failed: %v", err)
    	}
    	// nssm.exe install svc-demo "C:\xxx\svc-demo.exe" serve
    	err = runCommand(NSSM, "install", SVC_NAME, executable, "serve")
    	if err != nil {
    		log.Errorf("install service failed: %v", err)
    	}
    	// nssm.exe set NAME Description
    	err = runCommand(NSSM, "set", SVC_NAME, "Description", SVC_DESC)
    	if err != nil {
    		log.Errorf("set service description failed: %v", err)
    	}
    	log.Info("install service success!")
    	// nssm.exe start svc-demo
    	err = runCommand(NSSM, "start", SVC_NAME)
    	if err != nil {
    		log.Errorf("start service failed: %v", err)
    	}
    }
    
    func serve() {
    	log.Info("svc-demo started!")
    	done := make(chan interface{}, 1)
    	go func() {
    		//此地方进行业务逻辑的开发...
    	}()
    	sign := make(chan os.Signal, 1)
    	signal.Notify(sign, syscall.SIGINT, syscall.SIGTERM)
    	done <- <-sign
    	log.Info("svc-demo stopped!")
    }
    
    func runCommand(name string, args ...string) error {
    	log.Debugf("run command: %s %v", name, args)
    	cmd := exec.Command(name, args...)
    	cmd.SysProcAttr = &syscall.SysProcAttr{
    		HideWindow: true,
    	}
    	if err := cmd.Start(); err != nil {
    		return err
    	}
    	return cmd.Wait()
    }
    
    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

# 2、使用github.com/kardianos/service安装

参考文档:

https://www.bilibili.com/video/BV1XN4y1h7sb/?vd_source=7366cbc6dc577f4fde59f655b38c94a1

https://blog.csdn.net/peihexian/article/details/105279057

  1. 下载第三方包

    go get github.com/kardianos/service		//主要用于windows和linux作为服务运行的应用程序
    go get github.com/shirou/gopsutil/process	//主要用于获取进程信息
    
    1
    2
  2. 代码编写

    package main
     
    import (
    	"fmt"
    	"github.com/beevik/ntp"
    	"github.com/kardianos/service"
    	"github.com/mako2kano/systime"
    	"os"
    	"time"
    )
     
    func main(){
    	//以下为启动windows或者linux 服务相关的配置及初始化代码
    	svcConfig := &service.Config{
    		Name:         "goNtpClient",   //服务名称
    		DisplayName:  "goNtpClient", //服务说明
    		Description:  "自动校时程序",
    		Dependencies: []string{}, //无依赖
    	}
    	prg := &program{}
    	s, err := service.New(prg, svcConfig)
    	if err != nil {
    		fmt.Println(err.Error())
    		return
    	}
    	if len(os.Args) > 1 {
    		if os.Args[1] == "install" {
    			s.Install()
    			fmt.Println("服务安装成功")
    			return
    		}
     
    		if os.Args[1] == "remove" {
    			s.Uninstall()
    			fmt.Println("服务卸载成功")
    			return
    		}
    		fmt.Println("请使用程序名称 install 命令安装为服务,或者程序名称 remove 命令卸载服务!")
    		return
    	}
     
    	err = s.Run() //会触发Start()函数的执行
    	if err != nil {
    		fmt.Println(err.Error())
    		return
    	}
    }
     
    type program struct{} //用于windows/linux service服务控制
     
    func (p *program) Start(s service.Service) error {
    	// Start should not block. Do the actual work async.
    	go p.run()
    	return nil
    }
    func (p *program) run() {
    	time.LoadLocation("Asia/Shanghai")
     
    	for {
    		syncDateTime()
    		time.Sleep(time.Minute*30)
    	}
    }
     
    func (p *program) Stop(s service.Service) error {
    	// Stop should not block. Return with a few seconds.
     
    	return nil
    }
     
    func syncDateTime()  {
    	ntpServerIp:="ntp4.aliyun.com"
    	tm, err := ntp.Time(ntpServerIp)
    	if nil!=err {
    		fmt.Println(err.Error())
    		return
    	}
    	//fmt.Println(tm.Format("2006-01-02 15:04:05"))
    	err = systime.SetLocalTime(&tm)
    	if nil!=err {
    		fmt.Println(err.Error())
    		return
    	}
    }
    
    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

# msi安装包打包工具

advanced installer工具:

https://blog.csdn.net/qq_41750806/article/details/122166802

inno setup:

https://blog.csdn.net/z37411/article/details/129443045