Home / Guides / Why a Windows service failed to start
Find out why a Windows service failed to start or stopped, on many servers
A service that should be running is stopped, on one server or on several. The Services console only says Stopped, and the error dialog that explained it went to whoever started the service, or to nobody when it failed at boot. Windows does keep the reason: the Service Control Manager writes it to the System log, and the program's own error usually lands in the Application log. This guide covers which events to look for and what each one means, how to read them on one server and on many with PowerShell, what we saw when we broke test services on purpose, and where this stops.
Short answer.
Look in the System log for source Service Control Manager: 7000 (failed to start, with the reason), 7009 (timed out waiting for the service), 7001 (a service it depends on failed), 7023 and 7024 (stopped with an error), 7038 and 7041 (could not log on as its account). Then look in the Application log at the same time for Application Error 1000 and .NET Runtime 1026 (the program crashed) and for errors from the service's own source.
Get-WinEvent -FilterHashtable reads both on one server, and a loop with -ComputerName reads them on many.
If a running service crashed and you want an alert next time (events 7031 and 7034), see
Get an email when a Windows service stops.
The events that say why
All of these come from the source Service Control Manager in the System log. The service is named in the message
by its display name (for example Windows Update, not wuauserv). The last column is what we saw on a Windows 11 test
machine (build 26300) after creating test services with sc.exe and breaking them on purpose.
| Event | What it says and means | Seen in our test |
|---|---|---|
| 7000 | "The X service failed to start due to the following error:" and the reason. Common reasons: The system cannot find the file specified (the program path in the service is wrong or the file is gone), The service did not respond to the start or control request in a timely fashion (error 1053, a time-out) and The service did not start due to a logon failure (error 1069). | File not found for a service pointing at a missing .exe; 1053 for a program that never talked to Windows and for one that crashed at once |
| 7009 | "A timeout was reached (30000 milliseconds) while waiting for the X service to connect." The program did not report to Windows in time. It comes with a 7000 (1053). | Both time-out cases above, each with a 7000 |
| 7011 | Another time-out event. Microsoft documents it together with 7000 under the ServicesPipeTimeout setting (see the FAQ). |
Not triggered |
| 7001 | "The X service depends on the Y service which failed to start because of the following error:". Fix Y first. | Yes, for a service that depended on the missing-file one |
| 7023 | "The X service terminated with the following error:" and a Windows error text. The service started, then stopped and reported an error code. | "Access is denied." from a test service that stopped itself with exit code 5 |
| 7024 | "The X service terminated with service-specific error N." The number is the service's own code, not a Windows error: its meaning is in the vendor's documentation or the service's own log. Microsoft's examples include Netlogon (2114) and BITS. | Not triggered |
| 7038 | "The X service was unable to log on as ACCOUNT with the currently configured password due to the following error:". The password is wrong, expired or must be changed, the account is disabled or locked out, or the domain could not be reached. The start fails with 1069. | Not triggered |
| 7041 | The same logon failure because the account does not have the Log on as a service right ("the user has not been granted the requested logon type at this computer"). | Not triggered |
Read them on one server
-FilterHashtable filters on the server by log, source, event ID and time, so only the matching events come back:
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ProviderName = 'Service Control Manager'
Id = 7000, 7001, 7009, 7011, 7023, 7024, 7038, 7041
StartTime = (Get-Date).AddDays(-7)
} | Format-Table TimeCreated, Id, Message -AutoSize -Wrap
# Another server: add -ComputerName SERVER01 (it needs the rights described under "Many servers").
For a service that is stopped right now, Windows also keeps the last exit code. Get-CimInstance Win32_Service shows it, and
net helpmsg turns a Windows error number into its text:
Get-CimInstance Win32_Service -Filter "StartMode = 'Auto' AND State <> 'Running'" |
Format-Table Name, DisplayName, State, ExitCode, ServiceSpecificExitCode -AutoSize
net helpmsg 1053 # The service did not respond to the start or control request in a timely fashion.
Microsoft documents that ExitCode is 1066 when the service reported its own code, which is then in
ServiceSpecificExitCode (the 7024 case). Do not rely on ExitCode alone: in our test it was 5 for the service that
logged 7023 and 1068 for the dependency failure, but 0 for the missing file and for both time-outs. Some automatic services also stop on
purpose (on our test machine Software Protection and Edge Update were stopped with exit code 0), so a stopped automatic
service is not always a problem.
The Application log: the program's own reason
A 7000 or 7009 says that the start failed, not why the program failed. That part is usually in the Application log, written at the same moment:
- Application Error 1000: a program crashed. It names the faulting application and module and gives an exception code.
Microsoft documents
0xe0434352as an unhandled .NET exception and says to look for the matching .NET Runtime 1026 event. - .NET Runtime 1026: "The process was terminated due to an unhandled exception", with the exception type and the stack.
Our test service that crashed at once logged both, and the 1026 named the
FileNotFoundExceptionand the method that threw it. - The service's own source. Many services write their errors under their own name. Our test service built on .NET
Framework's
ServiceBasethat threw an exception while starting wrote "Service cannot be started." and the exception to the Application log under its own name, with event ID 0. The System log had nothing for that failed start: no 7000, no 7023. Search the Application log by the service's name and by time, not only by event ID.
Get-WinEvent -FilterHashtable @(
@{ LogName = 'Application'; ProviderName = 'Application Error'; Id = 1000; StartTime = (Get-Date).AddDays(-1) },
@{ LogName = 'Application'; ProviderName = '.NET Runtime'; Id = 1026; StartTime = (Get-Date).AddDays(-1) }
) | Format-List TimeCreated, ProviderName, Id, Message
The two filters are separate on purpose: on our Windows 11 test machine .NET Runtime also logged unrelated events with ID 1000, so one filter with both sources and both IDs returns noise.
Many servers: one script
This script reads both logs on each server you list, keeps the service events from the System log and the crash events from the Application log (plus the service's own errors when you give a name), and puts everything in one table sorted newest first and in a CSV file. A server that cannot be read is reported, not skipped silently. It also picks up 7031 and 7034, a running service that crashed (explained in the email alert guide), so one run shows both kinds of failure.
param(
[string[]]$ComputerName = @('SERVER01', 'SERVER02', 'SERVER03'),
[datetime]$StartTime = (Get-Date).AddDays(-1),
[string]$Name = '', # part of a service or program name; empty = every service failure
[string]$CsvPath = "$env:USERPROFILE\Desktop\ServiceFailures.csv"
)
# Service Control Manager events about a service that failed to start, stopped with an error or crashed.
$scmIds = 7000, 7001, 7009, 7011, 7023, 7024, 7031, 7034, 7038, 7041
$filters = @(
@{ LogName = 'System'; ProviderName = 'Service Control Manager'; Id = $scmIds; StartTime = $StartTime },
@{ LogName = 'Application'; Level = 1, 2; StartTime = $StartTime }
)
$found = [System.Collections.Generic.List[object]]::new()
$failed = [System.Collections.Generic.List[object]]::new()
foreach ($computer in $ComputerName) {
foreach ($filter in $filters) {
try {
$events = Get-WinEvent -ComputerName $computer -FilterHashtable $filter -ErrorAction Stop
}
catch {
# "No events were found" is an error in Get-WinEvent; here it just means nothing matched.
if ($_.FullyQualifiedErrorId -like 'NoMatchingEventsFound*') { continue }
$failed.Add([pscustomobject]@{ Computer = $computer; Log = $filter.LogName; Error = $_.Exception.Message })
continue
}
foreach ($e in $events) {
$isMatch = (-not $Name) -or
($e.Message -and $e.Message.IndexOf($Name, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) -or
($e.ProviderName.IndexOf($Name, [System.StringComparison]::OrdinalIgnoreCase) -ge 0)
if (-not $isMatch) { continue }
# Every Application error would be too much: keep the crash reports (Application Error 1000,
# .NET Runtime 1026), plus the service's own errors when -Name is given.
$isCrash = ($e.ProviderName -eq 'Application Error' -and $e.Id -eq 1000) -or
($e.ProviderName -eq '.NET Runtime' -and $e.Id -eq 1026)
if ($e.LogName -eq 'Application' -and -not $Name -and -not $isCrash) { continue }
$found.Add([pscustomobject]@{
Time = $e.TimeCreated
Computer = $computer
Log = $e.LogName
Source = $e.ProviderName
EventId = $e.Id
Message = ($e.Message -replace '\s+', ' ').Trim()
})
}
}
}
$sorted = $found | Sort-Object Time -Descending
$sorted | Format-Table Time, Computer, Source, EventId, Message -AutoSize -Wrap
$sorted | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8
"{0} events from {1} computers ({2} logs could not be read) written to {3}" -f $found.Count, $ComputerName.Count, $failed.Count, $CsvPath
foreach ($f in $failed) { Write-Warning "$($f.Computer) $($f.Log): $($f.Error)" }
Save it as C:\Scripts\Get-ServiceFailures.ps1 and run it with your own server names:
C:\Scripts\Get-ServiceFailures.ps1 -ComputerName SQL01, SQL02, WEB01 -StartTime (Get-Date).AddDays(-3)
# One service, servers from a file (one name per line):
C:\Scripts\Get-ServiceFailures.ps1 -ComputerName (Get-Content C:\Scripts\servers.txt) -Name 'SQL Server Agent'
-ComputerName: the servers to read.-StartTime: how far back to look (default 24 hours).-Name: part of a service or program name, not case-sensitive. With it, Application log errors whose source or message contain the name are included too.-CsvPath: where the results go.
Tested on Windows PowerShell 5.1 on Windows 11 with six broken test services, reading the computer by its own name and as
localhost: the 7000, 7001, 7009 and 7023 events and the Application Error 1000 and .NET Runtime 1026 events all came back in
one table and in the CSV; with -Name the service's own Application event was included; a name or time window that matched
nothing gave an empty result and no error; an unreachable computer was reported as a warning for each log ("The RPC server is unavailable")
and counted in the summary. Reading other servers is from Microsoft's documentation and was not tested.
Get-WinEvent -ComputerName reads over RPC, not PowerShell remoting. Each server needs your account in its
Event Log Readers group (or Administrators) and its Remote Event Log Management firewall rules turned on; on our Windows 11
test machine all six were off. The permissions, the firewall commands and the common errors are in
Search Windows Event Logs on multiple servers at once.
Get-CimInstance -ComputerName is different: it uses WinRM.
Where the script stops
- Only what is still in the log. When a log is full, Windows overwrites the oldest events, so the failure from two weeks ago may be gone. The script keeps nothing between runs.
- A clean stop leaves no error. If someone stopped the service, or the program ended without reporting an error, there is no 7023 or 7024 to find. The email alert guide covers watching for those.
- Not the program's own log file. Many services write their details to a text file, not the Application log. The events tell you when and which service; the file may tell you why.
- A search, not a monitor. Each run reads the servers again, and nothing tells you when a new failure appears.
Questions
What does error 1053 mean when a service will not start?
"The service did not respond to the start or control request in a timely fashion." Windows started the program, but it did not report back in time (30 seconds by default), so the System log also has a 7009 time-out event. The program may be slow, hung, or it may have crashed before it reported: on our test machine a service whose program crashed at once also gave 1053. Look in the Application log at the same time for Application Error 1000 or .NET Runtime 1026.
Where do I find why a Windows service failed to start?
In the System log, source Service Control Manager: event 7000 gives the reason (for example file not found, a time-out or a logon failure), 7001 a dependency that failed, 7038 and 7041 an account problem. The program's own error is usually in the Application log at the same moment: Application Error 1000 and .NET Runtime 1026 for a crash, or an error under the service's own source name.
Should I raise ServicesPipeTimeout to fix event 7009?
Only for a service that really needs longer to start. Microsoft documents the DWORD value ServicesPipeTimeout under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control, in milliseconds, effective after a restart, and recommends finding out why the service is slow first and raising the value in small steps. It applies to every service on the computer, and it does not help a program that crashed or hangs.
What is a service-specific error in event 7024?
A number the service itself reported when it stopped, not a Windows error code, so net helpmsg does not explain it. Its meaning is in the vendor's documentation or the service's own log. Win32_Service shows the last one in ServiceSpecificExitCode, with ExitCode set to 1066.
A service failed to start but the System log has no 7000. Why?
Some services catch their own start-up error, write it to the Application log and stop without reporting an error to Windows. Our test service built on .NET Framework's ServiceBase did exactly that: "Service cannot be started." and the exception in the Application log under the service's own name, and nothing in the System log. Search the Application log for the service's name around the time it should have started.
Related
- Get an email when a Windows service stops
- Search Windows Event Logs on multiple servers at once
- LogTrawler: all your server logs in one searchable place
- All guides
Sources (Microsoft Learn): Get-WinEvent, Creating Get-WinEvent queries with FilterHashtable, A slow service does not start due to time-out error (7000, 7011), Event ID 7000 and the 30-second default time-out, Event ID 7000: the system cannot find the file specified, Error 1069 with events 7038 and 7041, Netlogon event 7024, BITS service-specific error (7024), Event 7023 example, System error codes 1000-1299, Win32_Service (ExitCode, ServiceSpecificExitCode), Application Error 1000, 0xe0434352 and .NET Runtime 1026, Windows Event Log: accessing remote computers.