golang远程执行Windows机器命令的插件库winrm-cli的使用
winrm-cli
这是一个通过WinRM/WinRS在Windows机器上执行远程命令的Go命令行工具。
注意:此工具不支持域用户(不支持GSSAPI或Kerberos)。它主要用于在EC2 Windows机器上执行远程命令。
准备工作
为基本认证准备远程Windows机器
此项目仅支持本地账户的基本认证(不支持域用户)。远程Windows系统必须准备好winrm:
在远程主机上,以管理员身份运行PowerShell,并粘贴以下命令:
winrm quickconfig
y
winrm set winrm/config/service/Auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}'
注意:
- Windows防火墙需要运行才能执行此命令
- 不要禁用Negotiate认证,因为Windows
winrm
命令本身使用此进行内部认证 - 某些Windows 2008R2系统上
MaxMemoryPerShellMB
选项无效,这是WinRM的一个bug
构建winrm-cli
你可以从源代码构建winrm-cli:
git clone https://github.com/masterzen/winrm-cli
cd winrm-cli
make
这将生成一个名为./winrm
的二进制文件。
注意:需要Go 1.5+版本。可以通过以下命令检查你的安装:
go version
命令行使用
构建完成后,你可以像这样运行远程命令:
./winrm -hostname remote.domain.com -username "Administrator" -password "secret" "ipconfig /all"
Docker使用
构建镜像
docker build -t winrm .
使用
构建完成后,你可以像这样运行远程命令:
docker run -it --rm winrm -hostname remote.domain.com -username "Administrator" -password "secret" "ipconfig /all"
完整示例代码
以下是一个完整的Go代码示例,展示如何使用winrm-cli库:
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
// 设置远程主机信息
hostname := "remote.domain.com"
username := "Administrator"
password := "secret"
command := "ipconfig /all"
// 构建winrm命令
cmd := exec.Command("./winrm",
"-hostname", hostname,
"-username", username,
"-password", password,
command)
// 设置输出
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// 执行命令
err := cmd.Run()
if err != nil {
fmt.Printf("命令执行失败: %v\n", err)
os.Exit(1)
}
}
注意事项
- 确保远程Windows机器已正确配置WinRM服务
- 使用基本认证时传输未加密,建议在安全网络环境中使用
- 对于生产环境,建议使用更安全的认证方式
- 执行内存密集型命令时可能需要调整
MaxMemoryPerShellMB
值
更多关于golang远程执行Windows机器命令的插件库winrm-cli的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang远程执行Windows机器命令的插件库winrm-cli的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用winrm-cli在Golang中远程执行Windows命令
winrm-cli是一个Golang库,允许通过Windows远程管理(WinRM)协议在远程Windows机器上执行命令。下面我将详细介绍如何使用这个库。
安装winrm-cli
首先需要安装winrm-cli库:
go get github.com/masterzen/winrm-cli
基本用法
1. 创建WinRM客户端
package main
import (
"fmt"
"os"
"github.com/masterzen/winrm"
)
func main() {
// 配置WinRM客户端参数
endpoint := "https://192.168.1.100:5986/wsman" // WinRM端点
username := "administrator" // 管理员用户名
password := "yourpassword" // 密码
// 创建WinRM客户端
client, err := winrm.NewClient(
winrm.NewEndpoint(
endpoint, // 端点URL
5986, // 端口
false, // 是否使用HTTPS
false, // 不验证TLS证书
nil, // CA证书
nil, // 客户端证书
nil, // 客户端私钥
0, // 超时时间(0表示默认)
),
username,
password,
)
if err != nil {
fmt.Printf("创建WinRM客户端失败: %v\n", err)
os.Exit(1)
}
// 测试连接
_, err = client.Run("echo Hello, WinRM!", os.Stdout, os.Stderr)
if err != nil {
fmt.Printf("连接测试失败: %v\n", err)
os.Exit(1)
}
fmt.Println("连接成功!")
}
2. 执行远程命令
func executeRemoteCommand(client *winrm.Client, command string) (string, error) {
var stdout, stderr bytes.Buffer
exitCode, err := client.Run(command, &stdout, &stderr)
if err != nil {
return "", fmt.Errorf("执行命令失败: %v, 退出码: %d, 错误输出: %s",
err, exitCode, stderr.String())
}
if stderr.Len() > 0 {
return stdout.String(), fmt.Errorf("命令执行有错误输出: %s", stderr.String())
}
return stdout.String(), nil
}
// 使用示例
output, err := executeRemoteCommand(client, "ipconfig")
if err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Printf("命令输出:\n%s\n", output)
}
3. 执行PowerShell脚本
func executePowerShell(client *winrm.Client, script string) (string, error) {
// 将脚本转换为Base64编码,避免特殊字符问题
encodedScript := base64.StdEncoding.EncodeToString([]byte(script))
command := fmt.Sprintf("powershell -encodedcommand %s", encodedScript)
return executeRemoteCommand(client, command)
}
// 使用示例
psScript := `Get-Process | Where-Object { $_.CPU -gt 100 } | Select-Object Name, CPU`
output, err := executePowerShell(client, psScript)
if err != nil {
fmt.Printf("执行PowerShell失败: %v\n", err)
} else {
fmt.Printf("PowerShell输出:\n%s\n", output)
}
高级功能
1. 文件传输
func uploadFile(client *winrm.Client, localPath, remotePath string) error {
content, err := os.ReadFile(localPath)
if err != nil {
return fmt.Errorf("读取本地文件失败: %v", err)
}
// 将文件内容转换为Base64
encodedContent := base64.StdEncoding.EncodeToString(content)
// 创建PowerShell脚本解码并保存文件
script := fmt.Sprintf(`
$content = "%s"
$bytes = [Convert]::FromBase64String($content)
[IO.File]::WriteAllBytes("%s", $bytes)
`, encodedContent, remotePath)
_, err = executePowerShell(client, script)
return err
}
// 使用示例
err := uploadFile(client, "localfile.txt", "C:\\temp\\remotefile.txt")
if err != nil {
fmt.Printf("文件上传失败: %v\n", err)
}
2. 长时间运行命令
func runLongCommand(client *winrm.Client, command string) error {
shell, err := client.CreateShell()
if err != nil {
return fmt.Errorf("创建Shell失败: %v", err)
}
defer shell.Close()
cmd, err := shell.Execute(command)
if err != nil {
return fmt.Errorf("执行命令失败: %v", err)
}
defer cmd.Close()
var stdout, stderr bytes.Buffer
go io.Copy(&stdout, cmd.Stdout)
go io.Copy(&stderr, cmd.Stderr)
cmd.Wait()
if stderr.Len() > 0 {
return fmt.Errorf("命令执行有错误输出: %s", stderr.String())
}
fmt.Printf("命令输出:\n%s\n", stdout.String())
return nil
}
安全注意事项
- 使用HTTPS:在生产环境中始终使用HTTPS而不是HTTP
- 证书验证:应该验证服务器证书,不要跳过验证
- 凭据安全:不要将凭据硬编码在代码中,使用环境变量或配置管理工具
- 最小权限:使用具有最小必要权限的账户
完整示例
package main
import (
"bytes"
"encoding/base64"
"fmt"
"os"
"github.com/masterzen/winrm"
)
func main() {
// 从环境变量获取凭据
endpoint := os.Getenv("WINRM_ENDPOINT")
username := os.Getenv("WINRM_USERNAME")
password := os.Getenv("WINRM_PASSWORD")
if endpoint == "" || username == "" || password == "" {
fmt.Println("请设置WINRM_ENDPOINT, WINRM_USERNAME和WINRM_PASSWORD环境变量")
os.Exit(1)
}
// 创建WinRM客户端
client, err := winrm.NewClient(
winrm.NewEndpoint(
endpoint,
5986,
true, // 使用HTTPS
false, // 不验证证书(生产环境应该为true)
nil, nil, nil, 0),
username,
password,
)
if err != nil {
fmt.Printf("创建WinRM客户端失败: %v\n", err)
os.Exit(1)
}
// 执行系统信息命令
output, err := executeRemoteCommand(client, "systeminfo")
if err != nil {
fmt.Printf("获取系统信息失败: %v\n", err)
} else {
fmt.Printf("系统信息:\n%s\n", output)
}
// 执行PowerShell命令
psOutput, err := executePowerShell(client, "Get-Service | Where-Object { $_.Status -eq 'Running' }")
if err != nil {
fmt.Printf("执行PowerShell失败: %v\n", err)
} else {
fmt.Printf("运行中的服务:\n%s\n", psOutput)
}
}
// executeRemoteCommand 和 executePowerShell 函数同上文示例
winrm-cli库提供了强大的功能来远程管理Windows服务器。通过合理使用,可以构建自动化运维工具、部署脚本等。记得始终遵循安全最佳实践来保护你的远程管理连接。