Enable the unified security portal, connect all Defender products, configure incident routing and assignment rules, triage cross-product incidents with correlated alerts, and build SOC dashboards in Microsoft Defender XDR.
In this hands-on lab you will configure Microsoft Defender XDR as a unified incident management platform. You will navigate the Microsoft Defender portal, verify that all Defender products are licensed and active, connect Microsoft Sentinel for unified SIEM + XDR coverage, set up incident routing and assignment rules, understand how the correlation engine groups alerts across products, triage a realistic cross-product incident, apply custom tags and classifications, configure notification rules, create incident response templates, and review SOC performance dashboards. By the end, your security operations center will have a single pane of glass for every threat across endpoints, email, identity, and cloud apps.
A multinational retail corporation with 15,000 employees across 12 countries faces a growing challenge: security alerts from Microsoft Defender for Endpoint, Defender for Office 365, Defender for Identity, and Defender for Cloud Apps are scattered across separate portals. SOC analysts waste an average of 30 minutes per incident switching between consoles, manually correlating alerts, and trying to reconstruct attack timelines. During a recent phishing campaign, an analyst missed the connection between a malicious email (MDO), a credential compromise (MDI), and lateral movement on an endpoint (MDE) . resulting in a 4-hour delay before containment. The CISO has mandated a unified incident management strategy that correlates alerts across all Defender products, routes incidents to the right team automatically, and provides a single investigation experience.
Modern attacks rarely target a single surface. A typical business email compromise (BEC) attack spans email delivery (MDO), credential theft (MDI), endpoint exploitation (MDE), and data exfiltration via cloud apps (MDA). Without a unified incident view, SOC analysts investigate each alert in isolation and miss the full attack chain. Microsoft Defender XDR's correlation engine automatically stitches together related alerts from all Defender products into a single incident, reducing mean time to detect (MTTD) by up to 70% and mean time to respond (MTTR) by up to 60%. Configuring unified incident management is the foundational step for any organization deploying the Microsoft security stack.
Microsoft.Graph.Security module for API-based operationsThe Microsoft Defender portal at security.microsoft.com is the unified console for all Defender XDR products. It consolidates incidents, alerts, hunting, actions, and settings into a single experience. Familiarizing yourself with the portal layout is the essential first step.
The Home page displays a dashboard with cards for Active incidents, Active threats, Users at risk, and Devices at risk. The left navigation has sections grouped by: Investigation & response, Threat intelligence, Assets, Actions, and Settings. The incident queue shows a table with columns for Incident name, Severity, Status, Categories, and Assigned to.
security.microsoft.com as your primary security console. The Defender portal replaces the individual product portals (securitycenter.microsoft.com, protection.office.com, etc.) . those legacy URLs now redirect here automatically.Before configuring unified incident management, you must verify that all four Defender products are licensed and actively streaming telemetry. Missing or inactive products create blind spots in your incident correlation.
# Connect to Microsoft Graph with required scopes
# Scope: Organization.Read.All โ read tenant/org info
# Scope: Directory.Read.All โ read license and subscription data
# These are read-only scopes; no write permissions are requested
Connect-MgGraph -Scopes "Organization.Read.All","Directory.Read.All"
# List subscribed SKUs to check for E5 or Security add-on licenses
# This retrieves all license SKUs in your tenant and filters for the
# specific Defender-related plans needed for unified XDR coverage:
# SPE_E5 = Microsoft 365 E5 (full suite incl. all Defender products)
# IDENTITY_THREAT = Entra ID P2 / Identity Threat Protection
# ATP_ENTERPRISE = Defender for Endpoint P2
# THREAT_INTELLIGENCE = Defender for Office 365 P2
# Output columns:
# SkuPartNumber โ the license plan name
# CapabilityStatus โ should show "Enabled" if active
# Consumed โ number of licenses assigned to users
# Total โ total purchased license count
Get-MgSubscribedSku | Select-Object SkuPartNumber, CapabilityStatus,
@{N='Consumed';E={$_.ConsumedUnits}},
@{N='Total';E={$_.PrepaidUnits.Enabled}} |
Where-Object { $_.SkuPartNumber -match 'SPE_E5|IDENTITY_THREAT|ATP_ENTERPRISE|THREAT_INTELLIGENCE' } |
Format-Table -AutoSize
# Expected output: You should see entries for:
# SPE_E5 (Microsoft 365 E5) โ CapabilityStatus: Enabled
# THREAT_INTELLIGENCE (MDO P2) โ CapabilityStatus: Enabled
# ATP_ENTERPRISE (MDE P2) โ CapabilityStatus: Enabled
# If CapabilityStatus shows "Suspended" or "Deleted", the license
# has expired and the corresponding Defender product is inactive// Quick health check: confirm data is flowing from each Defender product
// Run each line individually in Advanced Hunting at security.microsoft.com
// Each query counts events ingested in the last 24 hours.
// A result of 0 means that product is NOT actively sending telemetry,
// which creates blind spots in cross-product incident correlation.
// MDE โ Defender for Endpoint: counts all device-level events
// (process creation, file changes, network connections, registry mods, etc.)
// If 0 โ no devices are onboarded or MDE is not licensed
DeviceEvents | where Timestamp > ago(24h) | count
// MDO โ Defender for Office 365: counts all email processing events
// (inbound/outbound mail, phishing detections, spam verdicts, etc.)
// If 0 โ MDO is not active or no mailboxes are protected
EmailEvents | where Timestamp > ago(24h) | count
// MDI โ Defender for Identity: counts identity logon events
// (AD authentication, Kerberos tickets, NTLM logons, pass-through auth)
// If 0 โ MDI sensors are not installed on domain controllers
IdentityLogonEvents | where Timestamp > ago(24h) | count
// MDA โ Defender for Cloud Apps: counts cloud application activity
// (SaaS app access, OAuth grants, file sharing, admin operations)
// If 0 โ MDA is not configured or no app connectors are enabled
CloudAppEvents | where Timestamp > ago(24h) | count0, the corresponding product is either not licensed, not configured, or has no onboarded assets. Resolve the issue before proceeding. unified incident management requires data from multiple products to demonstrate correlation.The unified SIEM + XDR experience brings Microsoft Sentinel directly into the Defender portal. This gives SOC analysts a single interface for both XDR incidents and Sentinel-generated incidents, with shared hunting, investigation, and automation capabilities.
law-sentinel-lab)After connection, the left navigation gains a SIEM section with sub-items for Content hub, Analytics, Data connectors, Workbooks, Hunting, and Automation. The incident queue now shows a Detection source column distinguishing between Microsoft Defender XDR and Microsoft Sentinel incidents.
Incident routing rules automatically assign incidents to the correct SOC team or analyst based on criteria like severity, category, device group, or detection source. This eliminates manual triage and ensures critical incidents reach the right responder immediately.
High-Severity to Tier 2 SOCHigh or CriticalSOC Tier 2 group or a specific userEmail Threats to MDO TeamInitialAccess AND Detection source contains Office 365Email Security Team# Connect to Microsoft Graph with incident management permissions
# Scope: SecurityIncident.ReadWrite.All โ read and update security incidents
# This permission requires admin consent in most tenants
Connect-MgGraph -Scopes "SecurityIncident.ReadWrite.All"
# Retrieve the 10 most recent incidents via the Graph Security API
# Sorted by creation time (newest first) to verify routing rules are working
# The $top parameter limits results; $orderby sorts descending by date
$incidents = Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/security/incidents?`$top=10&`$orderby=createdDateTime desc"
# Display incident assignment status in a formatted table
# Expected output columns:
# Id โ unique incident identifier (use this for API operations)
# Title โ incident display name (auto-generated from correlated alerts)
# Severity โ Low, Medium, High, or Critical
# Status โ New, Active, or Resolved
# AssignedTo โ analyst or group assigned (empty = unassigned, routing rule not matched)
# Created โ when the incident was created by the correlation engine
# If AssignedTo is empty for high-severity incidents, your routing rules need adjustment
$incidents.value | ForEach-Object {
[PSCustomObject]@{
Id = $_.id
Title = $_.displayName
Severity = $_.severity
Status = $_.status
AssignedTo = $_.assignedTo
Created = $_.createdDateTime
}
} | Format-Table -AutoSizeThe Defender XDR correlation engine is the heart of unified incident management. It automatically groups related alerts from different products into a single incident based on shared entities (users, devices, IP addresses, files), temporal proximity, and attack pattern matching. Understanding how this works is critical for effective triage.
// Find incidents with alerts from multiple detection sources
// Purpose: Identify TRUE cross-product incidents that demonstrate XDR correlation.
// Single-source incidents (e.g., only MDE) may be product-specific alerts.
// Multi-source incidents (e.g., MDE + MDO + MDI) represent coordinated attacks
// that the correlation engine automatically stitched together.
//
// How it works:
// 1. Queries the AlertInfo table for all alerts in the last 7 days
// 2. Groups alerts by IncidentId and counts distinct detection sources
// 3. Filters to only incidents with 2+ sources (cross-product correlation)
//
// Output columns:
// AlertCount โ total number of distinct alerts in the incident
// DetectionSources โ array of products that generated alerts (e.g., ["MDE","MDO"])
// SourceCount โ how many different products contributed alerts
// Categories โ MITRE ATT&CK categories (e.g., ["InitialAccess","Execution"])
// Severities โ severity levels present (e.g., ["High","Medium"])
// A high AlertCount with 3+ sources typically indicates a sophisticated multi-stage attack
AlertInfo
| where Timestamp > ago(7d)
| summarize
AlertCount = dcount(AlertId),
DetectionSources = make_set(DetectionSource),
SourceCount = dcount(DetectionSource),
Categories = make_set(Category),
Severities = make_set(Severity)
by IncidentId
| where SourceCount > 1 // Only incidents with alerts from 2+ products
| sort by AlertCount desc
| take 20The query results show incidents that span multiple detection sources (e.g., ["MicrosoftDefenderForEndpoint","MicrosoftDefenderForOffice365"]). Each row represents a correlated incident with the total alert count, the products involved, attack categories, and severity levels. High-value incidents typically have 3+ alerts from 2+ products.
SourceCount > 1 filter to focus on true cross-product incidents. these represent coordinated attacks that no single product can detect alone. This is the real power of XDR vs. standalone EDR or email security.In this step you will walk through the full triage workflow for a realistic multi-stage attack that spans email, identity, and endpoint telemetry. This simulates a business email compromise (BEC) attack where an employee receives a phishing email, enters credentials on a fake login page, and the attacker uses the compromised account to access internal systems.
// ============================================================
// ATTACK TIMELINE RECONSTRUCTION โ 3-stage BEC investigation
// Purpose: Trace a Business Email Compromise attack across
// email delivery โ credential theft โ endpoint compromise
// ============================================================
// Stage 1: Find the phishing email delivery
// MITRE ATT&CK: T1566.001 (Phishing: Spearphishing Attachment/Link)
// Searches EmailEvents for emails flagged as phishing by MDO
// Output: sender, recipient, subject, and delivery action
// DeliveryAction = "Delivered" means the phish reached the inbox
// DeliveryAction = "Blocked" means Safe Links/Safe Attachments stopped it
// NetworkMessageId is the unique email ID for deeper investigation
EmailEvents
| where Timestamp > ago(24h)
| where ThreatTypes has "Phish"
| project Timestamp, SenderFromAddress, RecipientEmailAddress,
Subject, DeliveryAction, ThreatTypes, NetworkMessageId
| order by Timestamp desc
| take 10
// Stage 2: Detect credential compromise via suspicious logon
// MITRE ATT&CK: T1078 (Valid Accounts) โ attacker using stolen credentials
// After phishing, check if the targeted user had suspicious logons
// Look for: unusual IPAddress, unknown Location, or unexpected Application
// LogonType "Interactive" = direct sign-in (vs. token refresh or service)
// FailureReason column helps identify brute-force attempts before success
let phishedUser = "user@contoso.com"; // Replace with actual user
IdentityLogonEvents
| where Timestamp > ago(24h)
| where AccountUpn == phishedUser
| where LogonType == "Interactive"
| project Timestamp, AccountUpn, DeviceName, IPAddress,
Location, Application, LogonType, FailureReason
| order by Timestamp asc
// Stage 3: Check for lateral movement or suspicious device activity
// MITRE ATT&CK: T1021 (Remote Services) / T1570 (Lateral Tool Transfer)
// Once credentials are compromised, attackers typically execute commands
// on endpoints. This query checks both direct and process-initiated actions
// by the compromised user across all devices.
// Key indicators: PowerShell execution, remote admin tools, file drops
// ActionType examples: ProcessCreated, FileCreated, RegistryValueSet
let compromisedUser = "user@contoso.com";
DeviceEvents
| where Timestamp > ago(24h)
| where AccountUpn == compromisedUser
or InitiatingProcessAccountUpn == compromisedUser
| project Timestamp, DeviceName, ActionType, FileName,
FolderPath, ProcessCommandLine, AccountUpn
| order by Timestamp asc
| take 50// ============================================================
// CROSS-PRODUCT UNIFIED ATTACK TIMELINE
// Purpose: Reconstruct the complete attack chain for a single user
// by merging telemetry from all four Defender products into one
// chronological timeline. This is the most powerful investigation
// technique in Defender XDR.
//
// How it works:
// - 'union' combines rows from 4 different tables into one result set
// - Each sub-query filters to the target user and adds a Source label
// - Results are sorted by Timestamp to show the attack progression
//
// Output columns:
// Timestamp โ when the event occurred (chronological order)
// Source โ which product detected it (MDO, MDI, MDE, or MDA)
// Detail โ human-readable summary of what happened
//
// Reading the timeline: look for the attack progression pattern:
// MDO event โ phishing email received
// MDI event โ credential used to sign in (possibly from unusual IP)
// MDE event โ suspicious process or file on endpoint
// MDA event โ cloud app access or data exfiltration
// ============================================================
let targetUser = "user@contoso.com";
let lookback = 24h;
union
// MDO: Emails received by the target user (phishing delivery)
(EmailEvents
| where Timestamp > ago(lookback)
| where RecipientEmailAddress == targetUser
| extend Source = "MDO", Detail = strcat("Email from: ", SenderFromAddress, " | Subject: ", Subject)
| project Timestamp, Source, Detail),
// MDI: Identity logon events (credential usage after compromise)
(IdentityLogonEvents
| where Timestamp > ago(lookback)
| where AccountUpn == targetUser
| extend Source = "MDI", Detail = strcat("Logon from: ", IPAddress, " | App: ", Application)
| project Timestamp, Source, Detail),
// MDE: Endpoint device activity (post-compromise actions)
(DeviceEvents
| where Timestamp > ago(lookback)
| where AccountUpn == targetUser
| extend Source = "MDE", Detail = strcat("Action: ", ActionType, " | File: ", FileName)
| project Timestamp, Source, Detail),
// MDA: Cloud app activity (data access or exfiltration)
(CloudAppEvents
| where Timestamp > ago(lookback)
| where AccountId == targetUser
| extend Source = "MDA", Detail = strcat("App: ", Application, " | Action: ", ActionType)
| project Timestamp, Source, Detail)
| order by Timestamp ascuser@contoso.com with an actual user from your tenant. If you are using a trial environment, use the user accounts from the Defender XDR evaluation lab's simulated attack scenarios.targetUser variable.Tags and classifications help SOC teams organize, filter, and report on incidents. Custom tags enable you to group incidents by business context (e.g., VIP user, PCI scope, specific campaign), while classifications record the final determination of each incident.
VIP-User . for incidents affecting executive accountsBEC-Campaign . for business email compromise patternsRetail-POS . for incidents affecting point-of-sale systemsContainment-Required . for incidents needing immediate isolation# Connect to Microsoft Graph
# Scope: SecurityIncident.ReadWrite.All โ required to read and modify incidents
# This scope requires admin consent and allows both reading and tagging incidents
Connect-MgGraph -Scopes "SecurityIncident.ReadWrite.All"
# Retrieve all high-severity active incidents via OData $filter
# The filter selects only incidents where:
# severity = 'high' AND status = 'active' (not yet resolved)
# This targets incidents that need escalation to Tier 2 SOC
$highSev = Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/v1.0/security/incidents?`$filter=severity eq 'high' and status eq 'active'"
# Loop through each incident and add the "Escalation-Required" tag
# The script preserves existing tags by merging with the new one
# Uses PATCH to update only the customTags property (not replace the incident)
# Expected behavior:
# - Incidents already tagged are skipped (idempotent)
# - Console output shows each incident ID and title that was tagged
# - After running, filter the incident queue by tag to see all escalated incidents
foreach ($incident in $highSev.value) {
$existingTags = $incident.customTags ?? @()
if ("Escalation-Required" -notin $existingTags) {
$body = @{
customTags = @($existingTags + "Escalation-Required")
} | ConvertTo-Json
Invoke-MgGraphRequest -Method PATCH `
-Uri "https://graph.microsoft.com/v1.0/security/incidents/$($incident.id)" `
-Body $body -ContentType "application/json"
Write-Host "Tagged incident $($incident.id): $($incident.displayName)"
}
}VIP, Crown-Jewel), compliance scope (PCI, HIPAA), campaign tracking (APT-XYZ), and workflow state (Escalated, Pending-Legal). Consistent tags enable powerful filtering and reporting.Email notification rules ensure that SOC managers, on-call analysts, and stakeholders are immediately alerted when high-priority incidents are created. This is essential for maintaining SLA response times on critical threats.
Critical Incident AlertsHigh and CriticalThe notification rules list shows your rules with columns for Name, Severity, Recipients, and Status (Enabled/Disabled). When a matching incident is created, recipients receive an email with the incident title, severity, category, impacted assets, and a direct link to the incident in the Defender portal.
Incident response templates standardize how analysts handle common incident types. By pre-defining investigation steps, containment actions, and remediation procedures, you ensure consistent quality across all analysts and reduce onboarding time for new SOC members.
# Add a structured BEC response playbook as a comment to an incident
# Scope: SecurityIncident.ReadWrite.All โ needed to post comments on incidents
# This creates a reusable investigation template that analysts can follow
# step-by-step during Business Email Compromise (BEC) incident response.
# Expected output: A Markdown-formatted comment appears in the incident's
# Comments tab, visible to all SOC analysts assigned to the incident.
Connect-MgGraph -Scopes "SecurityIncident.ReadWrite.All"
$incidentId = "12345" # Replace with actual incident ID from the portal
$commentBody = @"
## BEC Response Playbook. Phase 1: Triage
- [ ] Confirm phishing email delivery via EmailEvents
- [ ] Identify affected user(s) and scope of credential exposure
- [ ] Check IdentityLogonEvents for post-compromise logons
- [ ] Verify if MFA was bypassed or absent
## Phase 2: Containment
- [ ] Disable compromised account(s) in Entra ID
- [ ] Revoke all active sessions (Revoke-MgUserSignInSession)
- [ ] Block sender domain in MDO Tenant Allow/Block List
- [ ] Isolate affected device(s) via MDE
## Phase 3: Investigation
- [ ] Run cross-product timeline query in Advanced Hunting
- [ ] Check inbox rules for auto-forwarding (Get-InboxRule)
- [ ] Review OAuth app consents for malicious grants
- [ ] Examine CloudAppEvents for data exfiltration
## Phase 4: Remediation
- [ ] Reset user password and enforce MFA re-registration
- [ ] Remove malicious inbox rules and OAuth consents
- [ ] Purge phishing emails from all mailboxes (Soft Delete)
- [ ] Update conditional access policies
"@
$body = @{ comment = $commentBody } | ConvertTo-Json
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/v1.0/security/incidents/$incidentId/comments" `
-Body $body -ContentType "application/json"
Write-Host "Response template added to incident $incidentId"Congratulations! In this lab you have configured a complete unified incident management platform:
// ============================================================
// SOC PERFORMANCE DASHBOARD โ 3 key operational metrics
// Run these queries in Advanced Hunting for SOC reporting
// ============================================================
// QUERY 1: Mean Time to Acknowledge (MTTA)
// Purpose: Measure how quickly incidents get assigned to an analyst
// How it works:
// 1. Finds the earliest alert timestamp per incident (FirstAlert)
// 2. Finds the earliest assignment timestamp per incident (FirstAssignment)
// 3. Calculates the difference in minutes (MTTA_minutes)
// 4. Aggregates across all incidents for avg, median, and P95
// Target benchmarks:
// AvgMTTA < 15 min (industry standard for mature SOCs)
// P95_MTTA < 60 min (worst-case should still be under 1 hour)
// High MTTA values indicate routing rules are not working or SOC is understaffed
AlertInfo
| where Timestamp > ago(30d)
| join kind=inner (AlertEvidence | where Timestamp > ago(30d))
on AlertId
| summarize FirstAlert = min(Timestamp) by IncidentId
| join kind=inner (
AlertInfo
| where Timestamp > ago(30d)
| where isnotempty(AssignedTo)
| summarize FirstAssignment = min(Timestamp) by IncidentId
) on IncidentId
| extend MTTA_minutes = datetime_diff('minute', FirstAssignment, FirstAlert)
| summarize
AvgMTTA = avg(MTTA_minutes),
MedianMTTA = percentile(MTTA_minutes, 50),
P95_MTTA = percentile(MTTA_minutes, 95),
TotalIncidents = count()
// QUERY 2: Incident volume by severity and detection source
// Purpose: Visualize which products generate the most incidents
// and at what severity level โ helps with SOC staffing decisions
// Output: Column chart showing incident distribution
// High counts from a single source may indicate noisy detections
// that need tuning; cross-source incidents show XDR correlation value
AlertInfo
| where Timestamp > ago(30d)
| summarize IncidentCount = dcount(IncidentId) by Severity, DetectionSource
| sort by IncidentCount desc
| render columnchart
// QUERY 3: Classification accuracy โ track false positive rate
// Purpose: Measure detection quality by showing how incidents were classified
// Output: Count and percentage for each classification type
// TruePositive โ confirmed real threats
// FalsePositive โ incorrectly flagged benign activity
// InformationalExpected โ known/expected activity (e.g., pen tests)
// Target: False positive rate should be < 20%; above that, analytics rules
// need tuning to reduce alert fatigue and wasted analyst time
AlertInfo
| where Timestamp > ago(30d)
| summarize count() by Classification = tostring(Classification)
| extend Percentage = round(100.0 * count_ / toscalar(
AlertInfo | where Timestamp > ago(30d) | count), 1)
| sort by count_ desc| Resource | Description |
|---|---|
| Microsoft Defender XDR documentation | Comprehensive product docs for the unified XDR platform |
| Incidents overview in Defender XDR | How incidents are created, correlated, and managed |
| Respond to your first incident | Step-by-step first incident response guide |
| Advanced hunting overview | Cross-product threat hunting with KQL |
| Microsoft Graph Security API | Programmatic access to incidents, alerts, and security data |
| Defender XDR evaluation lab | Set up a trial environment with simulated attacks |
| Prioritize incidents in Defender XDR | Best practices for incident queue management |
| Sentinel + Defender XDR integration | Unified SIEM and XDR configuration guide |