// question

While reviewing Windows process events, you observe a command that recursively deleted a folder under the temporary directory. Use the process event data to identify which process or tool executed this recursive delete.

Reference KQL answer and model-by-model comparison.

edd779e4-a509-4cba-8dfa-a112543dbfb1
question id
10/23
models correct
1
valid answer
43%
success rate
// reference answer

Human-validated correct answer for this question.

powershell
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
powershell.exe
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has_any ("del", "rmdir", "rm ", "Remove-Item", "cmd.exe", "powershell")
| where (
    (ProcessCommandLine has_any ("temp", "tmp", @'AppData\Local\Temp', @'C:\temp', @'C:\tmp', "%TEMP%"))
    and
    (ProcessCommandLine has_any ("/s", "/q", "-r", "-force", "-Recurse"))
)
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
pass115.61s0.0083
gpt-35-turbo
no answer
no query generatedfail50.00s0.0109
gpt-4-turbo-2024-04-09
no answer
no query generatedfail50.00s0.2278
gpt-4.1
powershell.exe
DeviceProcessEvents
| where ProcessCommandLine has_any ("rmdir /s", "rd /s", "Remove-Item -Recurse", "/s /q", "-Recurse")
| where ProcessCommandLine has_any("temp", "%TEMP%")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc
pass28.65s0.0231
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0424
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0067
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0015
gpt-4o
no answer
no query generatedfail50.00s0.0537
gpt-5-high
powershell.exe
let temp_path_re = @"(\\windows\\temp|\\appdata\\local\\temp|%temp%|%tmp%|\$env:temp|\$env:tmp)"; // temp indicators (lower-cased)
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| extend pcl = tolower(ProcessCommandLine), fname = tolower(FileName)
// Must reference a temp path or TEMP/TMP variables
| where pcl matches regex temp_path_re
// Look for recursive delete patterns
| where 
    // cmd rmdir/rd with /s (optionally with /q)
    pcl matches regex @"\b(rmdir|rd)\b.*?\/(s)" 
    or 
    // cmd del with /s (optionally with /q)
    pcl matches regex @"\bdel(ete)?\b.*?\/(s)" 
    or 
    // PowerShell Remove-Item (or aliases) with -Recurse/-r
    (fname in ("powershell.exe","pwsh.exe","powershell_ise.exe") and pcl matches regex @"\b(remove-item|rm|ri|del)\b.*?\-(recurse|r\b)")
    or 
    // Sysinternals sdelete with -s or /s
    pcl matches regex @"\bsdelete(\.exe)?\b.*?(\s\-s|\s\/s)"
| project TimeGenerated, DeviceName, AccountDomain, AccountName, FileName, FolderPath, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountDomain, InitiatingProcessAccountName,
          ProcessTokenElevation, InitiatingProcessTokenElevation, ProcessId, InitiatingProcessId, InitiatingProcessParentFileName, InitiatingProcessCreationTime
| order by TimeGenerated desc
pass169.98s0.0513
gpt-5-mini-high
powershell.exe
DeviceProcessEvents
| where isnotempty(ProcessCommandLine)
// match references to temp directories (case-insensitive)
| where ProcessCommandLine matches regex @"(?i)(%temp%|\\temp\\|\\windows\\temp|\btemp\b)"
// match common recursive/remove/delete patterns (case-insensitive)
| where ProcessCommandLine matches regex @"(?i)(\bdel\b|\brmdir\b|\brd\b|\bremove-item\b|-recurse\b|-force\b|/s\b|/q\b|rm\s*-rf\b)"
| extend Initiator = strcat(tostring(InitiatingProcessFileName), " (PID:", tostring(InitiatingProcessId), ")")
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), AnyCmd = any(ProcessCommandLine), AnyInitiatorCmd = any(InitiatingProcessCommandLine), InitiatorFile = any(InitiatingProcessFileName), InitiatorId = any(InitiatingProcessId), InitiatorAccount = any(InitiatingProcessAccountName), InitiatorFolder = any(InitiatingProcessFolderPath) by Initiator
| order by LastSeen desc
| project Initiator, Count, FirstSeen, LastSeen, InitiatorFile, InitiatorId, InitiatorAccount, InitiatorFolder, AnyCmd, AnyInitiatorCmd
| take 50
pass225.65s0.0093
gpt-5-mini-low
no answer
no query generatedfail50.00s0.0145
gpt-5-mini-medium
powershell.exe
let tempRegex = @"(?i)(%temp%|\\Users\\[^\\]+\\AppData\\Local\\Temp|\\Windows\\Temp|\\bTemp\\b|\\btmp\\b)";

let procDeletes =
DeviceProcessEvents
| where isnotempty(ProcessCommandLine)
// common recursive-delete indicators (cmd, powershell, unix-like)
| where tolower(ProcessCommandLine) has_any ("rmdir","rd /s","rd /s /q","del /s","del /s /q","remove-item","-recurse","-force","rm -r","rm -rf","/s","/s /q")
// limit to commands that reference temp locations, or processes that operate in temp folders
| where ProcessCommandLine matches regex tempRegex or FolderPath matches regex tempRegex or InitiatingProcessCommandLine matches regex tempRegex
| project TimeGenerated, DeviceName, AccountName, AccountDomain = AccountDomain, ProcessId, ProcessCreationTime, ProcessCommandLine, ProcessFileName = FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessAccountName, InitiatingProcessAccountDomain, InitiatingProcessCreationTime, InitiatingProcessParentFileName, InitiatingProcessParentId;

let fileDeletes =
DeviceFileEvents
| where isnotempty(ActionType)
| where ActionType has "Delete" or ActionType has "deleted" or ActionType has "FileDeleted"
| where FolderPath matches regex tempRegex or PreviousFolderPath matches regex tempRegex
| project TimeGenerated, DeviceName, AccountName = InitiatingProcessAccountName, AccountDomain = InitiatingProcessAccountDomain, ProcessId = InitiatingProcessId, ProcessCreationTime = InitiatingProcessCreationTime, ProcessCommandLine = InitiatingProcessCommandLine, ProcessFileName = FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessAccountName, InitiatingProcessAccountDomain, InitiatingProcessCreationTime, InitiatingProcessParentFileName = InitiatingProcessParentFileName, InitiatingProcessParentId = InitiatingProcessParentId;

procDeletes
| union fileDeletes
| sort by TimeGenerated desc
| take 500
pass359.66s0.0175
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0079
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0077
grok-3-beta
powershell.exe
let tempPaths = dynamic(['temp', 'C:\\Windows\\Temp', '%temp%', 'C:/Windows/Temp']);
DeviceProcessEvents
| where ProcessCommandLine has_any ('rmdir', 'del', 'remove-item', 'rd')
| where ProcessCommandLine has_any ('/s', '/r', '-r', '-recurse', '/q')
| where ProcessCommandLine has_any (tempPaths)
| project Timestamp, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountName, DeviceId
| union (
    DeviceEvents
    | where ProcessCommandLine has_any ('rmdir', 'del', 'remove-item', 'rd')
    | where ProcessCommandLine has_any ('/s', '/r', '-r', '-recurse', '/q')
    | where ProcessCommandLine has_any (tempPaths)
    | project Timestamp, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountName, DeviceId
)
| order by Timestamp desc
pass222.03s0.0414
grok-3-mini-beta
no answer
no query generatedfail50.00s0.0073
o1-high
powershell.exe
DeviceProcessEvents
| where ProcessCommandLine != "" and isnotnull(ProcessCommandLine)
// Narrow down to recursive delete commands
| where ProcessCommandLine has_any ("rmdir /s", "rd /s", "del /s", "Remove-Item", "-Recurse")
// Ensure the deletion target is under a temp directory
| where tolower(ProcessCommandLine) has "temp"
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine, FolderPath
| order by TimeGenerated desc
pass139.02s0.3102
o1-low
powershell.exe
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has_any ("rmdir", "rd", "del", "Remove-Item")
      and ProcessCommandLine has_any ("/s", "-Recurse")
      and tolower(ProcessCommandLine) has "temp"
| project TimeGenerated, DeviceName, AccountDomain, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, ProcessCommandLine, FolderPath
pass125.88s0.2175
o3-high
powershell.exe
// --- Identify processes that executed a recursive delete inside a Temp folder
let delete_verbs   = dynamic(["rmdir","rd","del","erase","remove-item","rm"]);       // deletion tools / verbs
let recursion_flags = dynamic(["/s","/q","/purge","-recurse","-r","-rf","-force"]);   // switches that imply recursion or force
DeviceProcessEvents
| where ProcessCommandLine has_any(delete_verbs)       // must contain a delete verb
| where ProcessCommandLine has_any(recursion_flags)    // …and a recursive / force flag
| where ProcessCommandLine contains "\\temp"          // aimed at a Temp folder (typical Windows path)
      or ProcessCommandLine contains "/temp"          // POSIX style path (WSL, Git, Cygwin, etc.)
      or ProcessCommandLine contains "%temp%"         // Windows environment variable
      or ProcessCommandLine contains "$env:temp"      // PowerShell variable
| project TimeGenerated,
          DeviceName,
          Account = strcat(AccountDomain, "\\", AccountName),
          Executable = FileName,
          ProcessCommandLine,
          ParentProcess = InitiatingProcessFileName,
          ParentCommand  = InitiatingProcessCommandLine,
          ProcessId,
          InitiatingProcessParentId,
          SHA256
// | summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), ExecCount=count() by DeviceName, Executable, ProcessCommandLine, ParentProcess, Account, SHA256
| order by TimeGenerated desc
pass263.17s0.0479
o3-mini-high
no answer
no query generatedfail50.00s0.0385
o3-mini-low
no answer
no query generatedfail50.00s0.0348
o4-mini-high
powershell.exe
DeviceProcessEvents
| where tolower(ProcessCommandLine) has "temp" and (
    tolower(ProcessCommandLine) has "remove-item" and tolower(ProcessCommandLine) has "-recurse"
    or tolower(ProcessCommandLine) matches regex @"rmdir\s+/s"
    or tolower(ProcessCommandLine) matches regex @"del\s+/s"
    or tolower(ProcessCommandLine) matches regex @"rm\s+-r"
)
| project TimeGenerated, DeviceName, ProcessId, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessCommandLine
| sort by TimeGenerated desc
pass127.07s0.0125
o4-mini-low
no answer
no query generatedfail50.00s0.0491