Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Важно!
Некоторые сведения относятся к предварительно выпущенному продукту, который может быть существенно изменен перед выпуском. Корпорация Майкрософт не дает явных или подразумеваемых гарантий относительно предоставленных здесь сведений.
Microsoft Defender автоматически обнаруживает поддерживаемые локальные агенты ИИ и серверы MCP, настроенные на подключенных к Defender устройствах, и отображает их в инвентаре агентов ИИ и в расширенном поиске. Дополнительные сведения об обнаружении локальных агентов ИИ см. в статье Обнаружение локальных агентов ИИ с помощью Microsoft Defender для конечной точки.
В этой статье вы узнаете, как просматривать обнаруженные агенты в инвентаре, анализировать их конфигурацию и риски, изучать их связи с устройствами и идентичностями, а также изучать присутствие агентов с помощью продвинутой охоты.
Предварительные условия
Прежде чем обнаруживать локальные агенты ИИ в конечных точках, убедитесь, что вы соответствуете следующим требованиям:
- Ваша среда находится в коммерческом облаке. Суверенные и национальные облака не поддерживаются.
- У вашей организации имеется лицензия Microsoft Defender для конечной точки Plan 2. Дополнительные сведения см. в разделе "Лицензирование".
- Устройства подключены к Microsoft Defender для конечной точки.
- Устройства запускают поддерживаемую версию Windows или macOS, а антивирусная программа Microsoft Defender обновляется с текущими ежемесячными обновлениями платформы и подсистемы.
- Microsoft Defender Antivirus работает в активном режиме на ваших устройствах с включенной защитой в реальном времени.
Вам не требуется дополнительное развертывание, конфигурация или скрипты, выходящие за рамки требований к подключению устройства. Если устройство соответствует всем предварительным требованиям, обнаружение агента начинается автоматически.
Лицензирование
Microsoft Defender для конечной точки Plan 2 — это минимальная лицензия для локального обнаружения агентов ИИ. Возможности обеспечения безопасности для агентов, обнаруженных Defender, требуют дополнительной лицензии, как описано в следующей таблице.
| Capability | Требуемая лицензия |
|---|---|
| Откройте для себя локальные AI-агенты и просмотрите их в инвентаре агентов AI, включая данные агента, устройство и аккаунт, а также настроенные MCP-серверы | Microsoft Defender для конечной точки (план 2) |
Запрашивайте локальных агентов ИИ в расширенном поиске, включая таблицу AgentsInfo |
Microsoft Defender для конечной точки (план 2) |
| Просмотрите уровень риска, индикаторы риска и рекомендации по безопасности для обнаруженных локальных агентов ИИ | Microsoft 365 E7 или Microsoft Agent 365 вместе с Microsoft Defender для конечной точки Plan 2 |
Microsoft 365 E5 и Microsoft 365 E7 обе включают Microsoft Defender для конечной точки Plan 2. Если в вашей организации есть Microsoft Defender для конечной точки Plan 2 без Microsoft 365 E7 или Microsoft Agent 365, вы можете найти локальных ИИ-агентов, просмотреть инвентарь и запросить агентов в расширенном поиске, но уровень риска, индикаторы риска и рекомендации по безопасности недоступны.
Просмотреть локальных агентов ИИ в реестре
Войдите на портал Microsoft Defender.
В области навигации слева выберите Ресурсы>агенты ИИ.
Выберите вкладку «Локальные агенты », чтобы увидеть локальные агенты ИИ, обнаруженные на ваших устройствах.
Карточки инсайтов агентов суммируют общее количество контролируемых агентов, количество агентов с высоким уровнем риска и количество критически важных агентов.
Список показывает одну запись для каждой установки агента, поэтому агент, работающий на нескольких устройствах или под несколькими аккаунтами на одном устройстве, появляется более одного раза. Используйте фильтры, чтобы сузить список, выберите «Настроить столбцы », чтобы изменить появление столбцов, или выбрать «Экспорт », чтобы скачать список.
| колонна | Description |
|---|---|
| Имя агента, версия | Обнаруженный агент и установленная версия. |
| Имя устройства, идентификатор устройства, платформа ОС, тип устройства | Устройство, на котором был обнаружен агент. |
| Имя аккаунта, домен аккаунта | Счёт, под которым ведёт агент. |
| Уровень риска | Общий уровень риска агента. |
| Индикаторы риска | Почему агент считается рискованным, например , работает на критически важном устройстве или используется критическим пользователем. |
| Рекомендации | Рекомендации по безопасности, которые применяются к агенту. |
| MCP-серверы, локальные MCP | Количество удалённых MCP-серверов и локальных MCP-серверов, настроенных для агента. |
| Первый просмотр | Когда агента впервые обнаружили. |
Примечание.
Уровни риска, индикаторы риска и рекомендации по безопасности требуют Microsoft 365 E7 или Microsoft Agent 365. Без такой лицензии вы всё равно можете просматривать инвентарь и данные каждого агента. Дополнительные сведения см. в разделе "Лицензирование".
Просмотрите данные о местном агенте ИИ
Из списка локальных агентов выберите агента, чтобы открыть панель с его деталями:
- Детали показывают имя агента, поставщика, модель, связанный процесс, насколько доверен хост-процесс, автоматически ли агент одобряет свои действия, а также идентификатор исходного агента.
- Риск показывает уровень риска, индикаторы риска и рекомендации по безопасности, применимые к агенту.
- Данные устройства показывают устройство, на котором был обнаружен агент, включая платформу и версию ОС, тип устройства и роли, а также идентификатор устройства Microsoft Entra.
- Данные пользователя показывают идентификатор, имя и домен аккаунта, под которым работает агент.
- MCP-серверы перечисляют MCP-серверы, настроенные для агента, с указанием имени, типа и конечной точки каждого сервера.
- Локальные MCP-серверы отображают локальные записи MCP, обнаруженные на устройстве.
Чтобы продолжить расследование, выберите Перейти к поиску, чтобы выполнить запрос по агенту в расширенном поиске, Показать на карте, чтобы увидеть агента на карте поверхности атак, или Открыть страницу агента, чтобы открыть полную страницу агента.
Изучите поверхность атаки агента и рекомендации
На странице агента есть вкладка «Обзор » и вкладка « Рекомендации по безопасности ». Карта поверхности «Атака » на вкладке «Обзор » показывает другие агенты, устройства, идентичности и ресурсы, связанные с агентом.
Дополнительные сведения об использовании инвентаризации агентов ИИ см. в статье Обнаружение агентов ИИ и оценка состояния безопасности с помощью Microsoft Defender.
Запрашивайте локальных агентов ИИ с помощью расширенного поиска
Используйте продвинутую охоту для проактивного изучения локального присутствия агентов ИИ, понимания, как они настроены, и выявления агентов и пользователей, которые несут наибольший риск. Эти запросы помогают инвентаризировать агентов, проверять MCP-серверы, к которым они подключаются, и отслеживать доступ к критически важным или чувствительным активам.
Понимайте таблицы
Три расширенные таблицы поиска описывают локальные ИИ-агенты. Каждый отвечает на разные вопросы, и они наиболее полезны вместе.
| Стол | То, что он содержит | Используй его, чтобы ответить |
|---|---|---|
| AgentInfo | Запись профиля каждого AI-агента, обнаруженного Microsoft Defender, на всех платформах агентов. Для локальных AI-агентов запись включает издателя, версию, процесс хостинга, настройки доверия и автоутверждения, настроенные MCP-серверы, а также устройство и учетную запись, на которых был замечен агент. | Что это за агент и как он настроен? |
| ExposureGraphNodes | Каждая структура вашей организации в качестве узла, включая агентов ИИ, устройства, идентичности и облачные ресурсы, а также такие свойства, как критичность активов и наличие конфиденциальных данных. | Что это за сущность и насколько это важно? |
| ExposureGraphEdges | Взаимосвязи между узлами, такими как устройство, на котором работает агент, или ресурсы, к которым может получить доступ идентичность. | До чего может дотянуться этот агент? |
Вкратце, AgentsInfo описывает, что представляет собой агент, а граф доступности описывает, чего агент может достичь.
Оба источника данных содержат агенты от всех платформ, включая облачных, поэтому каждый требует собственного фильтра.
В AgentsInfo отфильтруйте по столбцу Platform:
AgentsInfo
| where Platform == "LocalAgents"
В ExposureGraphNodes ИИ-агенты используют метку узла ai-agent. Фильтр на платформе, указанной в свойствах узла:
ExposureGraphNodes
| where NodeLabel == "ai-agent"
| where tostring(NodeProperties.rawData.aiAgentMetadata.platform) == "LocalAgents"
Важно!
В ExposureGraphEdges таблице нет свойства, идентифицирующего местных агентов ИИ. При фильтрации только по SourceNodeLabel == "ai-agent" возвращаются пограничные устройства для всех AI-агентов в вашем тенанте, включая облачных агентов. Всегда сначала получайте набор локальных агентов из ExposureGraphNodes, а затем выполняйте соединение с ExposureGraphEdges по идентификатору узла, как показано в следующих запросах.
Объедините таблицы
Агент имеет два идентификатора, и запросы, объединяющие таблицы, требуют оба:
-
AgentIdИдентифицирует профиль агента вAgentsInfo. Граф экспозиции хранит в узле агента то же значение, что и вNodeProperties.rawData.aiAgentMetadata.id. -
NodeIdопределяет узел агента в графе экспозиции. Это значение, на которое ссылаетсяExposureGraphEdges, вSourceNodeIdиTargetNodeId.
| Чтобы перейти от | Кому | Матч продолжается |
|---|---|---|
AgentsInfo |
ExposureGraphNodes |
tostring(AgentId) и tostring(NodeProperties.rawData.aiAgentMetadata.id). |
ExposureGraphNodes |
ExposureGraphEdges |
NodeId или SourceNodeId или TargetNodeId |
Примечание.
AgentId — guid столбец в AgentsInfo, но граф экспозиции хранит то же значение, что и строка. Преобразуйте это с помощью tostring() с обеих сторон соединения. Соединение между столбцами разных типов не совпадает ни с одной строкой.
Локальные узлы агента ИИ соединяются с остальной частью графа экспозиции через следующие рёбра:
| Метка ребра | Метка целевого узла | Description |
|---|---|---|
runs on |
device, ec2.instance, microsoft.compute/virtualmachines |
Устройство, на котором был обнаружен агент. |
uses |
mcp/server |
MCP-сервер, настроенный под агента. |
used by |
user |
Субъект, использующий агента. |
Облачные ИИ-агенты также используют ребро can authenticate as, которое указывает на субъект-службу или приложение OAuth Microsoft Entra. Локальные агенты ИИ не используют это преимущество, поэтому используйте used by, чтобы определить, кто скрывается за локальным агентом ИИ.
Критичность актива хранится в ExposureGraphNodes, в NodeProperties.rawData.criticalityLevel.criticalityLevel, где 0 — наивысший уровень (очень высокий) и 3 самый низкий (низкий). Свойство ruleNames содержит список правил классификации, из-за которых ресурс был отнесён к критически важным.
Работа с локальными профилями агентов ИИ
AgentsInfo добавляет запись каждый раз при обновлении профиля агента, поэтому у одного агента обычно несколько записей. Чтобы вернуть только самую последнюю запись для каждого агента, используйте сводку с arg_max по Timestamp:
AgentsInfo
| where Platform == "LocalAgents"
| summarize arg_max(Timestamp, Name, Version, LifecycleStatus, RawAgentInfo) by AgentId
LifecycleStatus сообщает, по-прежнему ли агент присутствует на устройстве. Переустановленный агент также может получить новый AgentId, из-за чего предыдущая запись помечается как Deleted, поэтому, если вам нужен актуальный инвентарь, отфильтровывайте записи Deleted и Uninstalled.
Многие AgentsInfo столбцы описывают облачные агенты и пусты для локальных агентов ИИ. Столбцы, содержащие локальные данные агентов ИИ, — это AgentId, Name, Version, PublishedStatusLifecycleStatusLastUpdatedDateTimeMcpServersDeclaredToolsи .RawAgentInfo
Состояние локального ИИ-агента находится в столбце RawAgentInfo, в разделе localAgentMetadata:
| Property | Description |
|---|---|
vendor |
Издатель агента, например Anthropic, Google или OpenAI. |
relatedProcess |
Процесс, который размещает агента, например code.exe. |
trustedProcess |
Является ли процесс хоста доверенным. Указывается как строка "true" или "false". |
autoApprove |
Действует ли агент без запроса пользователя на одобрение. Указывается как строка "true" или "false". |
deviceName, aadDeviceId |
Устройство, на котором был обнаружен агент. |
accountName, accountDomain, accountSid |
Учётная запись, под которой работал агент. |
localMcps |
MCP-серверы, которые работают локально на устройстве, включая команду, запускающую каждый из них. |
Примечание.
trustedProcess и autoApprove отражаются как строки, а не как булевые значения. Сравнивайте их с "true" или "false" вместо использования tobool().
Каждый из следующих запросов является автономным. Запросы, использующие граф экспозиции, начинаются с набора операторов let, которые определяют локальные ИИ-агенты и устройства, на которых они работают.
Соберите инвентаризацию местных агентов ИИ
В этом запросе перечислены локальные агенты ИИ, обнаруженные в вашей организации, а также издатель, хост-процесс, используемые версии и масштабы развертывания каждого агента:
AgentsInfo
| where Platform == "LocalAgents"
| summarize arg_max(Timestamp, Name, Version, LifecycleStatus, RawAgentInfo)
by AgentId
| where LifecycleStatus !in~ ("Deleted", "Uninstalled")
| extend AgentMetadata = RawAgentInfo.localAgentMetadata
| extend Vendor = tostring(AgentMetadata.vendor),
Process = tostring(AgentMetadata.relatedProcess),
Device = tostring(AgentMetadata.deviceName),
Account = tostring(AgentMetadata.accountName)
| summarize Installations = count(),
DeviceCount = dcount(Device),
Devices = make_set(Device, 100),
Versions = make_set(Version, 20),
Accounts = make_set_if(Account, isnotempty(Account), 50)
by Agent = Name, Vendor, Process
| sort by DeviceCount desc, Installations desc
Каждый AgentId из них представляет один профиль агента, то есть один агент на одном устройстве для одной учетной записи.
Installations учитывает эти профили, поэтому профиль агента, которым на одном устройстве пользуются два человека, учитывается дважды, а DeviceCount учитывает устройство один раз.
Изучите MCP-серверы и инструменты, которые используют локальные AI-агенты
В этом запросе перечислены MCP-серверы и инструменты, настроенные для локальных AI-агентов, агенты и устройства, которые их используют, и где каждый из них запускается:
let localAgentProfiles =
AgentsInfo
| where Platform == "LocalAgents"
| extend AgentMetadata = RawAgentInfo.localAgentMetadata
| project Timestamp,
Agent = Name,
Device = tostring(AgentMetadata.deviceName),
Account = tostring(AgentMetadata.accountName),
McpServers,
DeclaredTools,
LocalServers = AgentMetadata.localMcps;
let remoteMcpServers =
localAgentProfiles
| mv-expand Server = McpServers
| project Timestamp, Agent, Device, Account,
McpServer = tostring(Server.name),
Origin = "Remote MCP server",
Transport = tostring(Server.type),
Location = tostring(Server.endpoint);
let agentDeclaredTools =
localAgentProfiles
| mv-expand Tool = DeclaredTools
| project Timestamp, Agent, Device, Account,
McpServer = tostring(Tool.name),
Origin = "Declared tool",
Transport = tostring(Tool.type),
Location = tostring(Tool.endpoint);
let localMcpServers =
localAgentProfiles
| mv-expand Server = LocalServers
| project Timestamp, Agent, Device, Account,
McpServer = tostring(Server.name),
Origin = "Local MCP server",
Transport = tostring(Server.transportType),
Location = tostring(Server.commandName);
remoteMcpServers
| union agentDeclaredTools, localMcpServers
| where isnotempty(McpServer)
| summarize LastSeen = max(Timestamp),
Agents = make_set(Agent, 20),
Devices = make_set(Device, 20),
Accounts = make_set_if(Account, isnotempty(Account), 20)
by McpServer, Origin, Transport, Location
| sort by McpServer asc, Origin asc
В столбце Origin выделены три способа отчёта о сервере или инструменте:
-
Удалённый MCP-сервер доступен по сети и
Locationсодержит свою конечную точку. -
Локальный MCP-сервер запускается как процесс на устройстве и
Locationсодержит команду, которая его запускает. Локальные MCP-серверы указываются только вAgentsInfo. - Декларированный инструмент — это инструмент, который агент рекламирует. Объявленные инструменты часто поддерживаются сервером MCP, но не всегда сообщают о конечной точке.
В отличие от других запросов, этот читает каждую запись профиля для каждого агента, чтобы были включены MCP-серверы, о которых сообщалось в любой момент времени. В столбце LastSeen указано, когда каждый сервер в последний раз отчитался.
Найдите локальных агентов ИИ с опасными конфигурациями
Этот запрос возвращает локальных ИИ-агентов, которые действуют, не запрашивая одобрения пользователя, или работают в недоверенном хост-процессе:
AgentsInfo
| where Platform == "LocalAgents"
| summarize arg_max(Timestamp, Name, Version, LifecycleStatus, RawAgentInfo)
by AgentId
| where LifecycleStatus !in~ ("Deleted", "Uninstalled")
| extend AgentMetadata = RawAgentInfo.localAgentMetadata
| extend AutoApprove = tostring(AgentMetadata.autoApprove),
TrustedProcess = tostring(AgentMetadata.trustedProcess),
Vendor = tostring(AgentMetadata.vendor),
Process = tostring(AgentMetadata.relatedProcess),
Device = tostring(AgentMetadata.deviceName),
Account = tostring(AgentMetadata.accountName)
| where AutoApprove =~ "true" or TrustedProcess =~ "false"
| extend RiskReason = case(
AutoApprove =~ "true" and TrustedProcess =~ "false",
"Acts without approval, and the host process isn't trusted",
AutoApprove =~ "true",
"Acts without approval",
"The host process isn't trusted")
| project Agent = Name, Vendor, Version, Process, Device, Account,
AutoApprove, TrustedProcess, RiskReason, LastSeen = Timestamp
| sort by Device asc, Agent asc
Агент, который автоматически одобряет свои действия, запускает инструменты и получает доступ к ресурсам без подтверждения каждого шага, поэтому учетная запись и устройство, на которых работает агент, определяют, что он может делать без надзора.
Найдите рискованных локальных агентов ИИ на критически важных устройствах
Этот запрос объединяет конфигурацию агентов из AgentsInfo с данными о критичности активов из графа подверженности, поэтому вы можете начать с агентов, которые действуют автономно и работают на критически важных для бизнеса устройствах:
let deviceLabels = dynamic(["device", "ec2.instance",
"microsoft.compute/virtualmachines"]);
let riskyAgentProfiles =
AgentsInfo
| where Platform == "LocalAgents"
| summarize arg_max(Timestamp, Name, Version, LifecycleStatus, RawAgentInfo)
by AgentId
| where LifecycleStatus !in~ ("Deleted", "Uninstalled")
| extend AgentMetadata = RawAgentInfo.localAgentMetadata
| extend AutoApprove = tostring(AgentMetadata.autoApprove),
TrustedProcess = tostring(AgentMetadata.trustedProcess)
| where AutoApprove =~ "true" or TrustedProcess =~ "false"
| project AgentId = tostring(AgentId),
Agent = Name,
Version,
Vendor = tostring(AgentMetadata.vendor),
Account = tostring(AgentMetadata.accountName),
AutoApprove,
TrustedProcess;
let localAgentNodes =
ExposureGraphNodes
| where NodeLabel == "ai-agent"
| where tostring(NodeProperties.rawData.aiAgentMetadata.platform) == "LocalAgents"
| project AgentNodeId = NodeId,
AgentId = tostring(NodeProperties.rawData.aiAgentMetadata.id);
let agentDeviceEdges =
ExposureGraphEdges
| where SourceNodeLabel == "ai-agent"
| where EdgeLabel =~ "runs on"
| where TargetNodeLabel in (deviceLabels)
| project AgentNodeId = SourceNodeId, DeviceId = TargetNodeId,
Device = TargetNodeName, DeviceType = TargetNodeLabel;
let criticalDevices =
ExposureGraphNodes
| where NodeLabel in (deviceLabels)
| where NodeProperties has "criticalityLevel"
| extend CriticalityLevel =
toint(NodeProperties.rawData.criticalityLevel.criticalityLevel)
| where CriticalityLevel between (0 .. 3)
| extend Criticality = case(
CriticalityLevel == 0, "Very high",
CriticalityLevel == 1, "High",
CriticalityLevel == 2, "Medium",
"Low")
| project DeviceId = NodeId, CriticalityLevel, Criticality,
CriticalityReason =
tostring(NodeProperties.rawData.criticalityLevel.ruleNames);
riskyAgentProfiles
| join kind=inner localAgentNodes on AgentId
| join kind=inner agentDeviceEdges on AgentNodeId
| join kind=inner criticalDevices on DeviceId
| project Device, DeviceType, Criticality, CriticalityReason,
Agent, Vendor, Version, Account, AutoApprove, TrustedProcess,
CriticalityLevel
| sort by CriticalityLevel asc, Device asc, Agent asc
| project-away CriticalityLevel
Чтобы проверить каждого локального ИИ-агента на критически важном устройстве, а не только рискованных, уберите эту where AutoApprove =~ "true" or TrustedProcess =~ "false" линию.
Ранжуйте пользователей, чьи локальные агенты ИИ достигают критически важных или чувствительных активов
Этот запрос ранжирует учетные записи, использующие локальные ИИ-агенты, по количеству критически важных или конфиденциальных ресурсов, к которым у них есть доступ, чтобы вы могли в первую очередь определить пользователей с наибольшей зоной потенциального воздействия. В столбце UserCriticality показано, классифицируется ли идентичность как критический актив, например, глобальный администратор:
let deviceLabels = dynamic(["device", "ec2.instance",
"microsoft.compute/virtualmachines"]);
let localAgents =
ExposureGraphNodes
| where NodeLabel == "ai-agent"
| where tostring(NodeProperties.rawData.aiAgentMetadata.platform) == "LocalAgents"
| project AgentNodeId = NodeId, AIAgent = NodeName;
let agentDeviceEdges =
ExposureGraphEdges
| where SourceNodeLabel == "ai-agent"
| where EdgeLabel =~ "runs on"
| where TargetNodeLabel in (deviceLabels)
| project AgentNodeId = SourceNodeId, DeviceId = TargetNodeId,
Device = TargetNodeName;
let agentUserEdges =
ExposureGraphEdges
| where SourceNodeLabel == "ai-agent"
| where EdgeLabel =~ "used by"
| project AgentNodeId = SourceNodeId, UserId = TargetNodeId,
User = TargetNodeName;
let userReach =
ExposureGraphEdges
| where EdgeLabel in~ ("has permissions to", "has role on")
| project UserId = SourceNodeId, AssetId = TargetNodeId
| union (
ExposureGraphNodes
| where NodeLabel == "user"
| project UserId = NodeId, AssetId = NodeId
);
let sensitiveAssets =
ExposureGraphNodes
| where NodeProperties has "criticalityLevel"
or NodeProperties has "containsSensitiveData"
| extend
CriticalityLevel =
toint(NodeProperties.rawData.criticalityLevel.criticalityLevel),
SensitiveDataRaw = tostring(NodeProperties.rawData.containsSensitiveData)
| extend HasSensitiveData =
iff(isnotempty(SensitiveDataRaw) and SensitiveDataRaw !~ "false", "Yes", "No")
| where CriticalityLevel between (0 .. 3) or HasSensitiveData == "Yes"
| extend CriticalityRank =
iff(CriticalityLevel between (0 .. 3), CriticalityLevel, 4)
| project AssetId = NodeId, AssetName = NodeName,
CriticalityRank, HasSensitiveData;
let agentUsers =
localAgents
| join kind=inner agentDeviceEdges on AgentNodeId
| join kind=inner agentUserEdges on AgentNodeId
| project AIAgent, Device, UserId, User;
agentUsers
| join kind=inner userReach on UserId
| join kind=inner sensitiveAssets on AssetId
| summarize AIAgents = make_set(AIAgent, 20),
Devices = make_set(Device, 20),
ReachableAssets = dcountif(AssetId, AssetId != UserId),
SensitiveAssets = dcountif(AssetId,
AssetId != UserId and HasSensitiveData == "Yes"),
Assets = make_set_if(AssetName, AssetId != UserId, 50),
UserRank = minif(CriticalityRank, AssetId == UserId),
AssetRank = minif(CriticalityRank, AssetId != UserId)
by User
| extend UserCriticality = case(
UserRank == 0, "Very high",
UserRank == 1, "High",
UserRank == 2, "Medium",
UserRank == 3, "Low",
"Not classified"),
HighestAssetCriticality = case(
AssetRank == 0, "Very high",
AssetRank == 1, "High",
AssetRank == 2, "Medium",
AssetRank == 3, "Low",
AssetRank == 4, "Sensitive data",
"None")
| extend SortRank = coalesce(AssetRank, 99)
| project User, UserCriticality, ReachableAssets, SensitiveAssets,
HighestAssetCriticality, AIAgents, Devices, Assets, SortRank
| sort by SortRank asc, ReachableAssets desc
| project-away SortRank