DEV Community

Cover image for A Windows Service is Down. Now What?
Prateek Srivastava
Prateek Srivastava

Posted on Originally published at prateeksrivastav598.Medium

A Windows Service is Down. Now What?

It doesn't matter if it's SQL Server, IIS, a background agent, or a custom app — when a Windows service goes down, the investigation is always the same five moves. Learn the pattern once, apply it to anything.

🚫 Don't restart first. Restarting a service without knowing why it stopped can hide a real problem — a failing update, an exhausted host, or an automation script that will stop it again in the next cycle. Spend 5 minutes on the evidence first.


Step 01 — Confirm Current State

Your first question isn't "why did it stop?" — it's "is it still stopped?" Monitoring systems have polling intervals; by the time an alert reaches you, the service may have already recovered. Establish ground truth before taking any action.

Get-Service "ServiceName1", "ServiceName2" |
    Select-Object Name, Status, StartType
Enter fullscreen mode Exit fullscreen mode

Two things matter: Status (is it actually down right now?) and StartType (is it still set to Automatic? OS updates occasionally reset this).

🔵 SQL Server example:

Get-Service MSSQLSERVER, SQLSERVERAGENT, MsDtsServer130 |
    Select-Object Name, Status, StartType

All three came back Running / Automatic — already self-recovered before anyone looked. This told us the alert was valid but not actionable, and shifted focus to understanding root cause.


Step 02 — Map Service Transitions with Event ID 7036

Windows logs every service state change — stopped, running, paused — as Event ID 7036 in the System log. Pull the last 20 transitions and sort them chronologically. This gives you the precise stop-and-start sequence and exact timestamps.

Get-WinEvent -FilterHashtable @{
    LogName='System'; Id=7036
} | Where-Object {
    $_.Message -match 'Your Service Name'
} | Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20
Enter fullscreen mode Exit fullscreen mode

Read the output bottom-up (oldest first). Look for the last time it went from running → stopped, and whether it came back on its own or stayed down. Multiple stop/start cycles in quick succession often mean a crash-and-restart loop.

🔵 SQL Server example:

Get-WinEvent -FilterHashtable @{LogName='System';Id=7036} |
    Where-Object {$_.Message -match
      'SQL Server Agent \(MSSQLSERVER\)|SQL Server \(MSSQLSERVER\)|SQL Server Integration Services 13.0'} |
    Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20

The output showed all three services stopped at 10:20 AM IST and returned to running at 10:27 AM IST — a 6-minute outage that overlapped exactly with the alert timestamp.


Step 03 — Look for System-Level Triggers

A service rarely stops in isolation. Before blaming the application, check whether the host itself caused the stop. Four event IDs tell this story:

Event ID Meaning
1074 Intentional shutdown/restart — includes initiating process (TrustedInstaller, shutdown.exe, Ansible), user, and reason code
6005 Event log service started = OS finished booting. Your "server is up" timestamp
6006 Event log service stopped = OS going down. Pair with 6005 to measure reboot windows
6008 Unexpected/dirty shutdown — previous shutdown was unclean. A crash or power loss leaves this
Get-WinEvent -FilterHashtable @{
    LogName='System'; Id=1074,6005,6006,6008
} | Select-Object TimeCreated, Id, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# For recent 1074s with full detail:
Get-WinEvent -FilterHashtable @{LogName='System';Id=1074} |
    Where-Object {$_.TimeCreated -gt (Get-Date).AddHours(-24)} |
    Format-List TimeCreated, Message
Enter fullscreen mode Exit fullscreen mode

🔵 SQL Server example:

Event 1074 revealed two reboots in the same maintenance window. The first was triggered by o9ansibleuser via Ansible. The second was chained by TrustedInstaller.exe with reason "Operating System: Upgrade (Planned)" — Windows Update had quietly queued a second reboot on top of the Ansible reboot. Without checking Event 1074, this would have looked like an unexplained outage.

💡 If you find a 6008 (dirty shutdown) near your service stop, the host itself crashed — investigate the host before the service.


Step 04 — Read the Application's Own Logs

Windows Event logs tell you when the service stopped. The application's own logs tell you why. Every serious Windows service writes its own log — find it and read the entries immediately before the service stopped.

# Common log locations:
# SQL Server → C:\Program Files\Microsoft SQL Server\MSSQL{ver}.{instance}\MSSQL\Log\ERRORLOG
# IIS        → C:\inetpub\logs\LogFiles\W3SVC1\

# For services that write to Windows Application log:
Get-WinEvent -FilterHashtable @{LogName='Application';Level=1,2} |
    Where-Object {$_.ProviderName -match 'YourService'} |
    Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20
Enter fullscreen mode Exit fullscreen mode

You're looking for one of three signatures:

  • Error/exception before stop → crash
  • Clean shutdown message → planned stop
  • Nothing unusual → external trigger (reboot killed the process)

🔵 SQL Server example — ERRORLOG:

SQL Server rotates its log on every restart. Find the file that covers your outage window by LastWriteTime:

# Find the right log file
Get-ChildItem "C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\ERRORLOG*" |
    Select-Object Name, LastWriteTime, Length |
    Sort-Object LastWriteTime

# Read the last 50 lines of the relevant file
Get-Content "...\MSSQL\Log\ERRORLOG.4" | Select-Object -Last 50

The critical line at the tail of our log:

SQL Server is terminating in response to a 'stop' request from Service Control Manager.

That's a clean stop — no crash, no error. Case closed on fault; focus shifts to who stopped it and why.

⚠️ SQL ERRORLOG uses local server time, not UTC. Convert your alert timestamp before searching.


Step 05 — Classify the Stop, Then Decide

By now you have enough to classify into one of three categories:

🔴 Crash

  • Exceptions/errors in app log immediately before stop
  • Event 6008 (dirty shutdown) present
  • Dump files in the app's log directory
  • No clean stop message

Response: Don't just restart — find the root cause first. Check memory (Get-Process), disk (Get-PSDrive), dump files. Restarting a crashing service without fixing the cause fails again.

🟢 Clean Stop

  • "Stop request from SCM" in app log
  • Config/agent disabled just before stop
  • No preceding errors — manual or scripted

Response: Safe to restart, but find out who stopped it. Was it automation? Is it expected to auto-restart?

🟡 External Trigger

  • Event 1074 near the stop time
  • 6005/6006 reboot pair visible
  • Ansible, Windows Update, manual reboot

Response: The service is a passenger — the host was the cause. Verify the reboot was planned, confirm all services are back, close the ticket.


Going Further: From Reactive to Proactive

🔕 Maintenance Windows — Before any planned reboot, open a monitoring suppression. Automate it as a pre-task in your Ansible playbook, not a manual step someone might forget.

📋 Parse App Logs Continuously — Ship application logs to a central store. Alert on terminating, severity 20+, exception before a service hits the floor.

🧠 Watch Memory Before It Matters — Many crashes are preceded by hours of memory pressure. A service paging to disk for 4 hours before crashing gave you warning you didn't act on.

🤖 Tag Automation in Monitoring — Have Ansible write a comment to your alert system before rebooting. A ticket that says "Ansible reboot — expected" closes in seconds. One without context takes 15 minutes.

📅 Track TrustedInstaller Reboots — Windows Update's chained reboots are invisible unless you watch Event 1074. Add a post-patch check that logs TrustedInstaller-initiated reboots to your CMDB.

📈 Trend Restart Frequency — A service that restarts once a quarter is healthy. One that restarts three times in a week has a problem. Track restart counts over time — the trend tells you before a crash does.


Quick Reference: The Diagnostic Playbook

Save this to your runbook.

# 1 — Current state
Get-Service "ServiceA","ServiceB" | Select-Object Name,Status,StartType

# 2 — Service transitions
Get-WinEvent -FilterHashtable @{LogName='System';Id=7036} |
    Where-Object {$_.Message -match 'YourServiceName'} |
    Select-Object TimeCreated,Message | Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# 3 — Shutdown events
Get-WinEvent -FilterHashtable @{LogName='System';Id=1074,6005,6006,6008} |
    Select-Object TimeCreated,Id,Message | Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# 4 — App event log (errors/criticals)
Get-WinEvent -FilterHashtable @{LogName='Application';Level=1,2} |
    Where-Object {$_.ProviderName -match 'YourService'} |
    Select-Object TimeCreated,Message | Select-Object -First 20

# 5 — Server uptime
(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime

# SQL Server bonus — find the right ERRORLOG
Get-ChildItem "C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\ERRORLOG*" |
    Select-Object Name,LastWriteTime | Sort-Object LastWriteTime
Enter fullscreen mode Exit fullscreen mode

💡 The three root causes — crash, clean stop, external trigger — each have a different recovery path. Classify before you act, and you'll never restart a service into the same problem twice.


If you're dealing with something like this at work — or you have a war story of your own — I'm on LinkedIn and I actually respond.

I publish one production incident breakdown every week — real commands, real dead ends, real fix. Follow on Medium if you want the next one in your feed: prateeksrivastav598.medium.com

Top comments (0)