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
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, StartTypeAll 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
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 20The 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
🔵 SQL Server example:
Event 1074 revealed two reboots in the same maintenance window. The first was triggered by
o9ansibleuservia Ansible. The second was chained byTrustedInstaller.exewith 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
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 50The 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
💡 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)