Microsoft Sentinel 中的 Kusto 查詢語言
Kusto 查詢語言 是您用來處理和操作 Sentinel Microsoft數據的語言。 如果您無法分析饋送到工作區的記錄,並取得那其中所有資料中隱藏的重要資訊,則這些記錄就沒什麼價值。 Kusto 查詢語言不僅具備取得該資訊的能力和彈性,而且還具備協助您快速開始使用的簡單性。 如果您有腳本或使用資料庫的背景,本文的內容應該很熟悉。 如果沒有,別擔心,因為語言的直覺本質可讓您快速開始撰寫自己的查詢,並為組織創造價值。
本文介紹 Kusto 查詢語言 的基本概念,涵蓋一些最常用的函式和運算符,該函式和運算符應處理 75%至 80% 的使用者每天撰寫的查詢。 當您需要更深入或執行更進階的查詢時,您可以利用新的 進階 KQL for Microsoft Sentinel 活頁簿(請參閱此 簡介部落格文章)。 另請參閱官方 Kusto 查詢語言 檔和各種在線課程(如 Pluralsight)。
背景 - 為何是 Kusto 查詢語言?
Microsoft Sentinel 建置於 Azure 監視器服務之上,並使用 Azure 監視器的 Log Analytics 工作區來儲存其所有資料。 此資料包括下列任一項:
- 使用 Microsoft Sentinel 資料連接器,從外部來源擷取到預先定義資料表的資料。
- 使用自定義建立的數據連接器和某些類型的現成連接器,從外部來源擷取至使用者定義的自定義數據表。
- 由 Microsoft Sentinel 本身建立的資料 (產生自其建立並執行的分析),例如,警示、事件及 UEBA 相關資訊。
- 上傳至 Microsoft Sentinel 以協助偵測和分析的資料,例如,威脅情報摘要和關注清單。
Kusto 查詢語言是作為 Azure 資料總管服務的一部分來開發,因此,會針對在雲端環境中搜尋巨量資料存放區進行最佳化。 受到著名海底探險家 Jacques Cousteau (相應發音為 "koo-STOH") 所啟發,此語言的設計目的是協助您深入探索資料海洋,並探索隱藏其中的寶藏。
Kusto 查詢語言 也用於 Azure 監視器,並支援額外的 Azure 監視器功能,可讓您擷取、可視化、分析和剖析 Log Analytics 數據存放區中的數據。 在 Microsoft Sentinel 中,不論是在現有的規則和活頁簿中,還是在建置您自己的規則中,每當您將資料視覺化且進行分析並搜捕威脅時,都會使用以 Kusto 查詢語言為基礎的工具。
因為 Kusto 查詢語言 是您在Microsoft Sentinel 中幾乎所做的一切的一部分,因此清楚瞭解其運作方式可協助您從 SIEM 中獲取更多功能。
什麼是查詢?
Kusto 查詢語言的查詢是處理資料並傳回結果的唯讀要求,它不會寫入任何資料。 查詢會針對組織為資料庫、資料表及資料行階層的資料進行操作,類似於 SQL。
要求均會明文陳述,並使用設計來讓語法易於讀取、撰寫及自動執行的資料流程模型。
Kusto 查詢語言的查詢由以分號分隔的「陳述式」所組成。 有許多類型的語句,但只有兩種廣泛使用的類型:
表格式運算式陳述式是我們一般在討論查詢時所代表的意義,這些是查詢的實際主體。 有個關於表格式運算式陳述式需了解的重要事項是,它們接受表格式輸入 (資料表或其他表格式運算式),並產生表格式輸出。 至少需要有這其中一個。 本文其餘大部分討論這種語句。
let 陳述式可讓您在查詢主體之外建立並定義變數與常數,以便更容易閱讀且具多樣性。 這些是選擇性,可根據您的特殊需求而定。 我們會在文章結尾處理這種陳述。
示範環境
您可以在 Azure 入口網站的 Log Analytics 示範環境中練習 Kusto 查詢語言陳述式,包括此文章中的陳述式。 使用此練習環境不收費,但您需要 Azure 帳戶才能存取。
探索示範環境。 就像生產環境中的Log Analytics一樣,它可以用許多方式使用:
選擇要在其中建置查詢的資料表。 從預設的 [資料表] 索引標籤 (顯示於左上方的紅色矩形中),從依主題群組的資料表清單中選取資料表 (顯示於左下方)。 展開主題以查看個別資料表,您可以進一步展開每個資料表來查看其所有欄位 (資料行)。 按兩下資料表或功能變數名稱,會將它放在查詢視窗中游標的點。 在資料表名稱之後輸入查詢的其餘部分,如下所示。
尋找要研究或修改的現有查詢。 選取 [查詢] 索引標籤 (顯示於左上方的紅色矩形中),以查看現成可用的查詢清單。 或者,從右上方的按鈕列中選取 [查詢]。 您可以探索隨附於 Microsoft Sentinel 的現成查詢。 按兩下查詢會將整個查詢放在資料指標點的查詢視窗中。
如同在此示範環境中,您可以在 Microsoft Sentinel 的 [記錄] 頁面中查詢和篩選資料。 您可以選取資料表並向下切入,以查看資料行。 您可以使用 [欄位選擇器] 來修改顯示的預設資料行,也可以為查詢設定預設時間範圍。 如果在查詢中明確定義時間範圍,時間篩選就無法使用(灰色)。 如需更多資訊,請參閱
如果您已上線至 Microsoft的統一安全性作業平臺,您也可以在 Microsoft Defender 進階搜捕 頁面中查詢和篩選數據。 如需詳細資訊,請參閱 Microsoft Defender 入口網站中使用 Microsoft Sentinel 數據的進階搜捕。
查詢結構
學習 Kusto 查詢語言時,了解整體查詢結構是個不錯的起點。 查看 Kusto 查詢時所注意到的第一件事是使用管道符號 (|
)。 Kusto 查詢的結構首先會從資料來源取得資料,然後在「管線」中傳遞資料,而每個步驟都會提供某種程度的處理,接著將資料傳遞到下一個步驟。 在管線結束時,您會取得最終結果。 實際上,這是我們的管線:
Get Data | Filter | Summarize | Sort | Select
這個將數據傳遞至管線的概念可讓結構直覺化,因為您可以輕鬆地在每個步驟中建立數據的精神圖片。
為了說明這一點,讓我們看看下列查詢,其會查看 Microsoft Entra 登入記錄。 當您逐行閱讀時,可以看到指出資料發生狀況的關鍵字。 我們已在每一行,以註解形式包含管線中的相關階段。
注意
您可以透過在註解前面加上雙斜線 (//
),將註解新增到查詢中的任一行。
SigninLogs // Get data
| evaluate bag_unpack(LocationDetails) // Ignore this line for now; we'll come back to it at the end.
| where RiskLevelDuringSignIn == 'none' // Filter
and TimeGenerated >= ago(7d) // Filter
| summarize Count = count() by city // Summarize
| sort by Count desc // Sort
| take 5 // Select
由於每個步驟的輸出都會作為下一個步驟的輸入,因此,步驟的順序可以判斷查詢的結果並影響其效能。 請務必根據您希望從查詢中取得的內容來排序步驟。
提示
- 有個良好的經驗法則是提早篩選資料,因此,您只需沿著管線傳遞相關資料。 這可大幅提升效能,並確保您不會意外地在摘要步驟中包含不相關的數據。
- 本文指出一些其他最佳做法要牢記在心。 如需更完整的清單,請參閱查詢最佳做法。
希望您現在已對 Kusto 查詢語言中查詢的整體結構有所了解。 現在,讓我們看看實際查詢運算子本身,其可用來建立查詢。
資料類型
進入查詢運算子之前,讓我們先快速查看資料類型。 如同大多數語言,資料類型會決定可以針對值執行哪些計算和操作。 例如,如果您有 string 類型的值,將無法對其執行算術計算。
在 Kusto 查詢語言中,大多數資料類型都遵循標準慣例,並具有您先前可能已看過的名稱。 下表顯示完整清單:
資料類型表格
類型 | 其他名稱 | 對等的 .NET 類型 |
---|---|---|
bool |
Boolean |
System.Boolean |
datetime |
Date |
System.DateTime |
dynamic |
System.Object |
|
guid |
uuid , uniqueid |
System.Guid |
int |
System.Int32 |
|
long |
System.Int64 |
|
real |
Double |
System.Double |
string |
System.String |
|
timespan |
Time |
System.TimeSpan |
decimal |
System.Data.SqlTypes.SqlDecimal |
儘管大多數資料類型均為標準,但您可能不熟悉 dynamic、timespan 和 guid 等類型。
Dynamic 的結構與 JSON 類似,但有一個主要差異:它可以儲存傳統 JSON 無法 Kusto 查詢語言 特定數據類型,例如巢狀動態值或時間範圍。 以下為 dynamic 類型的範例:
{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}
Timespan 是一種資料類型,可參考時間量值,例如小時、天或秒。 請勿將時間範圍與 datetime 混淆,這會評估為實際的日期和時間,而不是時間的量值。 下表顯示 timespan 尾碼的清單。
Timespan 尾碼
函式 | 描述 |
---|---|
D |
days |
H |
hours |
M |
分鐘 |
S |
seconds |
Ms |
milliseconds |
Microsecond |
微秒 |
Tick |
奈秒 |
Guid 是代表 128 位全域唯一標識符的數據類型,其遵循標準格式為 [8]-[4]-[4]-[4]-[12],其中每個 [number] 代表字元數目,且每個字符的範圍可以是 0-9 或 a-f。
注意
Kusto 查詢語言同時具有表格式和純量運算子。 在此文章的其餘部分,如果您只看到「運算子」一詞,除非另有說明,否則,可假設其表示表格式運算子。
取得、限制、排序及篩選資料
Kusto 查詢語言 的核心詞彙-可讓您完成大部分工作的基礎 -- 是篩選、排序和選取數據的運算符集合。 其餘的工作會要求您擴充語言的知識,以符合更進階的需求。 讓我們在先前的範例中使用的一些命令上展開一點,並查看 take
、 sort
和 where
。
在這些運算符中,我們會檢查其在先前 的 SigninLogs 範例中的用法,並瞭解有用的秘訣或最佳做法。
取得資料
所有基本查詢的第一行均會指定您要使用的資料表。 Microsoft Sentinel 的情況下,這可能是工作區中的記錄類型名稱,例如 SigninLogs、SecurityAlert 或 CommonSecurityLog。 例如:
SigninLogs
在 Kusto 查詢語言 中,記錄檔名稱會區分大小寫,因此SigninLogs
會signinLogs
以不同的方式解譯。 在選擇自定義記錄的名稱時,請小心,因此很容易識別它們,且與另一個記錄檔不太類似。
限制資料:take / limit
take 運算子 (以及相同的 limit 運算子) 可用於透過只傳回指定的資料列數目來限制結果。 後面接著一個整數,指定要傳回的資料列數目。 一般而言,在您判斷排序順序之後,它會在查詢結尾使用,在這種情況下,它會傳回排序順序頂端的指定數據列數目。
當您不想傳回大型資料集時,在查詢早期使用 take
,對測試查詢很有用。 不過,如果您在任何sort
作業之前放置take
作業,則會take
以隨機方式傳回選取的數據列,而且每次執行查詢時,可能都會傳回一組不同的數據列。 以下是使用 take 的範例:
SigninLogs
| take 5
提示
當您在可能不知道查詢外觀的全新查詢上工作時,將語句放在 take
開頭,以人為方式限制數據集以加快處理和實驗的速度會很有用。 當您滿意整個查詢之後,即可移除初始的 take
步驟。
排序資料:sort / order
sort 運算子 (以及相同的 order 運算子) 可用來依指定的資料行排序資料。 在下列範例中,我們依 TimeGenerated 排序結果,並使用 desc 參數來將排序方向設為遞減,即先放置最高值;針對遞增順序,我們使用 asc。
注意
排序的預設方向是遞減,因此,技術上,您只需指定是否要以遞增順序排序。 不過,在任何情況下指定排序方向,讓您的查詢更容易閱讀。
SigninLogs
| sort by TimeGenerated desc
| take 5
如前所述,我們將 sort
運算子放在 take
運算子之前。 我們需要先排序,以確保會取得五個適當的記錄。
前幾個
top 運算子可讓我們將 sort
和 take
運算合併為單一運算子:
SigninLogs
| top 5 by TimeGenerated desc
如果兩個或多個記錄在您排序依據的數據行中具有相同值,您可以新增更多數據行來排序依據。 在逗號分隔清單中新增額外的排序資料行,位於第一個排序資料行之後,但在排序順序關鍵字之前。 例如:
SigninLogs
| sort by TimeGenerated, Identity desc
| take 5
現在,如果 TimeGenerated 在多個記錄之間相同,則會嘗試依 Identity 數據行中的值排序。
注意
何時使用 sort
和 take
,以及何時使用 top
如果您只排序一個欄位,請使用
top
,因為它提供比sort
和take
的組合更好的效能。如果您需要對多個字段進行排序(例如在上一個範例中),
top
則無法這麼做,因此您必須使用sort
和take
。
篩選資料:where
其中 運算子可以說是最重要的運算符,因為它是確定您只處理與案例相關的數據子集的關鍵。 您應該盡最大努力在查詢中儘早篩選數據,因為這樣做可藉由減少後續步驟中需要處理的數據量來改善查詢效能:它也可確保您只對所需的數據執行計算。 請參閱此範例:
SigninLogs
| where TimeGenerated >= ago(7d)
| sort by TimeGenerated, Identity desc
| take 5
where
運算子會指定變數、比較 (「純量」) 運算子和值。 在我們的案例中,使用了 >=
來表示 TimeGenerated 資料行中的值必須大於 (也就是晚於) 或等於七天前。
Kusto 查詢語言中有兩種類型的比較運算子:字串和數值。 下表顯示數值運算子的完整清單:
數值運算子
Operator | 描述 |
---|---|
+ |
加法 |
- |
減 |
* |
乘法 |
/ |
除法 |
% |
模數 |
< |
小於 |
> |
大於 |
== |
等於 |
!= |
不等於 |
<= |
小於或等於 |
>= |
大於或等於 |
in |
等於其中一個元素 |
!in |
不等於任何元素 |
字串運算符清單是較長的清單,因為它具有區分大小寫、子字串位置、前置詞、後綴等等的排列。 ==
運算子既是數值運算子,同時也是字串運算子,這表示它可以同時用於數字和文字。 例如,下列兩個陳述式都是有效的 Where 陳述式:
| where ResultType == 0
| where Category == 'SignInLogs'
最佳做法: 在大部分情況下,您可能想要依多個數據行篩選數據,或以多個方式篩選相同的數據行。 在這些情況下,您應該記住兩種最佳做法。
您可以使用 and 關鍵字,將多個 where
陳述式合併為單一步驟。 例如:
SigninLogs
| where Resource == ResourceGroup
and TimeGenerated >= ago(7d)
當您使用 和 關鍵詞將多個篩選聯結至單where
一語句時,只要先放置只參考單一數據行的篩選,即可取得較佳的效能。 因此,撰寫上一個查詢的更好方式是:
SigninLogs
| where TimeGenerated >= ago(7d)
and Resource == ResourceGroup
在此範例中,第一個篩選提及單一資料行 (TimeGenerated),第二個篩選則參考兩個資料行 (Resource 和 ResourceGroup)。
摘要資料
Summarize 是 Kusto 查詢語言 中最重要的表格式運算符之一,但它也是較複雜的運算符之一,可瞭解您是否是一般查詢語言的新手。 summarize
的作業是取得一個資料資料表,並輸出由一或多個資料行彙總的「新資料表」。
Summarize 陳述式的結構
summarize
陳述式的基本結構如下:
| summarize <aggregation> by <column>
例如,以下傳回 Perf 資料表中,每個 CounterName 值的記錄計數:
Perf
| summarize count() by CounterName
因為的輸出 summarize
是新的數據表,因此語句中 summarize
未明確指定的任何數據行都不會傳遞至管線。 為了說明此概念,請考量下列範例:
Perf
| project ObjectName, CounterValue, CounterName
| summarize count() by CounterName
| sort by ObjectName asc
在第二行上,我們指定我們只關心 ObjectName、CounterValue 和 CounterName 資料行。 然後摘要說明依 CounterName 取得記錄計數,最後,嘗試根據 ObjectName 資料行以遞增順序來排序資料。 不幸的是,此查詢失敗,並出現錯誤(表示 ObjectName 未知),因為當我們摘要時,我們只在新數據表中包含 Count 和 CounterName 數據行。 若要避免此錯誤,我們可以將 ObjectName 新增至步驟summarize
結尾,如下所示:
Perf
| project ObjectName, CounterValue , CounterName
| summarize count() by CounterName, ObjectName
| sort by ObjectName asc
讀取您頭部中這一行的方式summarize
是:「依 CounterName 摘要記錄計數,以及依 ObjectName 分組」。您可以繼續將以逗號分隔的數據行加入語句結尾summarize
。
以上述範例為基礎,如果我們想要同時彙總多個資料行,可透過將彙總新增到 summarize
運算子 (以逗號分隔) 來達成此目的。 在下列範例中,我們不僅會取得所有記錄的計數,而且會取得所有記錄的 CounterValue 數據行值總和(符合查詢中的任何篩選條件):
Perf
| project ObjectName, CounterValue , CounterName
| summarize count(), sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc
重新命名彙總資料行
此時似乎是討論這些彙總資料行的資料行名稱的好時機。 在本節開始時,我們表示 summarize
運算符會採用數據表併產生新的數據表,而且只有您在 語句中指定的 summarize
數據行會繼續向下管線。 因此,如果您要執行上述範例,彙總的結果資料行會是 count_ 和 sum_CounterValue。
Kusto 引擎會自動建立資料行名稱,而不需要我們明確,但通常,您會發現您偏好新數據行具有更易記的名稱。 您可以透過指定新名稱,後面接著 summarize
和彙總,輕鬆地在 =
陳述式中將資料行重新命名,如下所示:
Perf
| project ObjectName, CounterValue , CounterName
| summarize Count = count(), CounterSum = sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc
現在,我們的摘要數據行會命名為 Count 和 CounterSum。
操作員比這裡所能涵蓋的還要多 summarize
,但您應該投入時間來瞭解它,因為這是您計劃對 Sentinel 數據 Microsoft 執行之任何數據分析的關鍵元件。
彙總參考
有許多彙總函式,但其中一些最常使用的函式是 sum()
、count()
和 avg()
。 以下是部分清單 (請參閱完整清單):
彙總函數
函式 | 描述 |
---|---|
arg_max() |
當引數最大化時,傳回一或多個運算式 |
arg_min() |
當引數最小化時,傳回一或多個運算式 |
avg() |
傳回整個群組的平均值 |
buildschema() |
傳回容許動態輸入的所有值的最小結構描述 |
count() |
傳回群組的計數 |
countif() |
傳回包含群組述詞的計數 |
dcount() |
傳回群組元素的近似相異計數 |
make_bag() |
傳回群組內動態值的屬性包。 |
make_list() |
傳回群組內所有值的清單 |
make_set() |
傳回群組內的一組相異值 |
max() |
傳回整個群組的最大值 |
min() |
傳回整個群組的最小值 |
percentiles() |
傳回群組的百分位數近似值 |
stdev() |
傳回整個群組的標準差 |
sum() |
傳回群組內元素的總和 |
take_any() |
傳回群組的隨機無空值 |
variance() |
傳回整個群組的變異數 |
選取:新增和移除資料行
當您開始使用查詢時,可能會發現您擁有的資訊比您主旨所需的信息還要多(也就是數據表中的數據行太多)。 或者,您可能需要比您擁有的更多資訊(也就是說,您需要新增包含其他數據行分析結果的數據行)。 讓我們看看一些用於進行資料行操作的關鍵運算子。
Project 和 project-away
Project 大致上相當於許多語言的 select 陳述式。 其允許您選擇要保留的資料行。 傳回的數據行順序符合您在語句中 project
列出之數據行的順序,如下列範例所示:
Perf
| project ObjectName, CounterValue, CounterName
如您所想像,當您使用寬數據集時,您可能會有許多想要保留的數據行,並以名稱指定全部數據行需要大量輸入。 針對那些情況,您可以使用 project-away,讓您能夠指定要移除的資料行,而非要保留的資料行,如下所示:
Perf
| project-away MG, _ResourceId, Type
提示
在查詢內的兩個位置中使用 project
(開頭一次且結尾再一次),這非常有用。 在查詢早期使用 project
,可透過移除您不需沿著管線傳遞的大型資料區塊,來協助改善效能。 在結尾再次使用它,可讓您移除可能已在先前步驟中建立,但最終輸出中不需要的任何資料行。
擴充
Extend 可用來建立新的導出資料行。 當您想要對現有資料行執行計算,並查看每個資料列的輸出時,這非常有用。 讓我們看一個簡單範例,我們在其中計算名為 Kbytes 的新資料行,並將 MB 值 (在現有 Quantity 資料行中) 乘以 1,024 來計算。
Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| project DataType, MBytes=Quantity, KBytes
在 project
陳述式的最後一行,將 Quantity 資料行重新命名為 Mbytes,因此,可輕鬆地分辨與每個資料行相關的量值單位。
值得注意的是,extend
也適用於已經導出的資料行。 例如,我們可以多新增一個名為 Bytes 的資料行 (從 Kbytes 導出):
Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| extend Bytes = KBytes * 1024
| project DataType, MBytes=Quantity, KBytes, Bytes
聯結資料表
您在Microsoft Sentinel 中的大部分工作都可以使用單一記錄類型來執行,但有時候您會想要將數據相互關聯,或對另一組數據執行查閱。 就像大多數查詢語言一樣,Kusto 查詢語言提供一些用來執行各種聯結類型的運算子。 在本節中,我們將探討最常使用的運算子 union
和 join
。
Union
Union 只會取得兩個或以上的資料表並傳回所有資料列。 例如:
OfficeActivity
| union SecurityEvent
這會從 OfficeActivity 和 SecurityEvent 資料表傳回所有資料列。 Union
提供一些參數,以用來調整集合聯集的行為。 其中兩個最實用的是 withsource 和 kind:
OfficeActivity
| union withsource = SourceTable kind = inner SecurityEvent
withsource 參數可讓您指定新數據行的名稱,該數據行在指定數據列中的值是數據列的來源數據表名稱。 在此範例中,我們會命名為SourceTable數據行,並根據數據列,此值為 OfficeActivity 或 SecurityEvent。
我們指定的另一個參數是 kind,其有兩個選項:inner 或 outer。 在此範例中,我們指定 了 inner,這表示聯集期間保留的唯一數據行是存在於這兩個數據表中的數據行。 或者,如果指定了 outer (這是預設值),則會傳回這兩個資料表的所有資料行。
聯結
聯結 的運作方式類似於 union
,除了聯結數據表來建立新的數據表之外,我們會聯 結數據列 來建立新的數據表。 就像大多數資料庫語言一樣,您可以執行的聯結類型有很多種。 join
的一般語法如下:
T1
| join kind = <join type>
(
T2
) on $left.<T1Column> == $right.<T2Column>
在 join
運算子之後,我們指定了想要執行的聯結 kind,後面接著左括弧。 在括弧內,指定您要聯結的數據表,以及您想要加入之數據表上的任何其他查詢語句。 在右括弧後面,我們使用 on 關鍵字,後面接著左側 ($left.<columnName> 關鍵字) 和右側 ($right.<columnName>) 資料行 (以 == 運算子分隔)。 以下為 inner join 的範例:
OfficeActivity
| where TimeGenerated >= ago(1d)
and LogonUserSid != ''
| join kind = inner (
SecurityEvent
| where TimeGenerated >= ago(1d)
and SubjectUserSid != ''
) on $left.LogonUserSid == $right.SubjectUserSid
注意
如果這兩個資料表對於您執行聯結所在的資料行具有相同名稱,則不需使用 $left 和 $right;您可以改為只指定資料行名稱。 不過,使用 $left 和 $right 更為明確,且通常會視為良好的做法。
如需參考,下表顯示可用的聯結類型清單。
聯結類型
加入類型 | 描述 |
---|---|
inner |
針對這兩個資料表中相符資料列的每個組合,各傳回一個。 |
innerunique |
從左側資料表傳回的資料列,在右側資料表中具有相符項的連結欄位中具有相異值。 這是預設未指定的聯結類型。 |
leftsemi |
從左側資料表中傳回在右側資料表中具有相符項的所有記錄。 只會傳回左數據表中的數據行。 |
rightsemi |
從右側資料表中傳回在左側資料表中具有相符項的所有記錄。 只會傳回來自右數據表的數據行。 |
leftanti /leftantisemi |
從左側資料表中傳回在右側資料表中不具相符項的所有記錄。 只會傳回左數據表中的數據行。 |
rightanti /rightantisemi |
從右側資料表中傳回在左側資料表中不具相符項的所有記錄。 只會傳回來自右數據表的數據行。 |
leftouter |
傳回左側資料表的所有記錄。 對於右數據表中沒有相符的記錄,單元格值為 null。 |
rightouter |
傳回右側資料表的所有記錄。 對於左數據表中沒有相符的記錄,單元格值為 Null。 |
fullouter |
傳回左側和右側資料表的所有記錄,而不論是否相符。 不相符的值為 Null。 |
提示
最佳做法是讓最小的資料表位於左側。 在某些情況下,根據您執行的聯結類型及資料表大小而定,遵循此規則可為您帶來巨大的效能優勢。
評估
您可能會記得,回到 第一個範例中,我們在其中一行上看到了 評估 運算符。 比起我們先前接觸的運算子,evaluate
運算子較不常使用。 不過,evaluate
運算子的運作方式很值得您花時間來了解。 再一次,以下是第一個查詢,您可以在第二行看到 evaluate
該查詢。
SigninLogs
| evaluate bag_unpack(LocationDetails)
| where RiskLevelDuringSignIn == 'none'
and TimeGenerated >= ago(7d)
| summarize Count = count() by city
| sort by Count desc
| take 5
此運算子可讓您叫用可用的外掛程式(內建函式)。 這其中許多外掛程式均著重於資料科學,例如 autocluster、diffpatterns 及 sequence_detect,可讓您執行進階分析,並探索統計異常和極端值。
此範例中使用的外掛程式稱為 bag_unpack,它可讓您輕鬆地擷取動態數據區塊,並將其轉換成數據行。 請記住, 動態數據 是類似 JSON 的數據類型,如下列範例所示:
{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}
在此案例中,我們想要依 city 摘要資料,但 city 會包含在 LocationDetails 資料行內作為屬性。 若要在查詢中使用 city 屬性,必須先使用 bag_unpack 來將其轉換成資料行。
回到原始管線步驟,我們看到了下列內容:
Get Data | Filter | Summarize | Sort | Select
既然我們已考慮 evaluate
運算子,我們可以看到它代表管線中的新階段,現在看起來像這樣:
Get Data |
Parse
| Filter | Summarize | Sort | Select
還有其他許多運算符和函式範例,可用來將數據源剖析為更容易閱讀且易讀的格式。 您可以在完整文件和活頁簿中了解他們以及 Kusto 查詢語言的其餘部分。
let 陳述式
既然我們介紹了許多主要運算子和資料類型,讓我們以 let 陳述式來總結,這是讓您的查詢更容易讀取、編輯及維護的絕佳方式。
Let 可讓您建立並設定變數,或將名稱指派給運算式。 此運算式可以是單一值,但也可能是整個查詢。 以下是簡單的範例:
let aWeekAgo = ago(7d);
SigninLogs
| where TimeGenerated >= aWeekAgo
在這裡,我們指定了 aWeekAgo 的名稱,並將它設定為等於 timespan 函式的輸出,這會傳回 datetime 值。 然後,以分號終止 let 陳述式。 現在,有一個名為 aWeekAgo 的新變數,可在查詢中的任何位置使用。
如前所述,您可以使用 let 語句來取得整個查詢,並提供結果名稱。 由於查詢結果 (是表格式運算式) 可用來作為查詢的輸入,因此,您可以將此具名結果視為資料表,以便在其上執行另一個查詢。 以下是稍微修改過先前範例的內容:
let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins
在此案例中,我們建立了第二個 let 陳述式,並將整個查詢包裝成名為 getSignins 的新變數。 就像之前一樣,我們會以分號終止第二個 let 陳述式。 然後,我們會在執行查詢的最後一行上呼叫 變數。 請注意,我們能夠在第二個 let 陳述式中使用 aWeekAgo。 這是因為我們在上一行指定了它;如果要交換 let 陳述式,以便讓 getSignins 先出現,就會收到錯誤。
現在,可以使用 getSignins 作為另一個查詢的基礎 (在相同視窗中):
let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins
| where level >= 3
| project IPAddress, UserDisplayName, Level
Let 陳述式可讓您以更強大且具彈性的方式協助組織查詢。 Let 可以定義純量和表格式值,以及建立使用者定義的函式。 當您組織可能執行多個聯結的更複雜的查詢時,它們確實會派上用場。
下一步
雖然本文只涵蓋基本概念,但您現在已有必要的基礎,我們已涵蓋最常用來完成Microsoft Sentinel 工作的元件。
適用於 Microsoft Sentinel 的進階 KQL 活頁簿
利用 Microsoft Sentinel 本身的 Kusto 查詢語言活頁簿:適用於 Microsoft Sentinel 的進階 KQL 活頁簿。 它為您提供在日常安全性作業期間可能遇到之許多情況的逐步說明和範例,同時也指出許多現成可用之分析規則、活頁簿、搜捕規則的範例,以及使用 Kusto 查詢的更多元素。 從 Sentinel Microsoft 的 [活頁簿] 頁面啟動此活頁簿。
進階 KQL Framework 活頁簿 - 讓您成為精通 KQL 的人 \(英文\) 是一篇出色的部落格文章,可為您說明如何使用此活頁簿。
更多資源
請參閱這個學習、定型及技能資源的集合,以擴大並強化您對 Kusto 查詢語言的知識。