The PowerShell Process Lasted Four Seconds — The Persistence Lasted Four Weeks
PowerShell started.
Four seconds later, it was gone.
No long-running process.
No obvious malware still sitting in memory.
Nothing about the process lifetime looked persistent.
Then Agent Foskett stopped asking how long PowerShell ran.
He asked what PowerShell left behind.
Four weeks of execution history answered the question.
The Process Lifetime Was a Distraction
A process can exist for only seconds and still create a registry entry, scheduled task or other mechanism that continues executing long after the original process disappears.
Four seconds looked insignificant
Start with the original PowerShell execution
DeviceProcessEvents to preserve the full command line, account, process ID and parent process around the original event. The command line is especially important because it may reveal the file, registry location, task name or script that becomes the next pivot.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
let Device = "LAPTOP-042";
let StartTime = datetime(2026-07-28 10:14:00);
let EndTime = datetime(2026-07-28 10:16:00);
DeviceProcessEvents
| where Timestamp between (StartTime .. EndTime)
| where DeviceName =~ Device
| where FileName in~ ("powershell.exe", "pwsh.exe")
| project Timestamp,
DeviceName,
AccountName,
FileName,
ProcessCommandLine,
ProcessId,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
SHA1
| order by Timestamp asc
Did PowerShell create a Run key?
DeviceRegistryEvents around the original execution and keep the initiating process context visible.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
let Device = "LAPTOP-042";
let StartTime = datetime(2026-07-28 10:13:00);
let EndTime = datetime(2026-07-28 10:18:00);
DeviceRegistryEvents
| where Timestamp between (StartTime .. EndTime)
| where DeviceName =~ Device
| where RegistryKey has_any
("\CurrentVersion\Run",
"\CurrentVersion\RunOnce")
| project Timestamp,
DeviceName,
ActionType,
RegistryKey,
RegistryValueName,
RegistryValueData,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp asc
What about a scheduled task?
DeviceEvents can contain relevant task-related action types depending on the telemetry available in the environment. Search the original window and inspect AdditionalFields rather than assuming one fixed event shape.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let Device = "LAPTOP-042";
let StartTime = datetime(2026-07-28 10:13:00);
let EndTime = datetime(2026-07-28 10:18:00);
DeviceEvents
| where Timestamp between (StartTime .. EndTime)
| where DeviceName =~ Device
| where ActionType has_any ("ScheduledTask", "Task")
| project Timestamp,
DeviceName,
ActionType,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
AdditionalFields
| order by Timestamp asc
The original process disappeared — the command came back
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
let Device = "LAPTOP-042";
let PersistenceCommand = "update.ps1";
DeviceProcessEvents
| where Timestamp > ago(30d)
| where DeviceName =~ Device
| where ProcessCommandLine has PersistenceCommand
| project Timestamp,
DeviceName,
AccountName,
FileName,
ProcessCommandLine,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp asc
The timeline stretched from seconds to weeks
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let Device = "LAPTOP-042";
let PersistenceCommand = "update.ps1";
DeviceProcessEvents
| where Timestamp > ago(30d)
| where DeviceName =~ Device
| where ProcessCommandLine has PersistenceCommand
| summarize Executions=count(),
FirstSeen=min(Timestamp),
LastSeen=max(Timestamp),
Parents=make_set(InitiatingProcessFileName, 20)
by DeviceName,
AccountName,
ProcessCommandLine
Did the same persistence appear on other devices?
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let PersistenceCommand = "update.ps1";
DeviceProcessEvents
| where Timestamp > ago(30d)
| where ProcessCommandLine has PersistenceCommand
| summarize Executions=count(),
FirstSeen=min(Timestamp),
LastSeen=max(Timestamp),
Accounts=make_set(AccountName, 20)
by DeviceName
| order by FirstSeen asc

