Azure-Sentinel/Tools/RuleMigration/SPL to KQL.md

26 KiB

Common Search Commands


SPL Command Description SPL Example KQL KQL Example
chart/ timechart Returns results in a tabular output for (time-series) charting. render
 … | render timechart
dedup Removes subsequent results that match a specified criterion. distinct
summarize
… | summarize by Computer, EventID 
eval Calculates an expression.
See Common Eval Commands for more Eval Commands.
extend
T | extend duration = endTime - startTime
fields Removes fields from search results. project
project-away
T | project cost=price*quantity, price
head/tail Returns the first/last N results. top
 T | top 5 by Name desc nulls last 
lookup Adds field values from an external source. externaldata
lookup
 Users 
| where UserID in ((externaldata (UserID:string) [
@"https://storageaccount.blob.core.windows.net/
storagecontainer/users.txt"
h@"?...SAS..." // Secret token to access the blob
])) | ...
rename Renames a field. Use wildcards to specify multiple fields. project-rename
 T | project-rename new_column_name = column_name 
rex Specifies regular expression named groups to extract fields. matches regex
… | where field matches regex "^addr.*" 
search Filters results to those that match the search expression. search
search "X"
sort Sorts the search results by the specified fields. sort
 T | sort by strlen(country) asc, price desc 
stats Provides statistics, grouped optionally by fields.
See Common Stats Commands for more Stats Commands.
summarize
Sales 
| summarize NumTransactions=count(),
Total=sum(UnitPrice * NumUnits) by Fruit,
StartOfMonth=startofmonth(SellDateTime)
mstats Similar to stats but used on metrics instead of events. summarize
 T 
| summarize count() by price_range=bin(price, 10.0)
table Specifies fields to keep in the result set. Retains data in tabular format. project
T | project columnA, columnB
top/rare Displays the most/least common values of a field. top
T | top 5 by Name desc nulls last 
transaction Groups search results into transactions. sourcetype=MyLogTable type=Event
| transaction ActivityId startswith="Start" endswith="Stop"
| Rename timestamp as StartTime
| Table City, ActivityId, StartTime, Duration
Refer to example

row_window_session
let Events = MyLogTable | where type=="Event";
Events
| where Name == "Start"
| project Name, City, ActivityId, StartTime=timestamp
| join (Events
| where Name == "Stop"
| project StopTime=timestamp, ActivityId)
on ActivityId
| project City, ActivityId, StartTime,
Duration = StopTime – StartTime

Note:
Use row_window_session() if you need to calculate session start values of a column in a serialized row set.
...| extend SessionStarted = row_window_session(
Timestamp, 1h, 5m, ID != prev(ID))
eventstats Generates summary statistics from fields in your events and saves those statistics in a new field. … | bin span=1m _time
|stats count AS count_i by _time, category
| eventstats sum(count_i) as count_total by _time
join
make_list
mv-expand

Refer to examples
Example 1 - Using join:
let binSize = 1h;
let detail = SecurityEvent
| summarize detail_count = count() by EventID,
tbin = bin(TimeGenerated, binSize);
let summary = SecurityEvent
| summarize sum_count = count() by
tbin = bin(TimeGenerated, binSize);
detail
| join kind=leftouter (summary) on tbin
| project-away tbin1
Or

Example 2 - Using make_list:
let binSize = 1m;
SecurityEvent
| where TimeGenerated >= ago(24h)
| summarize TotalEvents = count() by EventID,
groupBin =bin(TimeGenerated, binSize)
|summarize make_list(EventID), make_list(TotalEvents),
sum(TotalEvents) by groupBin
| mvexpand list_EventID, list_TotalEvents
streamstats Find the cumulative sum of a field. ... | streamstats sum(bytes) as bytes _ total | timechart row_cumsum ...| serialize cs=row_cumsum(bytes)
anomalydetection Find anomalies in the specified field. sourcetype=nasdaq earliest=-10y
| anomalydetection Close _ Price
series_decompose_
anomalies()
let LookBackPeriod= 7d;
let disableAccountLogon=SignIn
| where ResultType == "50057"
| where ResultDescription has "account is disabled";
disableAccountLogon
| make-series Trend=count() default=0 on TimeGenerated
in range(startofday(ago(LookBackPeriod)), now(), 1d)
| extend (RSquare,Slope,Variance,RVariance,Interception,
LineFit)=series_fit_line(Trend)
| extend (anomalies,score) =
series_decompose_anomalies(Trend)
where Filters search results using eval expressions. Used to compare two different fields. where
T | where fruit=="apple"



Common Eval Commands


SPL Command Description SPL Example KQL KQL Example
abs(X) Returns the absolute value of X. abs(number) abs()
abs(X)
case(X,"Y",…) Takes pairs of arguments X and Y, where X arguments are Boolean expressions.
When evaluated to TRUE, the arguments return the corresponding Y argument.
case(error == 404, "Not found",
error == 500,"Internal Server Error",
error == 200, "OK")
case
T
| extend Message = case(error == 404, "Not found",
error == 500,"Internal Server Error", "OK")
ceil(X) Ceiling of a number X. ceil(1.9) ceiling()
ceiling(1.9)
cidrmatch("X",Y) Identifies IP addresses that belong to a particular subnet. cidrmatch("123.132.32.0/25",ip) ipv4_is_match()
ipv6_is_match()
ipv4_is_match('192.168.1.1', '192.168.1.255')
== false
coalesce(X,…) Returns the first value that is not null. coalesce(null(), "Returned val", null()) coalesce()
coalesce(tolong("not a number"), tolong("42"),
33) == 42
cos(X) Calculates the cosine of X. n=cos(0) cos()
cos(X)
exact(X) Evaluates an expression X using double precision floating point arithmetic. exact(3.14*num) todecimal()
todecimal(3.14*2)
exp(X) Returns eX. exp(3) exp()
exp(3)
if(X,Y,Z) If X evaluates to TRUE, the result is the second argument Y.
If X evaluates to FALSE, the result evaluates to the third argument Z.
if(error==200, "OK", "Error") iif()
iif(floor(Timestamp, 1d)==floor(now(), 1d), 
"today", "anotherday")
isbool(X) Returns TRUE if X is Boolean. isbool(field) iif()
gettype()
iif(gettype(X) =="bool","TRUE","FALSE")
isint(X) Returns TRUE if X is Integer. isint(field) iif()
gettype()
iif(gettype(X) =="long","TRUE","FALSE")
isnull(X) Returns TRUE if X is NULL. isnull(field) isnull()
isnull(field)
isstr(X) Returns TRUE if X is String. isstr(field) iif()
gettype()
iif(gettype(X) =="string","TRUE","FALSE")
len(X) This function returns the character length of a string X. len(field) strlen()
strlen(field)
like(X,"y") Returns TRUE if and only if X is like the SQLite pattern in Y. like(field, "addr%") has
contains
startswith
matches regex

… | where field has "addr"

… | where field contains "addr"

… | where field startswith "addr"

… | where field matches regex "^addr.*"
log(X,Y) Returns the log of the first argument X using the second argument Y as the base.
Y defaults to 10.
log(number,2) log
log2
log10
log(X)
log2(X)
log10(X)
lower(X) Returns the lowercase of X. lower(username) tolower
tolower(username)
ltrim(X,Y) Returns X with the characters in Y trimmed from the left side.
Y defaults to spaces and tabs.
ltrim(" ZZZabcZZ ", " Z") trim_start()
trim_start(“ ZZZabcZZ”,” ZZZ”)
match(X,Y) Returns if X matches the regex pattern Y. match(field, "^\d{1,3}.\d$") matches regex
… | where field matches regex @"^\d{1,3}.\d$")
max(X,…) Returns the maximum value in a column. max(delay, mydelay) max()
arg_max()
… | summarize max(field)
md5(X) Returns the MD5 hash of a string value X. md5(field) hash_md5
hash_md5("X")
min(X,…) Returns the minimum value in a column. min(delay, mydelay) min_of()
min()
arg_min
min_of (expr_1, expr_2 ...)

…|summarize min(expr)

…| summarize arg_min(Price,*) by Product
mvcount(X) Returns the number of values of X. mvcount(multifield) dcount
…| summarize dcount(X) by Y
mvfilter(X) Filters a multi-valued field based on the Boolean expression X. mvfilter(match(email, "net$")) mv-apply
T | mv-apply Metric to typeof(real) on 
(
top 2 by Metric desc
)
mvindex(X,Y,Z) Returns a subset of the multivalued field X from start position (zero-based) Y to Z (optional). mvindex( multifield, 2) array_slice
array_slice(arr, 1, 2)
mvjoin(X,Y) Given a multi-valued field X and string delimiter Y, and joins the individual values of X using Y. mvjoin(address, ";") strcat_array
strcat_array(dynamic([1, 2, 3]), "->")
now() Returns the current time, represented in Unix time. now() now()
now()

now(-2d)
null() This function takes no arguments and returns NULL. null() null
null
nullif(X,Y) Given two arguments, fields X and Y, and returns the X if the arguments are different. Otherwise returns NULL. nullif(fieldA, fieldB) iif
iif(fieldA==fieldB, null, fieldA)
random() Returns a pseudo-random number ranging from 0 to 2147483647. random() rand()
rand()
relative_ time(X,Y) Given epochtime time X and relative time specifier Y, returns the epochtime value of Y applied to X. relative_time(now(),"-1d@d") unix time
let toUnixTime = (dt:datetime)
{
(dt - datetime(1970-01-01))/1s
};
replace(X,Y,Z) Returns a string formed by substituting string Z for every occurrence of regex string Y in string X. Returns date with the month and day numbers switched.
If the input was 4/30/2015 the return value would be 30/4/2009:

replace(date, "^(\d{1,2})/ (\d{1,2})/", "\2/\1/")
replace()
replace( @'^(\d{1,2})/(\d{1,2})/', @'\2/\1/',date)
round(X,Y) Returns X rounded to the amount of decimal places specified by Y. The default is to round to an integer. round(3.5) round()
round(3.5)
rtrim(X,Y) Returns X with the characters in Y trimmed from the right side. If Y is not specified, spaces and tabs are trimmed. rtrim(" ZZZZabcZZ ", " Z") trim_end()
trim_end(@"[ Z]+",A)
searchmatch(X) Returns TRUE if the event matches the search string X. searchmatch("foo AND bar") iif()
iif(field has "X","Yes","No")
split(X,"Y") Returns X as a multi-valued field, split by delimiter Y. split(address, ";") split()
split(address, ";")
sqrt(X) Returns the square root of X. sqrt(9) sqrt()
sqrt(9)
strftime(X,Y) Returns epochtime value X rendered using the format specified by Y. strftime(_time, "%H:%M") format_datetime()
format_datetime(time,'HH:mm')
strptime(X,Y) Given a time represented by a string X, returns value parsed from format Y. strptime(timeStr, "%H:%M") format_datetime()
format_datetime(datetime('2017-08-16 11:25:10'),
'HH:mm')
substr(X,Y,Z) Returns a substring field X from start position (1-based) Y for Z (optional) characters. substr("string", 1, 3) substring()
substring("string", 0, 3)
time() Returns the wall-clock time with microsecond resolution. time() format_datetime()
format_datetime(datetime(2015-12-14 02:03:04),
'h:m:s')
tonumber(X,Y) Converts input string X to a number, where Y (optional, defaults to 10) defines the base of the number to convert to. tonumber("0A4",16) toint()
toint("123")
tostring(X,Y) Returns a field value of X as a string. If the value of X is a number, it reformats it as a string.

If X is a Boolean value, reformats to TRUE or FALSE. If X is a number, the second argument Y is optional and can either be "hex" (convert X to hexadecimal), "commas" (formats X with commas and 2 decimal places), or "duration" (converts seconds X to readable time format HH:MM:SS).
This example returns:
foo=615 and foo2=00:10:15:

… | eval foo=615 | eval foo2 = tostring(
foo, "duration")
tostring()
tostring(123)
typeof(X) Returns a string representation of the field type. typeof(12) gettype()
gettype(12)
urldecode(X) Returns the URL X decoded. urldecode("http%3A%2F%2Fwww.
splunk.com%2Fdownload%3Fr%3D
header")
url_decode
url_decode('https%3a%2f%2fwww.bing.com%2f')



Common Stats Commands


SPL Command Description KQL KQL Example
avg(X) Returns the average of the values of field X. avg()
avg(X)
count(X) Returns the number of occurrences of the field X. To indicate a specific field value to match, format X as eval(field="value"). count()
summarize count()
dc(X) Returns the count of distinct values of the field X. dcount()
…| summarize countries=dcount(country) by continent
earliest(X) Returns the chronologically earliest seen value of X. arg_min()
… | summarize arg_min(TimeGenerated, *) by X
latest(X) Returns the chronologically latest seen value of X. arg_max()
… | summarize arg_max(TimeGenerated, *) by X
max(X) Returns the maximum value of the field X. If the values of X are non-numeric, the max is found from alphabetical ordering. max()
…| summarize max(X)
median(X) Returns the middle-most value of the field X. percentile()
…| summarize percentile(X, 50)
min(X) Returns the minimum value of the field X. If the values of X are non-numeric, the min is found from alphabetical ordering. min()
…| summarize min(X)
mode(X) Returns the most frequent value of the field X. top-hitters()
…| top-hitters 1 of Y by X
perc(Y) Returns the X-th percentile value of the field Y. For example, perc5(total) returns the 5th percentile value of a field "total". percentile()
…| summarize percentile(Y, 5)
range(X) Returns the difference between the max and min values of the field X. range()
range(1, 3)
stdev(X) Returns the sample standard deviation of the field X. stdev
stdev()
stdevp(X) Returns the population standard deviation of the field X. stdevp()
stdevp()
sum(X) Returns the sum of the values of the field X. sum()
sum(X)
sumsq(X) Returns the sum of the squares of the values of the field X.
values(X) Returns the list of all distinct values of the field X as a multi-value entry. The order of the values is alphabetical. make_set()
…| summarize r = make_set(X)
var(X) Returns the sample variance of the field X. variance()
variance(X)



The above SPL samples are based on Splunk quick reference guide