The Script Ran From AppData
The alert never arrived.
No ransomware note. No screaming antivirus banner. No dramatic pop-up on the user's screen. Just a quiet PowerShell process, a short command line, and a script path buried under C:\Users\...\AppData\Roaming.
To most people, AppData looked like clutter. To Agent Foskett, it looked like a question.
Why was a script running from a user-writable folder that most users never open?

Briefing summary
AppData is not malicious by itself. But when scripts, PowerShell, unusual parent processes and persistence all point back to AppData, the endpoint is giving investigators a trail to follow.
AppData was not the attack
What Defender XDR can show
Find scripts running from AppData
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ (
"powershell.exe",
"pwsh.exe",
"cmd.exe",
"wscript.exe",
"cscript.exe",
"mshta.exe"
)
| where ProcessCommandLine has @"\AppData\"
| project
Timestamp,
DeviceName,
AccountName,
FileName,
ProcessCommandLine,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp desc
The path changed the meaning
Look for scripts written into AppData
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in~ ("FileCreated", "FileModified", "FileRenamed")
| where FolderPath has @"\AppData\"
| where FileName has_any (
".ps1",
".vbs",
".js",
".jse",
".bat",
".cmd",
".lnk",
".exe",
".dll"
)
| project
Timestamp,
DeviceName,
ActionType,
FolderPath,
FileName,
SHA256,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp desc
The parent process told the story
Review suspicious parent processes
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ (
"powershell.exe",
"pwsh.exe",
"cmd.exe",
"wscript.exe",
"cscript.exe",
"mshta.exe",
"rundll32.exe"
)
| where InitiatingProcessFileName in~ (
"outlook.exe",
"winword.exe",
"excel.exe",
"powerpnt.exe",
"chrome.exe",
"msedge.exe",
"firefox.exe",
"teams.exe",
"explorer.exe"
)
| project
Timestamp,
DeviceName,
AccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
FileName,
ProcessCommandLine
| order by Timestamp desc
Persistence was the next question
Hunt for AppData persistence
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
DeviceRegistryEvents
| where Timestamp > ago(30d)
| where RegistryValueData has @"\AppData\"
| where RegistryKey has_any (
@"\Software\Microsoft\Windows\CurrentVersion\Run",
@"\Software\Microsoft\Windows\CurrentVersion\RunOnce",
@"\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run"
)
| project
Timestamp,
DeviceName,
ActionType,
RegistryKey,
RegistryValueName,
RegistryValueData,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp desc
Review scheduled tasks pointing to AppData
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
DeviceEvents
| where Timestamp > ago(30d)
| where ActionType has_any ("ScheduledTaskCreated", "ScheduledTaskUpdated")
or InitiatingProcessCommandLine has_any ("schtasks", "Schedule.Service")
| where tostring(AdditionalFields) has @"\AppData\"
or InitiatingProcessCommandLine has @"\AppData\"
| project
Timestamp,
DeviceName,
ActionType,
InitiatingProcessAccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
AdditionalFields
| order by Timestamp desc
What investigators should ask
Build the AppData endpoint timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
let InvestigationDevice = "DEVICE-NAME-HERE";
let StartTime = ago(1d);
union isfuzzy=true
(
DeviceProcessEvents
| where Timestamp > StartTime
| where DeviceName =~ InvestigationDevice
| where ProcessCommandLine has @"\AppData\"
or InitiatingProcessCommandLine has @"\AppData\"
| project Timestamp, DeviceName, EvidenceType="Process", ActionType, Detail=ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
),
(
DeviceFileEvents
| where Timestamp > StartTime
| where DeviceName =~ InvestigationDevice
| where FolderPath has @"\AppData\"
| project Timestamp, DeviceName, EvidenceType="File", ActionType, Detail=FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine
),
(
DeviceRegistryEvents
| where Timestamp > StartTime
| where DeviceName =~ InvestigationDevice
| where RegistryValueData has @"\AppData\"
or InitiatingProcessCommandLine has @"\AppData\"
| project Timestamp, DeviceName, EvidenceType="Registry", ActionType, Detail=strcat(RegistryKey, " ", RegistryValueName, " ", RegistryValueData), InitiatingProcessFileName, InitiatingProcessCommandLine
)
| order by Timestamp asc
AppData was only the hiding place
Related investigations
Final thought
The Script Ran From AppData
This Agent Foskett investigation explains how scripts running from AppData can reveal suspicious PowerShell execution, file writes, registry changes and endpoint persistence.
Microsoft Defender XDR AppData Investigation
DeviceProcessEvents, DeviceFileEvents and DeviceRegistryEvents can help defenders investigate AppData abuse, suspicious scripts, parent-child process relationships and persistence.
KQL Hunting For AppData Script Execution
Defenders can use KQL to hunt for PowerShell running from AppData, scripts written to user-writable folders, scheduled tasks, registry Run keys and suspicious endpoint timelines.
