// question

Windows system logs show PowerShell zipping up the contents of a user’s profile folder. Investigate process and file events to determine the exact name of the ZIP archive created.

Reference KQL answer and model-by-model comparison.

41410c60-614d-4b9d-b66e-b0192dd9c597
question id
12/23
models correct
1
valid answer
52%
success rate
// reference answer

Human-validated correct answer for this question.

T1560-data-ps.zip
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
T1560-data-ps.zip
DeviceFileEvents
| where ActionType == "FileCreated"
| where FileName endswith ".zip"
| where InitiatingProcessFileName =~ "powershell.exe"
| where InitiatingProcessCommandLine has "Compress-Archive" or InitiatingProcessCommandLine has ".Compression.FileSystem"
| project Timestamp, DeviceName, InitiatingProcessCommandLine, FileName, FolderPath, InitiatingProcessAccountName
pass114.39s0.0074
gpt-35-turbo
no answer
no query generatedfail50.00s0.0112
gpt-4-turbo-2024-04-09
T1560-data-ps.zip
DeviceProcessEvents
| where InitiatingProcessFileName == 'powershell.exe' and ProcessCommandLine has 'Compress-Archive'
| project DeviceId, ProcessId, ProcessCreationTime, ProcessCommandLine
| join kind=inner (
    DeviceFileEvents
    | where ActionType == 'FileCreated' and FileName endswith '.zip'
) on DeviceId
| project FileName, ProcessCommandLine, TimeGenerated
pass111.39s0.0602
gpt-4.1
T1560-data-ps.zip
DeviceFileEvents
| where ActionType == "FileCreated"
// Focus on ZIP archive creations
| where FileName endswith ".zip"
// Initiated by PowerShell
| where InitiatingProcessFileName =~ "powershell.exe"
// Profile folder paths typically contain '\Users\' or similar.
| where FolderPath has "\\Users\\"
| project TimeGenerated, DeviceName, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessAccountDomain
| sort by TimeGenerated desc
pass15.99s0.0152
gpt-4.1-finetuned
T1560-data-ps.zip
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has @".zip"
| take 100
pass415.73s0.0361
gpt-4.1-mini
T1560-data-ps.zip
DeviceFileEvents
| where InitiatingProcessFileName has "powershell.exe" and FileName endswith ".zip"
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine, FileName, FolderPath
| order by TimeGenerated desc
| take 10
pass12.94s0.0029
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0020
gpt-4o
no answer
no query generatedfail50.00s0.0585
gpt-5-high
T1560-data-ps.zip
let ps_zip_procs =
DeviceProcessEvents
| where FileName in~ ("powershell.exe","pwsh.exe")
| where ProcessCommandLine has_any ("Compress-Archive","ZipFile]::CreateFromDirectory","System.IO.Compression.FileSystem","System.IO.Compression.ZipFile")
| where ProcessCommandLine has_any ("C\\Users\\","$env:USERPROFILE","%USERPROFILE%")
| extend ZipDestFromCmd = coalesce(
    extract('-DestinationPath\\s+"([^"]+\\.zip)"', 1, ProcessCommandLine),
    extract("-DestinationPath\\s+'([^']+\\.zip)'", 1, ProcessCommandLine),
    extract("-DestinationPath\\s+([^\\s]+\\.zip)", 1, ProcessCommandLine),
    extract('ZipFile\\]::CreateFromDirectory\\([^,]+,\\s+"([^"]+\\.zip)"', 1, ProcessCommandLine),
    extract("ZipFile\\]::CreateFromDirectory\\([^,]+,\\s+'([^']+\\.zip)'", 1, ProcessCommandLine),
    extract("ZipFile\\]::CreateFromDirectory\\([^,]+,\\s+([^\\s\\)]+\\.zip)", 1, ProcessCommandLine)
)
| project DeviceId, DeviceName, ProcessId, ProcessCreationTime, AccountDomain, AccountName, ProcessCommandLine, ZipDestFromCmd;

let zip_file_events =
DeviceFileEvents
| where ActionType in~ ("FileCreated","FileRenamed","FileMoved")
| where tolower(FileName) endswith ".zip"
| where InitiatingProcessFileName in~ ("powershell.exe","pwsh.exe")
| extend ZipFullPath = iff(isempty(FolderPath), FileName, strcat(FolderPath, "\\", FileName))
| project DeviceId, DeviceName, ZipFullPath, FileName, FolderPath, FileSize, FileEventTime=TimeGenerated,
          InitiatingProcessId, InitiatingProcessCreationTime, InitiatingProcessCommandLine,
          InitiatingProcessAccountDomain, InitiatingProcessAccountName;

zip_file_events
| join kind=leftouter (ps_zip_procs) on DeviceId, $left.InitiatingProcessId == $right.ProcessId
| where (
    (isnotempty(InitiatingProcessCommandLine) and InitiatingProcessCommandLine has_any ("Compress-Archive","ZipFile]::CreateFromDirectory","System.IO.Compression"))
    or (isnotempty(ProcessCommandLine) and ProcessCommandLine has_any ("Compress-Archive","ZipFile]::CreateFromDirectory","System.IO.Compression"))
)
| where (
    (isnotempty(InitiatingProcessCommandLine) and InitiatingProcessCommandLine has_any ("C\\Users\\","$env:USERPROFILE","%USERPROFILE%"))
    or (isnotempty(ProcessCommandLine) and ProcessCommandLine has_any ("C\\Users\\","$env:USERPROFILE","%USERPROFILE%"))
)
| summarize FirstSeen=min(FileEventTime),
            FileSize=any(FileSize),
            DeviceName=any(DeviceName),
            InitiatingProcessId=any(InitiatingProcessId),
            InitiatingProcessCreationTime=any(InitiatingProcessCreationTime),
            InitiatingCmd=any(InitiatingProcessCommandLine),
            AccountDomain=any(InitiatingProcessAccountDomain),
            AccountName=any(InitiatingProcessAccountName),
            PSProcessCmd=any(ProcessCommandLine),
            ZipPathFromCmd=any(ZipDestFromCmd)
  by ZipFullPath, DeviceId
| order by FirstSeen asc
pass2295.81s0.1491
gpt-5-mini-high
T1560-data-ps.zip
// Find PowerShell processes that likely created ZIPs and correlate to .zip file writes
let psProcs = DeviceProcessEvents
| where ProcessCommandLine has_any ("powershell", "pwsh.exe", "powershell.exe")
// Restrict to typical archive-creating cmdlets or .NET/Compression usage
| where ProcessCommandLine has_any ("Compress-Archive", "CompressArchive", "System.IO.Compression", "Ionic.Zip", "ZipArchive", ".zip")
| project DeviceId, DeviceName, ProcTime = TimeGenerated, ProcessId, ProcessCreationTime, InitiatingProcessId, ProcCommandLine = ProcessCommandLine, ProcFileName = FileName, ProcFolderPath = FolderPath, AccountName, AccountDomain, InitiatingProcessFileName;

let fileEvents = DeviceFileEvents
| where FileName endswith ".zip" or FileName has ".zip"
| project DeviceId, DeviceName, FileTime = TimeGenerated, FileFolder = FolderPath, FileName, FileSize, FileAction = ActionType, FileInitiatingProcessId = InitiatingProcessId, FileInitiatingCmd = InitiatingProcessCommandLine, FileInitiatingName = InitiatingProcessFileName, RequestAccountName;

let genericFileEvents = DeviceEvents
| where FileName endswith ".zip" or FileName has ".zip"
| project DeviceId, DeviceName, FileTime = TimeGenerated, FileFolder = FolderPath, FileName, FileSize, FileAction = ActionType, Gen_ProcessId = ProcessId, Gen_ProcessCommandLine = ProcessCommandLine, Gen_InitiatingProcessName = InitiatingProcessFileName, Gen_InitiatingProcessId = InitiatingProcessId;

// Join ps processes to fileEvents by DeviceId and either matching initiating process id or time proximity
psProcs
| join kind=leftouter (
    fileEvents
) on DeviceId
| extend pid_match = iif(isnotempty(FileInitiatingProcessId) and FileInitiatingProcessId == ProcessId, 1, 0)
| where pid_match == 1 or (FileTime between (ProcessCreationTime - 1m .. ProcessCreationTime + 30m))
| project DeviceName, DeviceId, ProcessId, ProcessCreationTime, ProcCommandLine, ZipFile = FileName, ZipFolder = FileFolder, ZipFileTime = FileTime, FileSize, FileAction, FileInitiatingName, FileInitiatingCmd

| union (
    // also correlate with generic DeviceEvents file records
    psProcs
    | join kind=leftouter (
        genericFileEvents
    ) on DeviceId
    | extend pid_match = iif(isnotempty(Gen_InitiatingProcessId) and Gen_InitiatingProcessId == ProcessId, 1, 0)
    | where pid_match == 1 or (FileTime between (ProcessCreationTime - 1m .. ProcessCreationTime + 30m))
    | project DeviceName, DeviceId, ProcessId, ProcessCreationTime, ProcCommandLine, ZipFile = FileName, ZipFolder = FileFolder, ZipFileTime = FileTime, FileSize, FileAction, FileInitiatingName = Gen_InitiatingProcessName, FileInitiatingCmd = Gen_ProcessCommandLine
)
| where ZipFile has ".zip"
| summarize FirstSeen = min(ZipFileTime), LastSeen = max(ZipFileTime), AnySize = any(FileSize), AnyAction = any(FileAction), AnyInitiatingName = any(FileInitiatingName), AnyInitiatingCmd = any(FileInitiatingCmd) by DeviceName, DeviceId, ProcessId, ProcCommandLine, ZipFile, ZipFolder
| project DeviceName, DeviceId, ProcessId, ProcCommandLine, ZipFile, ZipFolder, FirstSeen, LastSeen, AnySize, AnyAction, AnyInitiatingName, AnyInitiatingCmd
| order by FirstSeen desc
| take 100
pass334.98s0.0147
gpt-5-mini-low
T1560-data-ps.zip
// Identify PowerShell processes with compression-like activity
let ps_procs = DeviceProcessEvents
| where Timestamp between (startofday(ago(7d)) .. now())
| where tolower(FileName) has_any ("powershell","pwsh","powershell.exe","pwsh.exe")
| where isnotempty(ProcessCommandLine) and (
    ProcessCommandLine contains "Compress-Archive" or
    ProcessCommandLine contains "CompressArchive" or
    ProcessCommandLine contains "ZipFile" or
    ProcessCommandLine contains "System.IO.Compression" or
    ProcessCommandLine contains ".zip" or
    ProcessCommandLine contains "Expand-Archive" or
    ProcessCommandLine contains "Add-Type" or
    ProcessCommandLine contains "-zip" or
    ProcessCommandLine contains "New-Item" and ProcessCommandLine contains "-ItemType" and ProcessCommandLine contains "file"
)
| project DeviceId, DeviceName, ProcessId, ProcTime=Timestamp, ProcessCreationTime, ProcessCommandLine, Account=coalesce(InitiatingProcessAccountName, AccountName), AccountDomain=coalesce(InitiatingProcessAccountDomain, AccountDomain), ReportId;

// Collect .zip file events from DeviceFileEvents
let zip_file_events = DeviceFileEvents
| where Timestamp between (startofday(ago(7d)) .. now())
| where isnotempty(FileName) and tolower(FileName) endswith ".zip"
| extend Action = tostring(ActionType)
| project DeviceId, DeviceName, ZipName=FileName, FolderPath, ZipSize=FileSize, FileAction=Action, InitiatingProcessId=InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessAccountDomain, FileTime=Timestamp;

// Also check DeviceEvents for any .zip references
let zip_deviceevents = DeviceEvents
| where Timestamp between (startofday(ago(7d)) .. now())
| where isnotempty(FileName) and tolower(FileName) endswith ".zip"
| extend Action = tostring(ActionType)
| project DeviceId, DeviceName, ZipName=FileName, FolderPath, ZipSize=FileSize, FileAction=Action, InitiatingProcessId=InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessAccountDomain, FileTime=Timestamp;

let all_zips = union zip_file_events, zip_deviceevents
| summarize any_FolderPath=any(FolderPath), any_ZipSize=any(ZipSize), FileActions=make_set(FileAction), InitiatingProcessId=any(InitiatingProcessId), InitiatingProcessFileName=any(InitiatingProcessFileName), InitiatingProcessCommandLine=any(InitiatingProcessCommandLine), InitiatingProcessAccountName=any(InitiatingProcessAccountName), InitiatingProcessAccountDomain=any(InitiatingProcessAccountDomain), FirstSeen=min(FileTime), LastSeen=max(FileTime) by DeviceId, DeviceName, ZipName;

// Join PowerShell processes to zip file events by DeviceId and either matching process id or time proximity (±5 min)
ps_procs
| join kind=leftouter (
    all_zips
) on DeviceId
| where (
    (isnotempty(InitiatingProcessId) and tolong(InitiatingProcessId) == ProcessId)
    or (isnotempty(FirstSeen) and abs(datetime_diff('second', ProcTime, FirstSeen)) <= 300)
    or (isnotempty(LastSeen) and abs(datetime_diff('second', ProcTime, LastSeen)) <= 300)
)
| extend ZipPath = strcat(coalesce(any_FolderPath, ""), iff(coalesce(any_FolderPath, "") == "", "", "\\"), ZipName)
| project DeviceName, DeviceId, Account, AccountDomain, ProcessId, ProcessCreationTime, ProcessCommandLine, ProcTime, ZipName, ZipPath, ZipSize=any_ZipSize, FileActions = tostring(FileActions), FileFirstSeen = FirstSeen, FileLastSeen = LastSeen
| order by FileLastSeen desc
| distinct DeviceId, DeviceName, Account, AccountDomain, ProcessId, ProcessCommandLine, ZipName, ZipPath, ZipSize, FileActions, FileFirstSeen, FileLastSeen
pass388.54s0.0187
gpt-5-mini-medium
no answer
no query generatedfail50.00s0.0236
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0073
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0096
grok-3-beta
chrome.zip
let TimeRange = ago(7d);
DeviceProcessEvents
| where TimeGenerated >= TimeRange
| where InitiatingProcessFileName =~ 'powershell.exe'
| where ProcessCommandLine has_any ('Compress-Archive', 'zip', 'DestinationPath', '-Path')
| project ProcessTimestamp=Timestamp, DeviceId, DeviceName, InitiatingProcessId, ProcessCommandLine, ProcessCreationTime
| join kind=leftouter (
    DeviceFileEvents
    | where TimeGenerated >= TimeRange
    | where FileName endswith '.zip'
    | where ActionType == 'FileCreated'
    | project FileTimestamp=Timestamp, DeviceId, FileName, FolderPath
) on DeviceId
| where FileTimestamp between (ProcessCreationTime .. timespan(10m))
| project ProcessTimestamp, DeviceName, FileName, FolderPath, ProcessCommandLine
| order by ProcessTimestamp desc
fail452.33s0.0981
grok-3-mini-beta
no answer
no query generatedfail50.00s0.0077
o1-high
T1560-data-ps.zip
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| project DeviceId,
          HostName=DeviceName,
          PSPID=ProcessId,
          PSCommandLine=ProcessCommandLine,
          PSTime=TimeGenerated
| join kind=inner (
    DeviceFileEvents
    | where ActionType == "FileCreated" and FileName endswith ".zip"
    | project DeviceId,
              FileCreatedTime=TimeGenerated,
              ZipFolderPath=FolderPath,
              ZipFileName=FileName,
              ParentPID=InitiatingProcessId
) on $left.DeviceId == $right.DeviceId and $left.PSPID == $right.ParentPID
| project FileCreatedTime,
          HostName,
          ZipFolderPath,
          ZipFileName,
          PSCommandLine
| order by FileCreatedTime desc
pass3120.05s0.6092
o1-low
T1560-data-ps.zip
DeviceFileEvents
| where ActionType in ("FileCreated", "FileCreatedOrModified")
| where FolderPath startswith "C:\\Users\\"
| where FileName endswith ".zip"
| where InitiatingProcessFileName =~ "powershell.exe" or InitiatingProcessCommandLine has "powershell"
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FolderPath, FileName, InitiatingProcessAccountName
| order by TimeGenerated desc
pass127.47s0.2247
o3-high
Sysmon.zip
// -------------------------------------------------------------
//  PowerShell suspected of zipping a user profile – find the ZIP
// -------------------------------------------------------------
// 1.  Candidate PowerShell sessions that look like they are doing
//     compression / archiving.
let PsCompression =
    DeviceProcessEvents
    | where FileName in~ ("powershell.exe", "pwsh.exe")
    | where ProcessCommandLine has_any ("Compress-Archive", "compress-archive", ".zip", "System.IO.Compression")
    | project DeviceId,
              DeviceName,
              PsPID              = ProcessId,
              PsSessionId        = CreatedProcessSessionId,
              PsStartTime        = TimeGenerated,
              AccountName,
              AccountDomain,
              ProcessCommandLine;

// 2.  File-system events that actually create / rename / copy a ZIP file.
let ZipEvents =
    DeviceFileEvents
    | where ActionType in ("FileCreated", "FileCreated (CreateFile)", "FileRenamed", "FileCopied", "FileMoved")
    | where FileName endswith_cs ".zip"
    // optional: focus on user-profile area – comment out if not needed
    //| where FolderPath startswith_cs "C:\\Users\\"
    | extend ZipEventTime = TimeGenerated,
             ZipFullPath  = iff(isempty(FolderPath), FileName, strcat(FolderPath, "\\", FileName))
    | project DeviceId,
              InitiatingProcessId,
              InitiatingProcessSessionId,
              ZipFullPath,
              ZipEventTime;

// 3.  Correlate – same device and (same PID OR same session id) and close in time.
ZipEvents
| join kind=inner (
        PsCompression
    ) on DeviceId
| where (InitiatingProcessId == PsPID or InitiatingProcessSessionId == PsSessionId)
| where ZipEventTime between (PsStartTime - 5m .. PsStartTime + 2h)

// 4.  Return one row per archive with context.
| summarize arg_max(ZipEventTime, ZipFullPath, ProcessCommandLine, PsStartTime) by DeviceName, AccountDomain, AccountName
| project Timestamp       = ZipEventTime,
          DeviceName,
          Account          = strcat(AccountDomain, "\\", AccountName),
          ZipArchivePath   = ZipFullPath,
          PowerShellCmd    = ProcessCommandLine
| order by Timestamp asc
fail3139.58s0.0700
o3-mini-high
T1560-data-ps.zip
union
  (DeviceProcessEvents
    | where InitiatingProcessCommandLine has "powershell"
    | where InitiatingProcessCommandLine has "Compress-Archive"
  ),
  (DeviceFileEvents
    | where FileName endswith ".zip"
    | where FolderPath has "C:\\Users\\"
  )
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, InitiatingProcessCommandLine, SourceSystem, Type
| sort by TimeGenerated desc
pass115.23s0.0125
o3-mini-low
no answer
no query generatedfail50.00s0.0488
o4-mini-high
T1560-data-ps.zip
let CompressEvents =
    DeviceProcessEvents
    // Identify PowerShell compress-archive commands
    | where FileName == "powershell.exe"
    | where ProcessCommandLine has "Compress-Archive"
    | project
        DeviceId,
        DeviceName,
        CompressProcessId = ProcessId,
        CompressTime = TimeGenerated,
        User = AccountName,
        CommandLine = ProcessCommandLine;

let ZipFileCreations =
    DeviceFileEvents
    // Capture created ZIP files
    | where ActionType in ("Created", "FileCreated")
    | where FileName endswith ".zip"
    | project
        DeviceId,
        ZipCreationTime = TimeGenerated,
        InitiatingProcessId,
        ZipFileName = FileName,
        ZipFullPath = strcat(FolderPath, "\\", FileName);

// Correlate the compress command with the ZIP file creation
CompressEvents
| join kind=inner ZipFileCreations
    on $left.DeviceId == $right.DeviceId
    and $left.CompressProcessId == $right.InitiatingProcessId
| project
    ZipCreationTime,
    DeviceId,
    DeviceName,
    User,
    ZipFileName,
    ZipFullPath,
    CommandLine
| sort by ZipCreationTime desc
pass276.91s0.0140
o4-mini-low
no answer
no query generatedfail50.00s0.0585