关于 azure-kusto-irql-graph
此技能将现有 KQL 或 IRQL 表格结果映射为图,用于在 Kusto Explorer 中可视化、折叠、提取或丰富节点。它面向已有查询结果的 Kusto 用户,不负责把一般自然语言转换为查询。
主要功能
- 01用 Lift_To_Graph 映射表格结果
- 02通过 Graph_Render_View 渲染图
- 03按属性折叠节点并重连边
- 04提取节点属性或丰富图数据
适用场景
- 01把认证事件查询结果绘制为关系图
- 02按共享属性合并节点
- 03为节点添加提取或关联信息
MCP 相关
此技能通过 Azure MCP Server 的 `kusto_query` 工具运行 KQL,并使用 Kusto 数据库中预先部署的图函数。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ azure-skills --skill azure-kusto-irql-graph安装后在 Claude Code 中输入/azure-kusto-irql-graph确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/DEPLOY_IRQL_FUNCTIONS.mdEXAMPLES.mdKUSTO_EXPLORER_LAUNCH.md详细介绍
IRQL 图函数——将查询结果转换为可视化图
将 IRQL 图函数系列应用于表格结果。根据 KQL 或 IRQL 查询以及用户对图的描述,生成 Lift_To_Graph 映射,并仅组合在 Kusto Explorer 中可视化、折叠、提取或丰富图所需的已存储图函数。源查询不需要使用 IRQL。
范围与路由
| 请求 | 使用 |
|---|---|
| 将提供的 KQL/IRQL 行转换为带图标的可视化图 | 本技能:Lift_To_Graph + Graph_Render_View |
折叠节点,或应用 Extract_Node_*、Enrich_Node_* 或 Enrich_Graph_* | 本技能 |
使用 make-graph、graph-match、最短路径、连通分量、图模型或快照 | azure-kusto-graph |
| 根据自然语言编写非简单的 KQL/IRQL 调查查询 | Kusto 或 IRQL 查询生成技能,然后使用本技能 |
如果请求同时涉及可视化和原生图分析,请使用本技能完成提升/渲染部分,并使用 azure-kusto-graph 处理运算符语义。除非用户要求使用原生图运算符,否则不要用手动构建的边优先图替代图提升函数。
输入约定
- 首选输入:一个可运行且能生成表格结果的 KQL/IRQL 查询,以及对所需节点、边、标签、图标、提取、丰富或折叠方式的自然语言描述。
- 本技能不是自然语言转 KQL 或自然语言转 IRQL 转换器。它会将现有查询结果转换为图可视化。一般性的自然语言转 KQL 或自然语言转 IRQL 转换,请使用专用的查询生成技能(另行提供)。
- 保留所提供查询中的检索、联接、筛选和聚合。仅添加图映射所需的投影或合成 ID。
- 仅当基本的自然语言数据源请求可直接映射到一个已知表或 IRQL
Get_*选择器,且列明显、筛选简单时,才支持此类请求。请说明假定的数据源,不要臆造联接、架构或调查逻辑。 - 对于非简单的查询构建,请先使用单独的 Kusto/IRQL 查询生成技能,再将其输出交由本技能处理。
- 如果没有查询或输出架构,且数据源并非简单情况,请在生成映射前请求用户提供 KQL 查询或其结果列。
激活条件
在以下情况下使用本技能:
- 用户提供 KQL/IRQL 结果,并要求生成 IRQL 图可视化或映射
- 用户提到
Lift_To_Graph、Graph_Render_View或Graph_Fold_By_Property - 用户要求在 Kusto Explorer 中生成带图标的节点/边映射
- 用户希望按共有属性折叠/收起节点
- 用户要求通过
Extract_Node_*、Enrich_Node_*或Enrich_Graph_*提取或丰富图
不要仅因用户提到 graph-match、图路径/连通分量、持久化图或通用 make-graph 构建而激活本技能;这些属于 azure-kusto-graph。
这不是自然语言转 KQL/IRQL 转换器。 输入通常应为一个可运行的 KQL 或 IRQL 查询,其结果需要转换为图可视化。仅对简单的单表/选择器情况支持基本的自然语言数据源请求。对于一般性的自然语言转 KQL 或自然语言转 IRQL,请使用专用的查询生成技能(另行提供)。
环境
- 集群:
https://kc7001.eastus.kusto.windows.net - 数据库:
ValdyTimes、JoJosHospital(已预先部署图函数) - 渲染:Kusto Explorer 桌面应用(make-graph 可视化窗口)
- 工具:
kusto_query(通过 Azure MCP Server)
函数预检查
Lift_To_Graph 和 Graph_Render_View 是存储函数,而非 Kusto 内置运算符。在针对目标数据库生成或运行提升管道之前,请检查已部署的函数:
.show functions
| where Name in~ ("Lift_To_Graph", "Graph_Render_View", "Graph_Fold_By_Property")
| project Name
- 必须有
Lift_To_Graph和Graph_Render_View。 - 仅在请求折叠时才需要
Graph_Fold_By_Property。 - 使用任何
Extract_Node_*、Enrich_Node_*或Enrich_Graph_*函数前,请先检查该函数;如果函数不可用,则省略可选的丰富操作,除非用户希望部署该函数。 - 如果缺少必需函数,且你有权限修改数据库,请先征求用户确认,再进行部署。然后使用 references/DEPLOY_IRQL_FUNCTIONS.md 中的
.create-or-alter function定义。运行相关的.create-or-alter代码块,然后重新运行预检查以确认。 - 如果你没有修改权限,请告知用户缺少哪些函数,并指引他们参阅
references/DEPLOY_IRQL_FUNCTIONS.md进行手动部署。
IRQL 图函数系列
Lift_To_Graph(T, mappingJson)
将任意表格 KQL 结果转换为统一的节点和边表。
输入:任意表格 T 和一个 JSON 映射字符串。
输出:EntityType 为 "node" 或 "edge" 的行,可直接用于 make-graph。
Graph_Render_View(T)
接收 Lift_To_Graph 的输出,拆分节点和边,并调用 make-graph 打开 Kusto Explorer 的图窗口。
Graph_Fold_By_Property(T, NodeType, PropertyName)
将具有相同属性值的指定类型节点合并为一个节点,并自动重新连接边。
图提取和丰富函数
这些是其他存储函数,必须已部署在目标数据库中。它们未包含在 references/DEPLOY_IRQL_FUNCTIONS.md 中。将其纳入管道前,请使用 .show functions 确认它们可用。
| 函数 | 操作 | 关键属性 |
|---|---|---|
Extract_Node_Email_Sender_Domain(T, displayName) | 将 Domain 添加到节点属性中 | EmailSender |
Extract_Node_Employee_Firstname(T, displayName) | 将 Firstname 添加到节点属性中 | Name |
Extract_Node_Event_Network_Domain(T, displayName) | 将 DomainName 添加到节点属性中 | Url |
Enrich_Node_Ip_Employee(T, displayName) | 将员工信息添加到 IP 节点 | ClientIp |
Enrich_Node_Username_Employee(T, displayName) | 将员工信息添加到用户节点 | Username |
Enrich_Node_Event_Authentication_Username(T, displayName) | 添加身份验证上下文 | Username |
Enrich_Node_Ip_Domain(T, displayName) | 添加 DNS 域名 | ClientIp |
Enrich_Node_Ip_Event_NetworkOutbound(T, displayName) | 添加出站事件 | ClientIp |
Enrich_Graph_Ip_Employee(T, mappingJson) | 使用员工节点扩展图 | ClientIp |
Enrich_Graph_Username_Employee(T, mappingJson) | 使用员工节点扩展图 | Username |
Enrich_Graph_Event_Authentication_Username(T, mappingJson) | 使用身份验证节点扩展图 | Username |
映射 JSON 架构
JSON 映射包含两个数组:node_types 和 edges。
node_types[]
| 字段 | 必需 | 描述 |
|---|---|---|
type | 是 | 节点类型标签(例如 "User"、"Host"、"IP") |
id | 是 | 节点 ID 前缀,通常与类型相同 |
key | 是 | 值将成为节点身份标识的列名 |
props | 是 | 要作为节点属性携带的列数组 |
defaults | 否 | 用于空属性的回退值对象 |
defIcon | 否 | 此节点类型的默认图标 URL |
displayName | 否 | 用作显示标签的列(默认为 id) |
color | 否 | 用于提供颜色的列 |
size | 否 | 用于提供大小的列 |
edges[]
| 字段 | 必填 | 描述 |
|---|---|---|
type | 是 | 边类型标签(例如 "AuthenticatesTo"、"SentEmail") |
source | 是 | {"id": "<prefix>", "type": "<NodeType>"} |
target | 是 | {"id": "<prefix>", "type": "<NodeType>"} |
props | 否 | 用作边属性的列数组 |
displayName | 否 | 用作边标签的列 |
color | 否 | 用作边颜色的列 |
图标仓库
使用以下地址中的图标:https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/:
- IP:
Public-IP-Addresses-(Classic).svg - 主机/VM:
Virtual-Machine.svg - 用户:
Users.svg - 电子邮件:
Mailbox.svg(或azure-cds/command-1070-Mail.svg) - 进程:
App-Services.svg - 文件:
Storage-Accounts.svg - 警报:
Activity-Log.svg - 域:
DNS-Zones.svg
映射生成规则
根据提供的查询列和用户的图描述,按以下规则生成映射 JSON:
- 识别实体 -> 每个不同的名词都成为一个
node_type - 识别关系 -> 每个动词/介词都成为一条
edge - 映射到列 -> 使用所提供查询实际生成的列;切勿假设存在不可用的列
- 设置方向 -> 源是动作的发出者,目标是动作的承受者
- 添加属性 -> 包含与调查相关的列(时间戳、结果、哈希)
- 分配图标 -> 根据实体类型从上述图标集中选择
列参考(IRQL 统一架构)
| 实体 | 键列 | 可用属性 |
|---|---|---|
| 用户 | Username | Username、Name、Role、Email |
| 主机 | Hostname | Hostname |
| IP | ClientIp | ClientIp |
| 电子邮件 | Subject | EnvTime、Subject、Verdict、Url |
| 发件人 | EmailSender | EmailSender、Domain |
| 收件人 | EmailRecipient | EmailRecipient |
| 进程 | ProcessName | EnvTime、ProcessName、ProcessCommandLine、ProcessHash |
| 文件 | Filename | EnvTime、Filename、Path、Sha256 |
| 域 | DomainName | DomainName |
| 身份验证事件 | (合成 ID) | EnvTime、UserAgent、Result、Description |
函数选择
- 从提供的 KQL/IRQL 表格管道开始。
- 使用
Lift_To_Graph(mapping)创建图实体。 - 仅在用户要求且与映射键兼容时,添加
Extract_Node_*、Enrich_Node_*或Enrich_Graph_*。 - 仅在用户要求分组/折叠时,添加
Graph_Fold_By_Property()。 - 以
Graph_Render_View()结束可视化输出。 - 对所选管道中准确存储的函数进行预检。
管道模式
// 1. Preserve the supplied KQL or IRQL query
<input query>
// 2. Lift to graph
| invoke Lift_To_Graph(<mapping_json>)
// 3. Optionally extract or enrich graph entities
| invoke <Extract_Node_* | Enrich_Node_* | Enrich_Graph_*>()
// 4. Optionally fold nodes when requested
| invoke Graph_Fold_By_Property("<NodeType>", "<PropertyName>")
// 5. Render
| invoke Graph_Render_View()
示例
更多提示词和完整示例,请参阅 references/EXAMPLES.md。
身份验证图:IP -> AuthEvent -> 用户 -> 主机
输入查询:Get_Event_Authentication_All | where Result == "Failed Login" | take 200
图请求:“显示 IP、身份验证事件、用户和主机;按结果折叠事件。”
let auth_mapping = '{"node_types":[{"type":"SrcIp","id":"SrcIp","key":"ClientIp","props":["ClientIp"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Public-IP-Addresses-(Classic).svg"},{"type":"Host","id":"Host","key":"Hostname","props":["Hostname"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Virtual-Machine.svg"},{"type":"User","id":"User","key":"Username","props":["Username"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Users.svg"},{"type":"AuthEvent","id":"AuthEvent","key":"AuthEventId","props":["AuthEventId","EnvTime","UserAgent","Result","Description"],"defaults":{"Result":"unknown"},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Activity-Log.svg"}],"edges":[{"type":"RequestsAuth","source":{"id":"SrcIp","type":"SrcIp"},"target":{"id":"AuthEvent","type":"AuthEvent"},"props":["EnvTime"]},{"type":"TargetsUser","source":{"id":"AuthEvent","type":"AuthEvent"},"target":{"id":"User","type":"User"},"props":["EnvTime"]},{"type":"AgainstHost","source":{"id":"AuthEvent","type":"AuthEvent"},"target":{"id":"Host","type":"Host"},"props":["EnvTime"]}]}';
Get_Event_Authentication_All
| extend AuthEventId = strcat(Username, "_", Hostname, "_", EnvTime)
| where Result == "Failed Login"
| take 200
| invoke Lift_To_Graph(auth_mapping)
| invoke Graph_Fold_By_Property("AuthEvent", "Result")
| invoke Graph_Render_View()
电子邮件图:发件人 -> 邮件 -> 收件人
输入查询:Get_Email_All | take 400
图请求:“可视化发件人到邮件再到收件人的流转,并按判定结果折叠邮件。”
let mail_mapping = '{"node_types":[{"type":"EmailMessage","id":"Message","key":"Subject","props":["EnvTime","Subject","Verdict"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Media-File.svg"},{"type":"Sender","id":"Email","key":"EmailSender","props":["EmailSender"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-cds/command-1070-Mail.svg"},{"type":"Recipient","id":"Email","key":"EmailRecipient","props":["EmailRecipient"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-cds/command-1070-Mail.svg"}],"edges":[{"type":"SentBy","source":{"id":"Message","type":"EmailMessage"},"target":{"id":"Email","type":"Sender"},"props":["EnvTime","Verdict"]},{"type":"DeliveredTo","source":{"id":"Message","type":"EmailMessage"},"target":{"id":"Email","type":"Recipient"},"props":["EnvTime","Verdict"]}]}';
Get_Email_All
| take 400
| invoke Lift_To_Graph(mail_mapping)
| invoke Graph_Fold_By_Property("EmailMessage", "Verdict")
| invoke Graph_Render_View()
可疑域名调查(端到端)
基本数据源请求:“使用这些可疑域名的出站网络事件,绘制 IP 到域名的连接图,并通过员工姓名丰富图数据。”
这是有限的回退方案:一个已知选择器、一个提取器和一个直接筛选条件。
let suspicious_domain_mapping = '{"node_types":[{"type":"IP","id":"IP","key":"ClientIp","props":["ClientIp"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Public-IP-Addresses-(Classic).svg"},{"type":"Domain","id":"Domain","key":"DomainName","props":["DomainName"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/DNS-Zones.svg"}],"edges":[{"type":"ConnectsTo","source":{"id":"IP","type":"IP"},"target":{"id":"Domain","type":"Domain"},"props":["EnvTime"]}]}';
Get_Event_NetworkOutbound
| invoke Extract_Event_Network_Domain()
| where DomainName has_any ("raisinkanes.com", "nothing-to-see-here.net", "totally-legit-domain.com")
| invoke Lift_To_Graph(suspicious_domain_mapping)
| invoke Enrich_Node_Ip_Employee("Name")
| invoke Graph_Fold_By_Property("Domain", "DomainName")
| invoke Graph_Render_View()
进程执行图:用户 -> 进程 -> ParentProcess
输入查询:Get_Event_Process_All | where ProcessCommandLine has "powershell" | take 300
图请求:“可视化进程、父进程、主机和用户之间的关系。”
let proc_mapping = '{"node_types":[{"type":"Process","id":"Proc","key":"ProcessName","props":["ProcessName","ProcessCommandLine","ProcessHash"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/App-Services.svg"},{"type":"ParentProcess","id":"Proc","key":"ParentProcessName","props":["ParentProcessName","ParentProcessHash"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/App-Services.svg"},{"type":"Host","id":"Host","key":"Hostname","props":["Hostname"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Virtual-Machine.svg"},{"type":"User","id":"User","key":"Username","props":["Username"],"defaults":{},"defIcon":"https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/Users.svg"}],"edges":[{"type":"SpawnedBy","source":{"id":"Proc","type":"Process"},"target":{"id":"Proc","type":"ParentProcess"},"props":["EnvTime"]},{"type":"RanOn","source":{"id":"Proc","type":"Process"},"target":{"id":"Host","type":"Host"},"props":["EnvTime"]},{"type":"ExecutedBy","source":{"id":"Proc","type":"Process"},"target":{"id":"User","type":"User"},"props":["EnvTime"]}]}';
Get_Event_Process_All
| where ProcessCommandLine has "powershell"
| take 300
| invoke Lift_To_Graph(proc_mapping)
| invoke Graph_Render_View()
查询结果 -> 映射转换
当用户提供查询并描述图时:
- 检查查询的最终输出列
- 解析实体名词和关系动词
- 仅使用这些列生成映射 JSON
- 保留提供的管道,并追加
Lift_To_Graph() - 在末尾包含
Graph_Render_View() - 如果用户提到分组/折叠,且该函数存在,则添加
Graph_Fold_By_Property()
在必需函数预检通过后,输出完整的 KQL —— 即用户提供的查询,以及作为字符串 let 绑定内联的映射 JSON。如果无法检查目标数据库,请明确标记未经验证的函数依赖项。
在 Kusto Explorer 中打开查询(仅限 Windows)
可选的便利功能。 默认工作流是在聊天中输出 KQL,让用户手动将其复制到 Kusto Explorer 或 VS Code Kusto 扩展中。仅在用户选择启用时自动启动。
始终在聊天回复中输出完整的 KQL 查询,并清楚标注步骤 1(连接)和步骤 2(查询):
// Step 1: Connect to your cluster (skip if already connected)
// Example: uncomment to connect to the KC7 training cluster
// #connect cluster('kc7001.eastus.kusto.windows.net').database('ValdyTimes')
// Or replace with your own cluster:
// #connect cluster('<YOUR_CLUSTER>').database('<YOUR_DATABASE>')
// Step 2: Run the query below
<KQL_QUERY>
如果用户要求保存或在 Kusto Explorer 中打开,请遵循 references/KUSTO_EXPLORER_LAUNCH.md 中的流程。关键规则:
- 写入文件或启动可执行文件前,使用
ask_user确认 - 在打开文件前,在聊天中显示文件内容,供用户检查
- 绝不使用 shell 插值或 here-string;通过
Set-Content/Add-Content写入文件 - 绝不将查询编码到浏览器 URL 中
- 在 macOS/Linux 上,保存
.kql文件,并建议使用 VS Code Kusto 扩展或 ADX Web Explorer