
本文介绍在 go 语言中获取 windows 系统已安装服务列表的实用方法,由于标准库不支持该功能,需通过调用系统命令 sc query state=all 并解析其输出实现。
在 Go 的标准库中,没有原生跨平台或 Windows 专用的 API 用于枚举系统服务(如 Windows Service Control Manager 中注册的服务)。这与获取进程列表(可通过 psutil 类第三方库或 os/exec 调用 tasklist)不同——服务管理属于操作系统内核级抽象,Go 标准库出于可移植性与设计哲学考量,未封装此类平台专属能力。
因此,推荐方案是:使用 os/exec 包执行 Windows 内置服务控制工具 sc.exe,并解析其结构化输出。最常用且稳定的命令是:
sc query state=all
该命令会列出所有服务(无论运行、停止、暂停或禁用状态),每项以 SERVICE_NAME:、DISPLAY_NAME:、STATE: 等字段标识,格式稳定、无需额外依赖。
以下是一个完整、健壮的 Go 示例,用于获取服务名称与状态:
package main
import (
"bufio"
"fmt"
"os/exec"
"strings"
)
type Service struct {
Name string
DisplayName string
State string // e.g., "RUNNING", "STOPPED", "DISABLED"
}
func listWindowsServices() ([]Service, error) {
cmd := exec.Command("sc", "query", "state=all")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to run sc command: %w", err)
}
var services []Service
scanner := bufio.NewScanner(strings.NewReader(string(output)))
var current Service
inServiceBlock := false
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "[") || line == "" {
continue // skip headers and empty lines
}
// Detect new service block (starts with SERVICE_NAME:)
if strings.HasPrefix(line, "SERVICE_NAME:") {
if inServiceBlock && current.Name != "" {
services = append(services, current)
}
current = Service{Name: strings.TrimPrefix(line, "SERVICE_NAME:")}
current.Name = strings.TrimSpace(current.Name)
inServiceBlock = true
} else if strings.HasPrefix(line, "DISPLAY_NAME:") {
current.DisplayName = strings.TrimPrefix(line, "DISPLAY_NAME:")
current.DisplayName = strings.TrimSpace(current.DisplayName)
} else if strings.HasPrefix(line, "STATE:") {
parts := strings.Fields(line)
if len(parts) > 1 {
current.State = parts[1] // e.g., "4 RUNNING" → take "RUNNING"
}
}
}
// Don't forget the last service
if inServiceBlock && current.Name != "" {
services = append(services, current)
}
return services, scanner.Err()
}
func main() {
svcs, err := listWindowsServices()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Found %d services:\n", len(svcs))
for _, s := range svcs[:min(10, len(svcs))] { // show first 10
fmt.Printf("- %s (%s): %s\n", s.Name, s.DisplayName, s.State)
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}✅ 注意事项:
- 该方法仅适用于 Windows,不可跨平台;若需多平台支持,应结合 runtime.GOOS 做条件编译或抽象接口。
- sc query state=all 需要普通用户权限即可运行(无需管理员),但部分隐藏/驱动类服务可能仍受限。
- 输出格式虽稳定,但仍建议做容错解析(如跳过空行、忽略非关键字段、处理截断显示等),避免因系统语言或版本微小差异导致 panic。
- 如需更精细控制(如启动/停止服务),可进一步调用 sc start
/ sc stop ,但务必加入权限校验与错误重试逻辑。
总结:Go 不提供服务枚举的内置能力,但借助 os/exec 调用 sc 是简洁、可靠、零依赖的 Windows 解决方案。掌握此模式,也能轻松扩展至其他系统管理任务(如查询防火墙规则、注册表项或 WMI 数据)。










