Windows Event Logs: 10 Event IDs That Reveal an Intruder
Here is a fact that surprises most people: on a typical breach, the evidence was sitting in the Windows event log the whole time. Logons, new accounts, new services, cleared logs. Windows records it all. The attacker is counting on nobody reading it.
This post gives you the ten event IDs worth knowing by heart, what a suspicious one looks like, and a one-liner to pull each from PowerShell.
Before you start
- Open Event Viewer (press the Windows key, type Event Viewer) or an elevated PowerShell window.
- Most of these live in the Security log. One lives in System and one in the PowerShell operational log. I say which.
- Some events only appear if auditing is switched on. The Auditing you need section near the end shows the settings.
- Only review logs on machines you are authorized to administer.
1. Event ID 4624: successful logon
The most important event in the log. Every time someone (or something) logs on, you get one of these, including a Logon Type that tells you how.
| Logon type | Meaning | Worth attention? |
|---|---|---|
| 2 | Interactive, at the keyboard | Normal for users |
| 3 | Network: file shares, remote admin tools | Yes, if from unexpected sources |
| 5 | Service start | Normal |
| 7 | Screen unlock | Normal |
| 10 | Remote Desktop | Yes, always review |
| 11 | Cached credentials, offline | Normal for laptops |
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4624} -MaxEvents 300 |
Where-Object { $_.Properties[8].Value -in 3,10 } |
Select-Object TimeCreated, @{n="User";e={$_.Properties[5].Value}}, @{n="Type";e={$_.Properties[8].Value}}, @{n="FromIP";e={$_.Properties[18].Value}}
Suspicious when: type 10 at odd hours, type 3 from an address outside your network, or a service account logging on interactively.
2. Event ID 4625: failed logon
A password was wrong, an account was locked, or a username did not exist. A handful is life. A thousand in an hour is a brute-force attack.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4625} -MaxEvents 1000 |
Group-Object { $_.Properties[5].Value } | Sort-Object Count -Descending | Select-Object Count, Name -First 10
Suspicious when: many failures against one account, failures against many accounts from one source (password spraying), or failures for accounts that do not exist on this machine.
3. Event ID 4648: logon with explicit credentials
Someone ran something as a different user, such as runas, or connected to another machine with alternate credentials. Normal for admins. Also exactly what lateral movement looks like.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4648} -MaxEvents 100 |
Select-Object TimeCreated, @{n="By";e={$_.Properties[1].Value}}, @{n="As";e={$_.Properties[5].Value}}, @{n="Target";e={$_.Properties[8].Value}}
Suspicious when: a regular user account is using admin credentials, or one workstation is reaching out to many others.
4. Event ID 4672: special privileges assigned
Logged when an account with admin-level rights logs on. Expect it for your admins. Do not expect it for anyone else.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4672} -MaxEvents 100 |
Select-Object TimeCreated, @{n="User";e={$_.Properties[1].Value}} | Group-Object User | Select-Object Count, Name
Suspicious when: a name appears that is not on your admin list.
5. Event ID 4688: a new process was created
Every program start, with the parent process and (if enabled) the full command line. This is the single richest source of evidence on a Windows machine. It is off by default. Turn it on today (see Auditing you need below).
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4688} -MaxEvents 200 |
Select-Object TimeCreated, @{n="Process";e={$_.Properties[5].Value}}, @{n="Parent";e={$_.Properties[13].Value}}, @{n="CmdLine";e={$_.Properties[8].Value}}
Suspicious when: Office programs (Word, Excel, Outlook) spawning powershell.exe or cmd.exe, encoded PowerShell commands (-enc, -EncodedCommand), or anything running from Temp, AppData or Downloads.
6. Event ID 4698: scheduled task created
Scheduled tasks are a top persistence method. This event shows who created a task and the full task definition, including the command it runs.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4698} -MaxEvents 50 |
Select-Object TimeCreated, @{n="By";e={$_.Properties[1].Value}}, @{n="Task";e={$_.Properties[4].Value}}
Suspicious when: created by a non-admin, named to look like system maintenance, or pointing at a script in a user folder.
7. Event ID 4720: user account created
A new local or domain account. Attackers create accounts so they can come back after you reset the one they stole.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4720} -MaxEvents 50 |
Select-Object TimeCreated, @{n="NewAccount";e={$_.Properties[0].Value}}, @{n="CreatedBy";e={$_.Properties[4].Value}}
Suspicious when: you did not create it. Pair with 4722 (enabled), 4724 (password reset) and 4726 (deleted) to see the whole story.
8. Event ID 4732: member added to a local group
Specifically, security-enabled local groups like Administrators and Remote Desktop Users. The domain equivalents are 4728 (global group) and 4756 (universal group).
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4732,4728,4756} -MaxEvents 50 |
Select-Object TimeCreated, Id, @{n="Group";e={$_.Properties[2].Value}}, @{n="By";e={$_.Properties[6].Value}}
Suspicious when: anyone is added to Administrators outside a change window.
9. Event ID 7045: a new service was installed (System log)
Services run as SYSTEM, start at boot and need no user. Tools like PsExec and many malware families install one. Note this lives in the System log, not Security.
Get-WinEvent -FilterHashtable @{LogName="System"; Id=7045} -MaxEvents 50 |
Select-Object TimeCreated, @{n="Service";e={$_.Properties[0].Value}}, @{n="Path";e={$_.Properties[1].Value}}, @{n="Account";e={$_.Properties[4].Value}}
Suspicious when: the path is outside C:\Windows or C:\Program Files, the name is random letters, or the service appeared right after an unexplained logon.
10. Event ID 1102: the audit log was cleared
The one event an attacker cannot avoid creating when they try to cover their tracks. Clearing the Security log writes this as the very first entry in the new, empty log, with the account that did it.
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=1102} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, @{n="ClearedBy";e={$_.Properties[1].Value}}
Suspicious when: always. There is almost no legitimate reason to clear the Security log on a production machine.
Bonus: Event ID 4104, PowerShell script block logging
In the Microsoft-Windows-PowerShell/Operational log. When enabled, Windows records the actual content of every script that runs, even if it was obfuscated or encoded. Attackers hate this one.
Get-WinEvent -FilterHashtable @{LogName="Microsoft-Windows-PowerShell/Operational"; Id=4104} -MaxEvents 50 |
Select-Object TimeCreated, @{n="Script";e={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}}
Auditing you need
Several of these are silent unless the policy is on. Open Local Security Policy (or your domain GPO) and go to Advanced Audit Policy Configuration:
| Event | Policy to enable |
|---|---|
| 4624, 4625, 4648 | Logon/Logoff → Audit Logon (Success and Failure) |
| 4672 | Logon/Logoff → Audit Special Logon |
| 4688 | Detailed Tracking → Audit Process Creation. Also enable Include command line in process creation events under Administrative Templates → System → Audit Process Creation |
| 4698 | Object Access → Audit Other Object Access Events |
| 4720, 4732 | Account Management → Audit User Account Management and Audit Security Group Management |
| 4104 | Administrative Templates → Windows Components → Windows PowerShell → Turn on Script Block Logging |
Also raise the Security log size. The default is small and rolls over in hours on a busy server. 1 GB is a reasonable floor.
Common mistakes
- Logs only on the machine. If the attacker clears them, they are gone. Forward logs to a central server or SIEM.
- Alerting on 4625 alone. Failed logons are noisy. The real signal is a run of 4625s followed by a 4624 of type 3 or 10.
- Never enabling 4688 with command line. Without it, you know a process started but not what it was told to do.
- Ignoring the System log. 7045 lives there and it catches a great deal.
FAQ
How far back do the logs go?
As far as the log size allows. Check with Get-WinEvent -ListLog Security and look at MaximumSizeInBytes. Increase it.
Can I search all machines at once?
With PowerShell Remoting, yes: Invoke-Command -ComputerName (Get-Content servers.txt) -ScriptBlock { ... }. For anything beyond a few dozen machines, you want a SIEM.
Is Sysmon better?
Sysmon (free, from Microsoft Sysinternals) adds much more detail: network connections per process, file hashes, DNS queries. The built-in events above are where to start because they are already there.
Final thoughts
You do not need a six-figure security platform to catch an intruder. You need the logs switched on, kept long enough, and read by someone who knows these ten numbers. Print the quick reference, pin it next to your monitor, and run the queries once a week until they are reflex.
Useful resources
Know the attack. Own the defense.
Tagged:WindowsEvent logsIncident responseBlue teamPowerShell
Need this done for your organization?
I run security and compliance programs for a living. I can review, set up, or train your team.