📌 Author's note: Independent, not affiliated with or endorsed by Microsoft. This site is a starting point — verify current product status against Microsoft documentation before architecture or purchasing decisions.
Programme shape

Where to
start

⚠ Rule zero — never quote an agent count without saying which screen it came from

Four screens count agents and they disagree by design: the reconciliation is the finding. The full walkthrough of the four screens and the gaps between them is on the Agent Map.

Six phases — each produces the evidence the next consumes

PhaseWhat you doOutput
01 · Discover & InventorySecurity Dashboard for AI · AgentsInfo sweep · no-auth and maker-credential flags · H/M/L tiers · shadow AITiered agent register
02 · Identity & GovernanceClassic: managed environments, enforced auth, owner/sponsor model. Modern: Conditional Access, ID Protection (Agent 365)Governed estate, auth baseline
03 · Data SecurityPurview DSPM for AI · oversharing assessment · Purview DLP for Copilot · label inheritance · browser DLP for public LLMsDLP active, oversharing remediated
04 · Runtime ProtectionDefender real-time protection · Prompt Shields · pre-deployment red teamingGuardrails live
05 · Monitoring & DetectionSentinel connectors (Copilot, Defender XDR, the two lake connectors) · Agent 365 observability · Defender alerts · analytics rules · huntingDetections firing
06 · Compliance & GovernanceLifecycle board · access reviews · quarterly reportingStanding cadence

The first week — five checks on what you already own

These are the five questions I ask of any tenant in the first week. All five run on E5 — no procurement conversation required:

  1. Which AI agents run on our laptops? AgentsInfo | where Platform == "LocalAgents" — vendor, version, MCP servers, device, account
  2. Which agents have no authentication? — publicly reachable, anyone with the URL
  3. How many are Classic? — outside the Entra perimeter entirely; find them by tag AgentCreatedBy:CopilotStudio
  4. Who owns nothing? — ownerless agents are unremediable agents
  5. What shadow AI is in use? — cloud app catalogue, sanctioned vs not

Five queries I actually run

Not a query library — those exist. These five earn their place because each one teaches something about how this telemetry behaves. Preview schemas move; verify against your tenant's schema tab before wiring any of these into a dashboard.

1 · What runs on our laptops? The first question worth answering, and it runs on licences you already own (Defender for Endpoint P2).

ADVANCED HUNTING
AgentsInfo
| where Platform == "LocalAgents"
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus !in~ ("Deleted", "Uninstalled")
| extend M = RawAgentInfo.localAgentMetadata
| project AgentId, Vendor = tostring(M.vendor), Process = tostring(M.relatedProcess),
          Device = tostring(M.deviceName), Account = tostring(M.accountName), McpServers

2 · The fleet, by platform. The lesson is in line two: AgentsInfo stores snapshots, so a bare arg_max(Timestamp, *) without by AgentId collapses the whole fleet to one row. I know because I shipped it.

ADVANCED HUNTING
AgentsInfo
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus != "Deleted"
| summarize Agents = count() by Platform

3 · What did agents actually do? The Agent 365 runtime rows. An empty result here usually means the licence/instrumentation gate — these ActionTypes only exist for instrumented agents, however busy the fleet is. Note the key juggling: RawEventData names the agent differently per operation.

ADVANCED HUNTING
CloudAppEvents
| where ActionType in ("InvokeAgent", "InferenceCall",
    "ExecuteToolBySDK", "ExecuteToolByGateway", "ExecuteToolByMCPServer")
| extend rd = parse_json(tostring(RawEventData))
| extend Agent = tostring(rd.TargetAgentName)
| extend Agent = iff(isempty(Agent), tostring(rd.AgentName), Agent)
| summarize Calls = count() by Agent, ActionType

4 · Is anyone already probing our Copilot? Per-interaction safety verdicts arrive on E5 — look at what's already being flagged before buying anything new.

LOG ANALYTICS
CopilotActivity
| where RecordType == "CopilotInteraction"
| mv-expand m = LLMEventData.Messages
| where tobool(m.JailbreakDetected) == true
| project TimeGenerated, AgentId, ActorName

5 · Which blueprint hurts most if it leaks? Blueprints hold the credentials, agents don't — so the blueprint with the most agents is the biggest blast radius. The identity tables are preview with unpublished schemas, hence the column_ifexists() guard.

SENTINEL DATA LAKE
EntraAgentIdentities
| extend BlueprintId = tostring(column_ifexists("agentIdentityBlueprintId", ""))
| summarize Agents = count() by BlueprintId
| top 10 by Agents
📌 Four KPIs to track weekly

Inventory coverage · no-auth agent count (target zero) · ownerless agent count (target zero) · detection coverage. If a metric can't be produced from the current phase's evidence, the phase isn't done.