Windows · Service Management

Windows Services

A Windows service keeps a piece of software running without anyone signed in to babysit it, and nearly everything that goes wrong with one — never starting, starting too early, failing silently — traces back to just two settings: its startup type and the account it’s allowed to log on as.

Quick idea: The Service Control Manager (SCM) is the single database and broker for every background program on a Windows machine — it starts services in dependency order, tracks whether each is running, and enforces which account each one is allowed to run as. Most “service won’t start” tickets aren’t a code bug in the service at all; they’re the SCM correctly refusing to start something whose account, dependency, or startup type isn’t what the ticket assumes.
SCM

The Service Control Manager — the RPC server, started at boot, that owns the services database.

services.msc

The MMC console for viewing, starting, stopping, and configuring services by hand.

Service account

The identity a service runs as — a built-in account, a domain account, or a managed service account.

What Is a Windows Service?

A Windows service is a long-running background process that starts independently of any interactive user session — no one has to be logged in for it to run, and it keeps running across logons and logoffs until the system shuts down or the service is stopped. Think of it as the opposite of a desktop application: an application waits for someone to open it, while a service is already running, quietly, before anyone signs in at all.

Three kinds of programs cooperate to make this work, and none of them talk to each other directly — they all go through the SCM. A service program is the executable that does the actual work and reports its status to the SCM. A service configuration program installs, removes, or reconfigures entries in the services database — services.msc and sc.exe are both this. A service control program starts, stops, and sends control requests to running services — Start-Service and net start fall into this category.

The Service Control Manager

The Service Control Manager starts at system boot as a remote procedure call (RPC) server, which is what lets configuration and control programs manage services on remote machines, not just the local one. It owns the services database — the authoritative record of every installed service, its configuration, and its current status — and it’s the only thing with write access to that database while the system is running.

At boot, the SCM walks the database and starts every service marked to start automatically, honoring the dependency chain declared for each one — a service that depends on another won’t be started until its dependency is already running. After boot, the SCM keeps handling on-demand start requests, tracks status for every running service, and forwards control requests like stop, pause, and continue to the services that support them.

Startup Types

Every service has a startup type that tells the SCM when, if ever, to start it. This single setting is behind the most common category of service complaint: “it works when I start it by hand, but not after a reboot.”

Startup Type Behavior
AutomaticStarts at system boot, before any user signs in.
Automatic (Delayed Start)Starts shortly after boot, once all plain Automatic services are already running — reduces contention during the boot-to-desktop window.
ManualOnly starts when explicitly requested, by a user, another service, or an application.
DisabledCannot be started at all, by anyone, until the startup type is changed.
Practical rule: Automatic (Delayed Start) exists specifically to stop non-critical services from competing with critical ones for CPU and disk I/O during boot. If a service doesn’t need to be running the instant the desktop appears, delayed start is usually the better default over plain Automatic.

You can read and change the startup type from the console, or from PowerShell without opening a GUI at all:

# View a service's current startup type and status
Get-Service -Name Spooler | Select-Object Name, StartType, Status

# Change the startup type
Set-Service -Name Spooler -StartupType Automatic

# The equivalent with sc.exe - note the required space after each "="
sc.exe config Spooler start= auto
sc.exe config Spooler start= delayed-auto
sc.exe config Spooler start= demand
sc.exe config Spooler start= disabled

Service Accounts

Every service runs under some account, and that account determines what the service can touch — locally and over the network. Getting this wrong is the other major source of service failures, usually surfacing as access-denied errors that have nothing to do with the service’s own code.

Account Local Privilege Network Identity
LocalSystemFull, unrestricted access to the local machine.Presents the computer’s own credentials to remote servers.
NetworkServiceMinimal local privileges.Also presents the computer’s credentials to remote servers.
LocalServiceMinimal local privileges.Presents anonymous credentials — no network identity at all.
Domain user accountWhatever is explicitly granted.Authenticates as that domain identity; password is a real, managed secret.
gMSA (group Managed Service Account)Whatever is explicitly granted.Domain identity with a password Windows rotates and manages automatically, usable across multiple servers.
Important: None of the three built-in accounts — LocalSystem, NetworkService, LocalService — have a password at all, so any password you supply for them is simply ignored. LocalSystem’s unrestricted local access is also exactly why it should never be the answer on a domain controller: a compromised LocalSystem service there has effectively compromised the DC.

A service running under a real domain account, or a gMSA, needs the Log on as a service user right (SeServiceLogonRight) before the SCM will let it start. In most cases you don’t have to grant this by hand — setting the account and password on the service’s Log On tab in services.msc, or via sc.exe config ... obj=, grants the right automatically.

Key rule: If a GPO explicitly enumerates Log on as a service rather than leaving it undefined, that GPO’s list overrides the automatic grant on every policy refresh — the exact same trap that affects Log on as a batch job for scheduled tasks. A service account that has worked for months can start failing the moment a security baseline update quietly drops it from an explicit list.

Managing Services: GUI, sc.exe, and PowerShell

services.msc is the console for one-off, interactive changes — right-click a service for Properties to see its startup type, log-on account, dependencies, and recovery actions. For anything scripted or repeated across machines, sc.exe and the Microsoft.PowerShell.Management cmdlets cover the same ground from the command line.

# List every service and its current state
Get-Service

# Start, stop, and restart a service
Start-Service -Name Spooler
Stop-Service -Name Spooler
Restart-Service -Name Spooler

# Configure a service to run under a specific account (PowerShell 6+)
$credential = Get-Credential
Set-Service -Name MyAppService -Credential $credential

# The sc.exe equivalent - works on Windows PowerShell 5.1 and cmd.exe alike
sc.exe config MyAppService obj= "CORP\svc-myapp" password= "P@ssw0rd"

# Query detailed configuration, including the log-on account
sc.exe qc MyAppService

# Set failure/recovery actions - restart the service twice, then run a command
sc.exe failure MyAppService reset= 86400 actions= restart/60000/restart/60000/run/1000
sc.exe failure MyAppService command= "C:\Scripts\Notify-ServiceFailure.ps1"
Better approach: The -Credential parameter on Set-Service only exists from PowerShell 6.0 onward. On Windows PowerShell 5.1 — still the default on most Windows Server installs — use sc.exe config ... obj= ... password= to change a service’s log-on account instead.

Gotchas and Best Practices

A stopped dependency silently blocks everything above it. If a service won’t start and the error is generic, check Get-Service -Name X -RequiredServices before assuming the service itself is broken — the SCM won’t start it while a dependency is stopped or disabled.

Recovery actions are opt-in, not automatic. By default, a service that crashes just stays stopped. Configuring the Recovery tab — or sc.exe failure — to restart the service, run a script, or reboot the computer on failure turns a silent outage into a self-healing one, but only if someone deliberately sets it.

Troubleshooting note: A service configured with a domain account whose password has expired or changed outside the service’s own configuration fails to start with an authentication error that looks identical to a permissions problem. Confirm the account’s password is current before spending time on ACLs and rights.

Troubleshooting Cheat Sheet

Symptom Likely Cause Fix
Service never starts after reboot, works fine started manually Startup type is Manual, not Automatic. Set-Service -StartupType Automatic, or Delayed Start if it doesn’t need to be first.
“The service did not start due to a logon failure” Account password is wrong, expired, or the account lacks Log on as a service. Reset/verify the password; confirm the right wasn’t dropped by a GPO explicitly enumerating it.
Service fails to start, generic error, no detail A required dependency is stopped or disabled. Get-Service -Name X -RequiredServices; start or enable the dependency first.
Service crashes and stays down until someone notices No recovery/failure actions configured — the default state. Set restart actions on the Recovery tab or with sc.exe failure.
Service works locally but fails to reach a network resource Running as LocalService, which has no network identity, when the code assumes one. Switch to NetworkService (computer identity) or a domain account/gMSA with explicit rights.
Boot takes noticeably longer after adding a new service New service is set to plain Automatic and competes with core services at boot. Switch it to Automatic (Delayed Start) if it isn’t boot-critical.

Final Thoughts

Windows Services are a small, well-defined system — a database, a startup type, and an account — which is exactly why most failures in it are misdiagnosed as something more exotic than they are. The Service Control Manager almost always did precisely what its configuration told it to do; the configuration just didn’t say what the person troubleshooting it assumed.

Before chasing application-level logs, check the two settings that actually govern whether a service runs at all: its startup type, and the account it’s allowed to log on as. Between those two, and a glance at its dependency chain, most “the service just won’t start” tickets resolve in minutes.

Key takeaway: A service that runs manually but not after reboot is a startup-type problem. A service that fails with a logon or access-denied error is an account problem — check the password, the Log on as a service right, and whether a GPO is silently managing that right out from under the account.
Next in this series

The Log on as a service and gMSA questions this post raises tie directly into Task Scheduler‘s own Log on as a batch job requirement — the same GPO-override trap catches both, just under a different user right.