When critical Windows services mysteriously get disabled, system administrators need forensic tools to trace the modification. The key data sources include:
- Windows Security Event Log (Event ID 7040)
- System Event Log (Event ID 7036)
- PowerShell command history (if applicable)
- Registry modification timestamps
The most reliable method is querying Windows Event Logs with precise filtering. Here's the PowerShell command to extract service change events:
Get-WinEvent -LogName System |
Where-Object {$_.Id -eq 7040 -or $_.Id -eq 7036} |
Select-Object TimeCreated, Id, Message |
Format-List
For more targeted results showing disabled services specifically:
Get-WinEvent -FilterHashtable @{
LogName='System'
ID=7040
StartTime=(Get-Date).AddDays(-7)
} | Where-Object {$_.Message -match 'disabled'}
If the events aren't logged, you may need to enable advanced auditing policies first:
auditpol /set /subcategory:"Security System Extension" /success:enable /failure:enable
auditpol /set /subcategory:"Other System Events" /success:enable /failure:enable
Services configuration is stored in HKLM\SYSTEM\CurrentControlSet\Services
. You can check registry last modified times:
Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\YourServiceName |
Select-Object PSPath, PSParentPath, PSChildName, PSDrive,
PSProvider, Property, @{N='Modified';E={$_.PSPath | Get-Item | Select-Object -ExpandProperty LastWriteTime}}
Here's a complete PowerShell script that logs service configuration changes:
# ServiceChangeAudit.ps1
$services = Get-Service | Where-Object {$_.StartType -eq 'Disabled'}
$output = @()
foreach ($service in $services) {
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$($service.Name)"
$regItem = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue
if ($regItem) {
$lastModified = (Get-Item $regPath).LastWriteTime
$output += [PSCustomObject]@{
ServiceName = $service.Name
DisplayName = $service.DisplayName
CurrentStatus = $service.Status
StartType = $service.StartType
LastModified = $lastModified
RegistryPath = $regPath
}
}
}
$output | Export-Csv -Path "C:\Audit\DisabledServices_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
For domain environments, check Security logs for Event ID 4663 (filesystem access) filtered on the registry hive:
Get-WinEvent -LogName Security -FilterXPath "*[System[EventID=4663]] and *[EventData[Data[@Name='ObjectName'] and
(Data='\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services')]]" |
Select-Object TimeCreated, @{n='User';e={$_.Properties[1].Value}},
@{n='Process';e={$_.Properties[5].Value}},
@{n='AccessMask';e={$_.Properties[8].Value}} |
Format-Table -AutoSize
To prevent unauthorized service modifications:
- Implement proper ACLs on service registry keys
- Enable detailed service change auditing
- Regularly export service configurations as baselines
- Monitor with SIEM solutions for real-time alerts
For historical tracking, WMI permanent event consumers can log service changes:
$query = "SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Service'"
$action = {Param($target) Write-EventLog -LogName System -Source "Service Monitor" -EventId 9999 -EntryType Information -Message "Service change detected: $($target.PreviousInstance.StartType) → $($target.TargetInstance.StartType) by $($env:USERNAME)"}
Register-WmiEvent -Query $query -Action $action -SourceIdentifier "ServiceChangeMonitor" -MaxTriggerCount 0
When critical Windows services mysteriously change from Automatic
to Disabled
, administrators need forensic tools to identify the responsible party. This investigation involves multiple Windows logging subsystems and sometimes requires custom PowerShell scripting.
The most reliable approach checks Windows Security logs for Event ID 7040 ("Service configuration changed"). However, this requires proper audit policies:
# Verify audit policy is configured
auditpol /get /subcategory:"Security System Extension"
# Enable if not configured (requires admin)
auditpol /set /subcategory:"Security System Extension" /success:enable /failure:enable
Sample log entry structure:
Event ID: 7040
Task Category: Service Control Manager
Modified Service: W32Time (Windows Time)
Original Start Type: Automatic
New Start Type: Disabled
User: DOMAIN\jsmith
Process: C:\Windows\System32\services.exe
If changes were made via PowerShell, check command history:
# Get PowerShell console history
Get-Content (Get-PSReadlineOption).HistorySavePath
# Check for Set-Service commands
Get-WinEvent -LogName "Windows PowerShell" |
Where-Object {$_.Message -like "*Set-Service*"} |
Select-Object TimeCreated, Message
Enable debug logging for Service Control Manager (SCM):
# Create registry key
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control"
-Name "SvcHostSplitDisable"
-Value 0
-PropertyType DWORD -Force
# Set logging level
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Tracing"
-Name "ServiceControlManager"
-Value 1
Logs will appear in %SystemRoot%\System32\LogFiles\Scm
with detailed change records including timestamps and process IDs.
For ongoing monitoring, implement a real-time watcher:
$query = @"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[EventID=7040]]
</Select>
</Query>
</QueryList>
"@
Register-WinEvent -Query $query -Action {
$event = $args[0]
$user = $event.Properties[6].Value
$service = $event.Properties[0].Value
$changeType = $event.Properties[3].Value
Write-Host "[$(Get-Date)] $user modified $service: $changeType"
}
In domain environments, consider these additional sources:
- SIEM system logs (if forwarding Windows events)
- AD audit logs for privileged account usage
- Windows Task Scheduler history for automated scripts