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.
The Service Control Manager — the RPC server, started at boot, that owns the services database.
The MMC console for viewing, starting, stopping, and configuring services by hand.
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 |
|---|---|
| Automatic | Starts 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. |
| Manual | Only starts when explicitly requested, by a user, another service, or an application. |
| Disabled | Cannot be started at all, by anyone, until the startup type is changed. |
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 |
|---|---|---|
| LocalSystem | Full, unrestricted access to the local machine. | Presents the computer’s own credentials to remote servers. |
| NetworkService | Minimal local privileges. | Also presents the computer’s credentials to remote servers. |
| LocalService | Minimal local privileges. | Presents anonymous credentials — no network identity at all. |
| Domain user account | Whatever 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. |
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.
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"
-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 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.
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.