Skip to main content
The Windows Services package is Windows-only and uses the Windows Service Control Manager API.

Introduction

The winservices package provides functionality to query and monitor Windows services. It wraps the Windows Service Control Manager (SCM) API through Go’s golang.org/x/sys/windows package.

Installation

go get github.com/shirou/gopsutil/v4/winservices

Key Features

Service Information

Query service configuration including start type, executable path, and dependencies

Service Status

Get current service state, PID, and accepted control commands

List Services

Enumerate all Windows services on the system

Process Information

Get the process ID of running services for monitoring

Service Type

The main data structure representing a Windows service.
type Service struct {
    Name   string
    Config mgr.Config
    Status ServiceStatus
    srv    *mgr.Service
}

Fields

  • Name - Service name
  • Config - Service configuration (from mgr.Config)
  • Status - Current service status
  • srv - Internal service handle (private)

ServiceStatus Type

Combines service state with process information.
type ServiceStatus struct {
    State         svc.State      // Current service state
    Accepts       svc.Accepted   // Accepted control commands
    Pid           uint32         // Process ID (if running)
    Win32ExitCode uint32         // Last exit code
}

State Values

The State field uses svc.State type:
  • svc.Stopped - Service is stopped
  • svc.StartPending - Service is starting
  • svc.StopPending - Service is stopping
  • svc.Running - Service is running
  • svc.ContinuePending - Service continue is pending
  • svc.PausePending - Service pause is pending
  • svc.Paused - Service is paused

Accepts Values

The Accepts field indicates which control commands the service accepts:
  • svc.AcceptStop - Can be stopped
  • svc.AcceptPauseAndContinue - Can be paused/continued
  • svc.AcceptShutdown - Can handle system shutdown
  • svc.AcceptParamChange - Can handle parameter changes
  • svc.AcceptNetBindChange - Can handle network binding changes

Core Functions

NewService

Creates a new Service instance for the specified service name.
func NewService(name string) (*Service, error)

Example

import (
    "fmt"
    "log"
    "github.com/shirou/gopsutil/v4/winservices"
)

func main() {
    service, err := winservices.NewService("wuauserv") // Windows Update service
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Service: %s\n", service.Name)
}
Creating a service requires opening a handle to the Service Control Manager. Ensure your application has appropriate permissions.

GetServiceDetail

Retrieves complete service information including configuration and status.
func (s *Service) GetServiceDetail() error
func (s *Service) GetServiceDetailWithContext(ctx context.Context) error
This populates both Config and Status fields of the Service struct.

Example

import (
    "fmt"
    "log"
    "github.com/shirou/gopsutil/v4/winservices"
    "golang.org/x/sys/windows/svc"
)

func main() {
    service, err := winservices.NewService("wuauserv")
    if err != nil {
        log.Fatal(err)
    }
    
    // Populate config and status
    err = service.GetServiceDetail()
    if err != nil {
        log.Fatal(err)
    }
    
    // Access configuration
    fmt.Printf("Display Name: %s\n", service.Config.DisplayName)
    fmt.Printf("Description: %s\n", service.Config.Description)
    fmt.Printf("Binary Path: %s\n", service.Config.BinaryPathName)
    
    // Access status
    fmt.Printf("State: %v\n", service.Status.State)
    if service.Status.State == svc.Running {
        fmt.Printf("PID: %d\n", service.Status.Pid)
    }
}

QueryServiceConfig

Retrieves only the service configuration.
func (s *Service) QueryServiceConfig() (mgr.Config, error)
func (s *Service) QueryServiceConfigWithContext(ctx context.Context) (mgr.Config, error)

mgr.Config Structure

Returns mgr.Config from golang.org/x/sys/windows/svc/mgr:
type Config struct {
    ServiceType      uint32
    StartType        uint32
    ErrorControl     uint32
    BinaryPathName   string   // Path to service executable
    LoadOrderGroup   string
    TagId            uint32
    Dependencies     []string // Service dependencies
    ServiceStartName string   // Account name
    DisplayName      string   // Friendly name
    Password         string
    Description      string
}

Example

service, err := winservices.NewService("wuauserv")
if err != nil {
    log.Fatal(err)
}

config, err := service.QueryServiceConfig()
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Service: %s\n", config.DisplayName)
fmt.Printf("Executable: %s\n", config.BinaryPathName)
fmt.Printf("Start Type: %d\n", config.StartType)

if len(config.Dependencies) > 0 {
    fmt.Println("Dependencies:")
    for _, dep := range config.Dependencies {
        fmt.Printf("  - %s\n", dep)
    }
}

QueryStatus

Retrieves only the current service status.
func (s *Service) QueryStatus() (ServiceStatus, error)
func (s *Service) QueryStatusWithContext(ctx context.Context) (ServiceStatus, error)

Example

import (
    "fmt"
    "log"
    "golang.org/x/sys/windows/svc"
    "github.com/shirou/gopsutil/v4/winservices"
)

service, err := winservices.NewService("wuauserv")
if err != nil {
    log.Fatal(err)
}

status, err := service.QueryStatus()
if err != nil {
    log.Fatal(err)
}

fmt.Printf("State: %v\n", status.State)
fmt.Printf("PID: %d\n", status.Pid)
fmt.Printf("Exit Code: %d\n", status.Win32ExitCode)

if status.Accepts&svc.AcceptStop != 0 {
    fmt.Println("Service can be stopped")
}
if status.Accepts&svc.AcceptPauseAndContinue != 0 {
    fmt.Println("Service can be paused/continued")
}

ListServices

Enumerates all Windows services on the system.
func ListServices() ([]Service, error)
This function returns services with only the Name field populated. Call GetServiceDetail() on each service to retrieve full information.

Example: List All Services

import (
    "fmt"
    "log"
    "github.com/shirou/gopsutil/v4/winservices"
)

func main() {
    services, err := winservices.ListServices()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Found %d services\n\n", len(services))
    
    for _, svc := range services {
        fmt.Printf("- %s\n", svc.Name)
    }
}

Example: List Running Services

import (
    "fmt"
    "log"
    "golang.org/x/sys/windows/svc"
    "github.com/shirou/gopsutil/v4/winservices"
)

func main() {
    services, err := winservices.ListServices()
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println("Running services:\n")
    
    for _, service := range services {
        // Query status for each service
        s, err := winservices.NewService(service.Name)
        if err != nil {
            continue
        }
        
        status, err := s.QueryStatus()
        if err != nil {
            continue
        }
        
        if status.State == svc.Running {
            config, _ := s.QueryServiceConfig()
            fmt.Printf("%-30s PID: %-6d %s\n",
                service.Name,
                status.Pid,
                config.DisplayName,
            )
        }
    }
}

Complete Example: Service Monitor

package main

import (
    "fmt"
    "log"
    "time"
    "golang.org/x/sys/windows/svc"
    "github.com/shirou/gopsutil/v4/winservices"
)

func monitorService(serviceName string) {
    service, err := winservices.NewService(serviceName)
    if err != nil {
        log.Fatal(err)
    }
    
    ticker := time.NewTicker(5 * time.Second)
    defer ticker.Stop()
    
    fmt.Printf("Monitoring service: %s\n\n", serviceName)
    
    for range ticker.C {
        status, err := service.QueryStatus()
        if err != nil {
            log.Printf("Error: %v", err)
            continue
        }
        
        timestamp := time.Now().Format("15:04:05")
        stateStr := stateToString(status.State)
        
        if status.State == svc.Running {
            fmt.Printf("[%s] %s (PID: %d)\n", timestamp, stateStr, status.Pid)
        } else {
            fmt.Printf("[%s] %s\n", timestamp, stateStr)
        }
    }
}

func stateToString(state svc.State) string {
    switch state {
    case svc.Stopped:
        return "STOPPED"
    case svc.StartPending:
        return "STARTING"
    case svc.StopPending:
        return "STOPPING"
    case svc.Running:
        return "RUNNING"
    case svc.ContinuePending:
        return "CONTINUE PENDING"
    case svc.PausePending:
        return "PAUSE PENDING"
    case svc.Paused:
        return "PAUSED"
    default:
        return "UNKNOWN"
    }
}

func main() {
    if len(os.Args) < 2 {
        log.Fatal("Usage: program <service-name>")
    }
    
    monitorService(os.Args[1])
}

Context Support

All query functions have WithContext variants for timeout and cancellation control.
import (
    "context"
    "time"
    "github.com/shirou/gopsutil/v4/winservices"
)

ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

service, err := winservices.NewService("wuauserv")
if err != nil {
    log.Fatal(err)
}

err = service.GetServiceDetailWithContext(ctx)
if err != nil {
    // Handle timeout or cancellation
}

Common Service Names

Some commonly queried Windows services:
  • wuauserv - Windows Update
  • Spooler - Print Spooler
  • Dhcp - DHCP Client
  • Dnscache - DNS Client
  • EventLog - Windows Event Log
  • W32Time - Windows Time
  • WinDefend - Windows Defender
  • MSSQLSERVER - SQL Server (if installed)

Requirements

Platform: Windows only (uses //go:build windows build tag)Permissions: Querying service information typically requires:
  • Standard user privileges for read-only operations
  • Administrator privileges for sensitive services or system services

Error Handling

Common errors you may encounter:
service, err := winservices.NewService("nonexistent")
if err != nil {
    // Handle error - service not found or access denied
    log.Printf("Error opening service: %v", err)
}
Errors can occur due to:
  • Service does not exist
  • Insufficient permissions
  • Service Control Manager is unavailable
  • Invalid service name format

API Reference

The package wraps the following Windows APIs:
  • OpenSCManager - Opens Service Control Manager
  • OpenService - Opens a service handle
  • QueryServiceConfig - Queries service configuration
  • QueryServiceConfig2 - Queries extended configuration
  • QueryServiceStatusEx - Queries service status with process info
  • EnumServicesStatusEx - Enumerates services (via ListServices)
For detailed Windows API documentation, see: https://docs.microsoft.com/en-us/windows/win32/services/service-functions

Build docs developers (and LLMs) love