Fonctions graphiques IRQL -- Résultats de requête vers visualisation
Appliquez la famille de fonctions graphiques IRQL aux résultats tabulaires. À partir d'une requête KQL ou IRQL et de la description graphique de l'utilisateur, générez un mapping Lift_To_Graph et composez uniquement les fonctions graphiques stockées nécessaires pour visualiser, replier, extraire ou enrichir le graphe dans Kusto Explorer. La requête source ne doit pas nécessairement utiliser IRQL.
Portée et routage
| Demande | Utilisation |
|---|---|
| Transformer les lignes KQL/IRQL fournies en un graphe visuel décoré d'icônes | Cette compétence : Lift_To_Graph + Graph_Render_View |
Replier des nœuds ou appliquer Extract_Node_*, Enrich_Node_*, ou Enrich_Graph_* |
Cette compétence |
Utiliser make-graph, graph-match, chemins les plus courts, composantes connexes, modèles de graphe ou instantanés |
azure-kusto-graph |
| Créer une investigation KQL/IRQL non triviale à partir du langage naturel | Une compétence de génération de requête Kusto ou IRQL, puis cette compétence |
Si une demande mélange visualisation et analyse native de graphe, utilisez cette compétence pour la portion lift/render et azure-kusto-graph pour la sémantique des opérateurs. Ne remplacez pas les fonctions graph-lift par un graphe construit manuellement arêtes-d'abord, sauf si l'utilisateur demande des opérateurs graphiques natifs.
Contrat d'entrée
- Entrée préférée : une requête KQL/IRQL fonctionnelle produisant des résultats tabulaires, plus une description en langage naturel des nœuds, arêtes, libellés, icônes, extraits, enrichissements ou replis souhaités.
- Cette compétence n'est pas un convertisseur langage naturel-vers-KQL ou NL-vers-IRQL. Elle transforme les résultats de requête existants en visualisations graphiques. Pour la conversion générale NL-vers-KQL ou NL-vers-IRQL, utilisez une compétence de génération de requête dédiée (disponible séparément).
- Préservez la récupération, les jointures, les filtres et les agrégations de la requête fournie. N'ajoutez que les projections ou identifiants synthétiques requis par le mapping graphique.
- Une demande source en langage naturel basique est supportée uniquement quand elle correspond directement à une table connue ou à un sélecteur IRQL
Get_*avec colonnes évidentes et filtres simples. Indiquez la source supposée et n'inventez pas de jointures, schémas ou logiques d'investigation. - Pour la construction de requêtes non triviales, utilisez d'abord une compétence de génération de requête Kusto/IRQL séparée, puis appliquez cette compétence à sa sortie.
- Si aucune requête ou schéma de sortie n'est disponible et la source n'est pas triviale, demandez la requête KQL ou ses colonnes de résultats avant de générer un mapping.
Déclencheurs d'activation
Utilisez cette compétence quand l'utilisateur :
- Fournit des résultats KQL/IRQL et demande une visualisation ou un mapping de graphe IRQL
- Mentionne
Lift_To_Graph,Graph_Render_View, ouGraph_Fold_By_Property - Demande des mappings nœud/arête décorés d'icônes dans Kusto Explorer
- Souhaite replier/réduire des nœuds par une propriété partagée
- Demande une extraction ou enrichissement graphique via
Extract_Node_*,Enrich_Node_*, ouEnrich_Graph_*
N'activez pas cette compétence uniquement pour graph-match, chemins/composantes graphe, graphes persistants, ou construction générique make-graph ; ceux-ci relèvent de azure-kusto-graph.
N'est pas un convertisseur langage naturel-vers-KQL/IRQL. L'entrée devrait généralement être une requête KQL ou IRQL fonctionnelle dont les résultats nécessitent une visualisation graphe. Les demandes source NL basiques fonctionnent uniquement pour les cas triviales table-unique/sélecteur-unique. Pour NL-vers-KQL ou NL-vers-IRQL général, utilisez une compétence de génération de requête dédiée (disponible séparément).
Environnement
- Cluster :
https://kc7001.eastus.kusto.windows.net - Bases de données :
ValdyTimes,JoJosHospital(fonctions graphiques pré-déployées) - Rendu : application de bureau Kusto Explorer (fenêtre de visualisation make-graph)
- Outil :
kusto_query(via serveur Azure MCP)
Vérification préalable des fonctions
Lift_To_Graph et Graph_Render_View sont des fonctions stockées, pas des opérateurs Kusto intégrés. Avant de générer ou exécuter un pipeline de lift contre une base de données cible, vérifiez ce qui est déployé :
.show functions
| where Name in~ ("Lift_To_Graph", "Graph_Render_View", "Graph_Fold_By_Property")
| project Name
Lift_To_GraphetGraph_Render_Viewsont obligatoires.Graph_Fold_By_Propertyest obligatoire uniquement quand un repli est demandé.- Vérifiez toute fonction
Extract_Node_*,Enrich_Node_*, ouEnrich_Graph_*avant de l'utiliser ; omettez les enrichissements optionnels quand ils ne sont pas disponibles, sauf si l'utilisateur souhaite les déployer. - Si une fonction requise manque et que vous avez la permission de modifier la base de données, demandez la confirmation de l'utilisateur avant le déploiement. Utilisez ensuite les définitions
.create-or-alter functiondans references/DEPLOY_IRQL_FUNCTIONS.md. Exécutez le bloc.create-or-alterpertinent, puis réexécutez la vérification préalable pour confirmer. - Si vous n'avez pas les permissions de modification, dites à l'utilisateur quelles fonctions manquent et dirigez-le vers
references/DEPLOY_IRQL_FUNCTIONS.mdpour le déploiement manuel.
Famille de fonctions graphiques IRQL
Lift_To_Graph(T, mappingJson)
Transforme tout résultat KQL tabulaire en table nœud + arête unifiée.
Entrée : toute table T + une chaîne mapping JSON.
Sortie : lignes avec EntityType = "node" ou "edge", prêtes pour make-graph.
Graph_Render_View(T)
Prend la sortie Lift_To_Graph, divise nœuds/arêtes, et appelle make-graph pour ouvrir la fenêtre graphe de Kusto Explorer.
Graph_Fold_By_Property(T, NodeType, PropertyName)
Réduit les nœuds d'un type donné partageant une valeur de propriété en un nœud unique. Réoriente automatiquement les arêtes.
Fonctions d'extraction et d'enrichissement graphe
Ce sont des fonctions stockées supplémentaires qui doivent déjà être déployées sur la base de données cible. Elles ne sont pas incluses dans references/DEPLOY_IRQL_FUNCTIONS.md. Utilisez .show functions pour vérifier la disponibilité avant d'inclure dans un pipeline.
| Fonction | Opération | Propriété clé |
|---|---|---|
Extract_Node_Email_Sender_Domain(T, displayName) |
Ajoute Domain aux props de nœud |
EmailSender |
Extract_Node_Employee_Firstname(T, displayName) |
Ajoute Firstname aux props de nœud |
Name |
Extract_Node_Event_Network_Domain(T, displayName) |
Ajoute DomainName aux props de nœud |
Url |
Enrich_Node_Ip_Employee(T, displayName) |
Ajoute info employé aux nœuds IP | ClientIp |
Enrich_Node_Username_Employee(T, displayName) |
Ajoute info employé aux nœuds utilisateur | Username |
Enrich_Node_Event_Authentication_Username(T, displayName) |
Ajoute contexte auth | Username |
Enrich_Node_Ip_Domain(T, displayName) |
Ajoute domaines DNS | ClientIp |
Enrich_Node_Ip_Event_NetworkOutbound(T, displayName) |
Ajoute événements sortants | ClientIp |
Enrich_Graph_Ip_Employee(T, mappingJson) |
Expande graphe avec nœuds employé | ClientIp |
Enrich_Graph_Username_Employee(T, mappingJson) |
Expande graphe avec nœuds employé | Username |
Enrich_Graph_Event_Authentication_Username(T, mappingJson) |
Expande avec nœuds auth | Username |
Schéma JSON de mapping
Le mapping JSON contient deux tableaux : node_types et edges.
node_types[]
| Champ | Obligatoire | Description |
|---|---|---|
type |
Oui | Libellé de type de nœud (p. ex. "User", "Host", "IP") |
id |
Oui | Préfixe pour l'ID du nœud ; généralement identique au type |
key |
Oui | Nom de colonne dont la valeur devient l'identité du nœud |
props |
Oui | Tableau de colonnes à conserver comme propriétés de nœud |
defaults |
Non | Objet de valeurs de repli pour les propriétés nulles/vides |
defIcon |
Non | URL d'icône par défaut pour ce type de nœud |
displayName |
Non | Colonne à utiliser pour le libellé d'affichage (par défaut id) |
color |
Non | Colonne pour sourcer la couleur |
size |
Non | Colonne pour sourcer la taille |
edges[]
| Champ | Obligatoire | Description |
|---|---|---|
type |
Oui | Libellé de type d'arête (p. ex. "AuthenticatesTo", "SentEmail") |
source |
Oui | {"id": "<prefix>", "type": "<NodeType>"} |
target |
Oui | {"id": "<prefix>", "type": "<NodeType>"} |
props |
Non | Tableau de colonnes à conserver comme propriétés d'arête |
displayName |
Non | Colonne pour le libellé d'arête |
color |
Non | Colonne pour la couleur d'arête |
Dépôt d'icônes
Utilisez des icônes de https://raw.githubusercontent.com/benc-uk/icon-collection/master/azure-icons/ :
- IP :
Public-IP-Addresses-(Classic).svg - Host/VM :
Virtual-Machine.svg - User :
Users.svg - Email :
Mailbox.svg(ouazure-cds/command-1070-Mail.svg) - Process :
App-Services.svg - File :
Storage-Accounts.svg - Alert :
Activity-Log.svg - Domain :
DNS-Zones.svg
Règles de génération de mapping
À partir des colonnes de la requête fournie et de la description graphe de l'utilisateur, générez le mapping JSON par :
- Identifier les entités -> chaque substantif distinct devient un
node_type - Identifier les relations -> chaque verbe/préposition devient une
edge - Mapper aux colonnes -> utiliser les colonnes réelles produites par la requête fournie ; ne jamais supposer des colonnes indisponibles
- Définir la direction -> la source est l'acteur, la cible est l'objet de l'action
- Ajouter des propriétés -> inclure les colonnes pertinentes pour l'investigation (horodatages, résultats, hashes)
- Assigner les icônes -> choisir dans l'ensemble d'icônes ci-dessus basé sur le type d'entité
Référence de colonne (schéma unifié IRQL)
| Entité | Colonne clé | Props disponibles |
|---|---|---|
| User | Username |
Username, Name, Role, Email |
| Host | Hostname |
Hostname |
| IP | ClientIp |
ClientIp |
| Email Message | Subject |
EnvTime, Subject, Verdict, Url |
| Sender | EmailSender |
EmailSender, Domain |
| Recipient | EmailRecipient |
EmailRecipient |
| Process | ProcessName |
EnvTime, ProcessName, ProcessCommandLine, ProcessHash |
| File | Filename |
EnvTime, Filename, Path, Sha256 |
| Domain | DomainName |
DomainName |
| Auth Event | (ID synthétique) | EnvTime, UserAgent, Result, Description |
Sélection de fonction
- Commencez par le pipeline tabulaire KQL/IRQL fourni.
- Utilisez
Lift_To_Graph(mapping)pour créer des entités graphe. - Ajoutez
Extract_Node_*,Enrich_Node_*, ouEnrich_Graph_*seulement quand demandé et compatible avec les clés mappées. - Ajoutez
Graph_Fold_By_Property()seulement quand le groupage/réduction est demandé. - Terminez la sortie visuelle par
Graph_Render_View(). - Vérifiez les fonctions stockées exactes sélectionnées pour le pipeline.
Motif de pipeline
// 1. Préserver la requête KQL ou IRQL fournie
<input query>
// 2. Lift vers graphe
| invoke Lift_To_Graph(<mapping_json>)
// 3. Optionnellement extraire ou enrichir les entités graphe
| invoke <Extract_Node_* | Enrich_Node_* | Enrich_Graph_*>()
// 4. Optionnellement replier les nœuds quand demandé
| invoke Graph_Fold_By_Property("<NodeType>", "<PropertyName>")
// 5. Rendre
| invoke Graph_Render_View()
Exemples
Pour des prompts supplémentaires et des exemples travaillés, voir references/EXAMPLES.md.
Graphe d'authentification : IP -> AuthEvent -> User -> Host
Requête d'entrée : Get_Event_Authentication_All | where Result == "Failed Login" | take 200
Demande graphe : « Montrer les IPs, événements d'authentification, utilisateurs et hosts ; replier les événements par résultat. »
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()
Graphe d'email : Sender -> Message -> Recipient
Requête d'entrée : Get_Email_All | take 400
Demande graphe : « Visualiser le flux sender-vers-message-vers-recipient et replier les messages par verdict. »
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()
Investigation de domaine suspect (bout en bout)
Demande source basique : « Utiliser les événements réseau sortants pour ces domaines suspects et graphier les connexions IP-vers-domaine enrichies avec les noms d'employés. »
C'est le recours limité : un sélecteur connu, un extracteur, et un filtre direct.
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()
Graphe d'exécution de processus : User -> Process -> ParentProcess
Requête d'entrée : Get_Event_Process_All | where ProcessCommandLine has "powershell" | take 300
Demande graphe : « Visualiser les relations processus, processus parent, host et utilisateur. »
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()
Traduction des résultats de requête vers mapping
Quand l'utilisateur fournit une requête et décrit le graphe :
- Inspectez les colonnes de sortie finale de la requête
- Analysez les substantifs d'entité et verbes de relation
- Générez le mapping JSON en utilisant uniquement ces colonnes
- Préservez le pipeline fourni et ajoutez
Lift_To_Graph() - Incluez
Graph_Render_View()à la fin - Si l'utilisateur mentionne groupage/réduction et que la fonction existe, ajoutez
Graph_Fold_By_Property()
Produisez le KQL complet -- la requête fournie plus le mapping JSON inline en tant que binding let -- après que la vérification préalable des fonctions requises réussisse. Marquez clairement les dépendances de fonction non vérifiées quand la base de données cible ne peut pas être vérifiée.
Ouverture de requêtes dans Kusto Explorer (Windows uniquement)
Fonctionnalité de commodité optionnelle. Le flux de travail par défaut est de produire le KQL dans le chat et laisser l'utilisateur le copier dans Kusto Explorer ou l'extension Kusto VS Code manuellement. Le lancement automatique est opt-in uniquement.
Produisez toujours la requête KQL complète dans la réponse de chat avec l'étape 1 (connexion) et l'étape 2 (requête) clairement étiquetées :
// Étape 1 : Connectez-vous à votre cluster (ignorer si déjà connecté)
// Exemple : décommenter pour se connecter au cluster d'entraînement KC7
// #connect cluster('kc7001.eastus.kusto.windows.net').database('ValdyTimes')
// Ou remplacez par votre propre cluster :
// #connect cluster('<YOUR_CLUSTER>').database('<YOUR_DATABASE>')
// Étape 2 : Exécuter la requête ci-dessous
<KQL_QUERY>
Si l'utilisateur demande de sauvegarder ou ouvrir dans Kusto Explorer, suivez la procédure dans references/KUSTO_EXPLORER_LAUNCH.md. Règles clés :
- Utilisez
ask_userpour confirmer avant d'écrire des fichiers ou lancer des exécutables - Affichez le contenu des fichiers dans le chat pour que l'utilisateur puisse vérifier avant ouverture
- Ne jamais utiliser d'interpolation shell ou here-strings — écrire les fichiers via
Set-Content/Add-Content - Ne jamais encoder les requêtes dans les URLs de navigateur
- Sur macOS/Linux, sauvegardez le fichier
.kqlet suggérez l'extension Kusto VS Code ou ADX Web Explorer