SentinelOne PowerQuery / Singularity Data Lake
Overview
PowerQuery is SentinelOne's query language for searching the Singularity Data Lake -- the centralized telemetry repository containing process events, network connections, file operations, registry changes, and other security-relevant data from all managed endpoints and cloud workloads. For MSPs, PowerQuery is the primary tool for deep forensic analysis, threat hunting, and incident investigation across client environments.
IMPORTANT: PowerQuery is a Scalyr-based pipeline query language. It is NOT Splunk SPL, SQL, KQL (Kusto), or Elasticsearch Query DSL. The syntax is fundamentally different. The recommended approach is to use the
purple_aitool to generate PowerQuery strings from natural language descriptions, then execute them with thepowerquerytool.
Anti-triggers
- A natural-language question with no query yet. Do not hand-write
PowerQuery from a plain-English prompt —
sentinelone-purple-aigenerates it correctly, and this skill executes what it returns. - "Threat hunting" on a Huntress tenant. The phrase belongs to both
products; the telemetry does not. Huntress raw detections are
huntress-signalsand its confirmed threats arehuntress-incidents. - A specific alert's timeline. Alert notes and history come from the
alert object, not the Data Lake — use
sentinelone-alerts.
MCP Tools
Available Tools
| Tool | Description | Key Parameters |
|---|---|---|
powerquery |
Execute a PowerQuery against the Singularity Data Lake | query (required), fromDate, toDate |
get_timestamp_range |
Get the available time range for PowerQuery data | None |
iso_to_unix_timestamp |
Convert ISO 8601 timestamp to Unix epoch milliseconds | timestamp (required) |
Execute a PowerQuery
Call powerquery with a query string and optional time range:
- query: PowerQuery string (required)
- fromDate: Start of time range (ISO 8601 or Unix epoch ms)
- toDate: End of time range (ISO 8601 or Unix epoch ms)
Default time range: Last 24 hours if not specified.
Example: Find PowerShell network connections:
powerquerywithquery="EventType = \"IP Connect\" AND SrcProcName = \"powershell.exe\" | columns EndpointName, SrcProcCmdLine, DstIP, DstPort | limit 100"
Example: With custom time range:
powerquerywithquery="EventType = \"Process Creation\" AND TgtProcName = \"mimikatz.exe\" | limit 50",fromDate="2026-02-23T00:00:00Z",toDate="2026-02-24T00:00:00Z"
Get Available Time Range
Call get_timestamp_range to determine how far back the Data Lake has data. Returns the earliest and latest available timestamps.
Convert Timestamps
Call iso_to_unix_timestamp to convert ISO 8601 timestamps to Unix epoch milliseconds, which is required by some query parameters.
Key Concepts
PowerQuery Syntax
PowerQuery uses a pipeline model with filters, columns, sorting, and aggregation:
<filter expression>
| columns <field1>, <field2>, ...
| sort -<field>
| limit <n>
| group <field> calculate count() as cnt
Filter Expressions
Filters use field operator value syntax:
| Operator | Description | Example |
|---|---|---|
= |
Equals | EventType = "Process Creation" |
!= |
Not equals | SrcProcName != "explorer.exe" |
contains |
Substring match | TgtProcCmdLine contains "powershell" |
In |
Match list | DstPort In (80, 443, 8080) |
NOT In |
Exclude list | NOT DstIP In ("10.0.0.0/8") |
AND |
Logical AND | EventType = "IP Connect" AND DstPort = 4444 |
OR |
Logical OR | SrcProcName = "cmd.exe" OR SrcProcName = "powershell.exe" |
Pipeline Operators
| Operator | Description | Example |
|---|---|---|
columns |
Select specific fields | | columns EndpointName, SrcProcName, DstIP |
sort |
Sort results (prefix - for descending) |
| sort -EventTime |
limit |
Limit result count (max 100) | | limit 100 |
group |
Aggregate data | | group EndpointName calculate count() as cnt |
filter |
Post-pipeline filter | | filter cnt > 10 |
Common Event Types
| Event Type | Description |
|---|---|
Process Creation |
New process started |
Process Exit |
Process terminated |
IP Connect |
Network connection established |
IP Listen |
Port opened for listening |
File Creation |
File created |
File Modification |
File modified |
File Deletion |
File deleted |
Registry Key Creation |
Registry key created |
Registry Value Modified |
Registry value changed |
DNS |
DNS query |
Login |
User login event |
Logout |
User logout event |
Module Load |
DLL or shared library loaded |
URL |
URL accessed |
Common Fields
| Field | Description |
|---|---|
EndpointName |
Hostname of the endpoint |
SiteName |
SentinelOne site (MSP client) |
EventTime |
Event timestamp |
EventType |
Type of event |
SrcProcName |
Source (parent) process name |
SrcProcCmdLine |
Source process command line |
SrcProcPid |
Source process ID |
TgtProcName |
Target (child) process name |
TgtProcCmdLine |
Target process command line |
TgtProcPid |
Target process ID |
DstIP |
Destination IP address |
DstPort |
Destination port |
SrcIP |
Source IP address |
SrcPort |
Source port |
NetConnStatus |
Network connection status |
TgtFileName |
Target file name/path |
TgtFileHashSha256 |
Target file SHA256 hash |
RegistryKeyPath |
Registry key path |
RegistryValueName |
Registry value name |
DNSRequest |
DNS query domain |
URL |
Accessed URL |
User |
User account |
Query Constraints
| Constraint | Value |
|---|---|
| Maximum rows returned | 100 |
| Default time range | Last 24 hours |
| Query timeout | 5 minutes |
| Empty results | Valid (no matching data, not an error) |
Common Hunting Scenarios
Lateral Movement
EventType = "Process Creation" AND
(TgtProcName = "psexec.exe" OR TgtProcName = "psexesvc.exe" OR
TgtProcCmdLine contains "wmic" AND TgtProcCmdLine contains "/node:")
| columns EndpointName, SiteName, SrcProcName, TgtProcName, TgtProcCmdLine, EventTime
| sort -EventTime
| limit 100
Credential Access (LSASS)
EventType = "Process Creation" AND
TgtProcCmdLine contains "lsass" AND
SrcProcName != "svchost.exe" AND SrcProcName != "csrss.exe"
| columns EndpointName, SiteName, SrcProcName, TgtProcName, TgtProcCmdLine, User, EventTime
| sort -EventTime
| limit 100
Persistence (Scheduled Tasks)
EventType = "Process Creation" AND
TgtProcName = "schtasks.exe" AND TgtProcCmdLine contains "/create"
| columns EndpointName, SiteName, SrcProcName, TgtProcCmdLine, User, EventTime
| sort -EventTime
| limit 100
Command & Control (Beaconing)
EventType = "IP Connect" AND NetConnStatus = "SUCCESS" AND
NOT DstIP In ("10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16") AND
DstPort NOT In (80, 443)
| group DstIP, SrcProcName, EndpointName calculate count() as connections
| filter connections > 50
| sort -connections
| limit 100
Data Staging
EventType = "Process Creation" AND
(TgtProcName In ("7z.exe", "rar.exe", "zip.exe", "tar.exe") OR
TgtProcCmdLine contains "Compress-Archive")
| columns EndpointName, SiteName, SrcProcName, TgtProcCmdLine, User, EventTime
| sort -EventTime
| limit 100
LOLBIN Activity
EventType = "Process Creation" AND
TgtProcName In ("certutil.exe", "mshta.exe", "regsvr32.exe", "rundll32.exe",
"wscript.exe", "cscript.exe", "bitsadmin.exe") AND
(TgtProcCmdLine contains "http" OR TgtProcCmdLine contains "ftp" OR
TgtProcCmdLine contains "/decode" OR TgtProcCmdLine contains "script:")
| columns EndpointName, SiteName, SrcProcName, TgtProcName, TgtProcCmdLine, EventTime
| sort -EventTime
| limit 100
DNS Tunneling
EventType = "DNS" AND
DNSRequest contains "." AND
NOT DNSRequest In ("*.microsoft.com", "*.windows.com", "*.windowsupdate.com",
"*.office.com", "*.sentinelone.net")
| group DNSRequest calculate count() as queries
| filter queries > 100
| sort -queries
| limit 100
Phishing (Office Macro Execution)
EventType = "Process Creation" AND
SrcProcName In ("winword.exe", "excel.exe", "powerpnt.exe") AND
TgtProcName In ("powershell.exe", "cmd.exe", "wscript.exe", "cscript.exe", "mshta.exe")
| columns EndpointName, SiteName, SrcProcName, TgtProcName, TgtProcCmdLine, User, EventTime
| sort -EventTime
| limit 100
Typical Workflow
The recommended threat hunting workflow is:
- Describe the threat to Purple AI - Call
purple_aiwith a natural language description of what you want to find - Review the generated PowerQuery - Purple AI returns one or more PowerQuery strings
- Check time range - Call
get_timestamp_rangeto verify data availability - Execute the query - Call
powerquerywith the generated query string - Analyze results - Review returned rows for indicators of compromise
- Iterate - Refine the query based on initial results, or ask Purple AI for follow-up queries
Response Examples
PowerQuery Result:
{
"rows": [
{
"EndpointName": "ACME-WS-042",
"SrcProcName": "winword.exe",
"TgtProcName": "powershell.exe",
"TgtProcCmdLine": "powershell.exe -enc aQBlAHgA...",
"EventTime": "2026-02-24T08:12:34.000Z"
},
{
"EndpointName": "ACME-WS-015",
"SrcProcName": "excel.exe",
"TgtProcName": "cmd.exe",
"TgtProcCmdLine": "cmd.exe /c whoami && net user",
"EventTime": "2026-02-24T07:45:12.000Z"
}
],
"totalRows": 2
}
Empty Result (Valid):
{
"rows": [],
"totalRows": 0
}
Empty results are valid and common in threat hunting. No results means no matching telemetry was found -- which is often a positive finding.
Error Handling
Common Errors
| Error | Cause | Resolution |
|---|---|---|
| Syntax error | Invalid PowerQuery syntax | Use purple_ai to generate correct syntax |
| Timeout | Query too broad or time range too large | Narrow the time range or add more filters |
| No data available | Time range outside Data Lake retention | Call get_timestamp_range to check availability |
| Authentication error | Invalid token | Verify Service User token is Account or Site level |
| Rate limited | Too many queries | Wait before retrying |
PowerQuery Syntax Tips
- String values must be in double quotes:
SrcProcName = "powershell.exe" - Use
In(capital I) for list matches:DstPort In (80, 443) - Use
NOTbefore conditions for negation:NOT DstIP In ("10.0.0.0/8") - Pipeline operators start with
|on a new line or after a space - Comments are not supported in PowerQuery
Best Practices
- Use Purple AI to generate queries - Do not write PowerQuery manually unless you are familiar with the syntax
- Always set a time range - Avoid scanning the entire Data Lake; default to 24 hours
- Start narrow, then broaden - Begin with specific filters and widen if no results
- Use the columns operator - Select only the fields you need for faster results
- Limit results - Always include
| limit 100to stay within the row limit - Check for empty results - Empty results are valid; they mean no matching data
- Iterate on findings - Use initial results to refine follow-up queries
- Filter by site - Add
SiteName = "Client Name"to scope hunts to specific clients - Combine with alerts - Cross-reference PowerQuery findings with alert data
- Document queries - Save successful hunting queries for reuse across client environments
Related Skills
- Purple AI - Generate PowerQuery strings from natural language
- Alerts - Alert context for threat hunting findings
- API Patterns - MCP tools reference and connection info
- Inventory - Asset context for endpoints in query results
- Vulnerabilities - Vulnerability context for compromised endpoints