functions/Get-XdrIncident.ps1
|
function Get-XdrIncident { <# .SYNOPSIS Retrieves incidents from Microsoft Defender XDR. .DESCRIPTION Gets incidents from Microsoft Defender XDR with support for pagination, sorting, and filtering. This cmdlet translates severity values and detection source IDs to friendly names. Severity translations: 32=Information, 64=Low, 128=Medium, 256=High This function includes caching support with a 10-minute TTL to reduce API calls. .PARAMETER TitleSearchTerms Array of search terms to filter incidents by title. .PARAMETER LookBackInDays Number of days to look back for incidents. Default is 30. .PARAMETER SortByField Field to sort by. Valid values are: TopRisk, CreatedDate, LastUpdatedDate, Status, severity, name. Default is TopRisk. .PARAMETER SortOrder Sort order. Valid values are Ascending or Descending. Default is Descending. .PARAMETER PageSize Number of incidents to retrieve per page. Default is 40. .PARAMETER PageIndex Page index for pagination. Default is 1. .PARAMETER DefenderExpertsLicensed Indicates if Microsoft Defender Experts for XDR license is assigned to the tenant. Default is false. .PARAMETER All Retrieves all incidents by automatically paging through all results. When specified, PageSize and PageIndex parameters are used for the page size, but pagination is automatic. .PARAMETER IncidentId Retrieves a specific incident by its ID. When specified, all other filtering and pagination parameters are ignored. Cannot be combined with any other parameters. .PARAMETER Force Bypasses the cache and forces a fresh retrieval from the API. .EXAMPLE Get-XdrIncident Retrieves the first 40 incidents from the last 30 days, sorted by TopRisk in descending order. .EXAMPLE Get-XdrIncident -LookBackInDays 7 -PageSize 100 Retrieves the first 100 incidents from the last 7 days. .EXAMPLE Get-XdrIncident -SortByField CreatedDate -SortOrder Ascending Retrieves incidents sorted by creation date in ascending order (oldest first). .EXAMPLE Get-XdrIncident -TitleSearchTerms "ransomware", "phishing" Retrieves incidents with titles containing "ransomware" or "phishing". .EXAMPLE Get-XdrIncident -All Retrieves all incidents by automatically paging through all results. .EXAMPLE Get-XdrIncident -DefenderExpertsLicensed -LookBackInDays 90 Retrieves incidents from the last 90 days for a tenant with Defender Experts license. .EXAMPLE Get-XdrIncident -IncidentId 2823 Retrieves a specific incident by its ID. .EXAMPLE Get-XdrIncident | Where-Object { $_.SeverityName -eq "High" } Retrieves incidents and filters for high severity ones. .OUTPUTS Object[] Returns an array of incident objects with properties including: - IncidentId: Unique incident identifier - Title: Incident title - Severity: Numeric severity value - SeverityName: Friendly severity name (Information/Low/Medium/High) - DetectionSources: Array of numeric detection source IDs - DetectionSourceNames: Array of friendly detection source names - Status: Incident status - CreatedTime: When the incident was created - LastUpdateTime: When the incident was last updated - AlertCount: Number of alerts in the incident - Classification: Incident classification - Determination: Incident determination And many other properties from the API response #> [OutputType([System.Object[]])] [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(ParameterSetName = 'List')] [string[]]$TitleSearchTerms, [Parameter(ParameterSetName = 'List')] [ValidateRange(1, 365)] [int]$LookBackInDays = 30, [Parameter(ParameterSetName = 'List')] [ValidateSet("TopRisk", "CreatedDate", "LastUpdatedDate", "Status", "severity", "name")] [string]$SortByField = "TopRisk", [Parameter(ParameterSetName = 'List')] [ValidateSet("Ascending", "Descending")] [string]$SortOrder = "Descending", [Parameter(ParameterSetName = 'List')] [ValidateRange(1, 1000)] [int]$PageSize = 40, [Parameter(ParameterSetName = 'List')] [ValidateRange(1, [int]::MaxValue)] [int]$PageIndex = 1, [Parameter(ParameterSetName = 'List')] [switch]$DefenderExpertsLicensed, [Parameter(ParameterSetName = 'List')] [switch]$All, [Parameter(ParameterSetName = 'List')] [switch]$Force, [Parameter(Mandatory = $true, ParameterSetName = 'ById')] [int]$IncidentId ) begin { Update-XdrConnectionSettings # Severity translation map $severityMap = @{ 32 = "Information" 64 = "Low" 128 = "Medium" 256 = "High" } } process { # Handle single incident retrieval by ID if ($PSCmdlet.ParameterSetName -eq 'ById') { Write-Verbose "Retrieving incident with ID: $IncidentId" try { $Uri = "https://security.microsoft.com/apiproxy/mtp/incidentQueue/incidents/$IncidentId" $incident = Invoke-RestMethod -Uri $Uri -Method Get -ContentType "application/json" -WebSession $script:session -Headers $script:headers # Add severity name $IncidentSeverity = [int]$incident.Severity if ($severityMap.ContainsKey($IncidentSeverity)) { $incident | Add-Member -NotePropertyName "SeverityName" -NotePropertyValue $severityMap[$IncidentSeverity] -Force } else { $incident | Add-Member -NotePropertyName "SeverityName" -NotePropertyValue "Unknown ($($IncidentSeverity))" -Force } # Add detection source names if ($incident.DetectionSources) { $detectionSourceNames = $incident.DetectionSources | ForEach-Object { ConvertFrom-XdrDetectionSourceId -Id $_ } $incident | Add-Member -NotePropertyName "DetectionSourceNames" -NotePropertyValue $detectionSourceNames -Force } return $incident } catch { throw "Failed to retrieve incident with ID $IncidentId : $($_.Exception.Message)" } } # Handle list retrieval with pagination $allIncidents = @() $currentPageIndex = $PageIndex do { # Build request body $body = @{ isDexLicense = $DefenderExpertsLicensed.IsPresent isStatusFilterEnable = $true isUSXIncidentAssignmentEnabled = $true pageSize = $PageSize isMultipleIncidents = $true lookBackInDays = $LookBackInDays.ToString() filterByLastUpdateTime = $true requestType = $null pageIndex = $currentPageIndex sortOrder = $SortOrder sortByField = $SortByField } if ($TitleSearchTerms) { $body.titleSearchTerms = $TitleSearchTerms } # Create cache key from parameters $cacheKeyParams = @{ LookBackInDays = $LookBackInDays SortByField = $SortByField SortOrder = $SortOrder PageSize = $PageSize PageIndex = $currentPageIndex DefenderExpertsLicensed = $DefenderExpertsLicensed.IsPresent } if ($TitleSearchTerms) { $cacheKeyParams.TitleSearchTerms = $TitleSearchTerms -join "," } $cacheKey = "XdrIncidents_$($cacheKeyParams.GetHashCode())" $currentCacheValue = Get-XdrCache -CacheKey $cacheKey -ErrorAction SilentlyContinue if (-not $Force -and $currentCacheValue.NotValidAfter -gt (Get-Date)) { Write-Verbose "Using cached XDR Incidents (Page $currentPageIndex)" $incidents = $currentCacheValue.Value } elseif ($Force) { Write-Verbose "Force parameter specified, bypassing cache" Clear-XdrCache -CacheKey $cacheKey $incidents = $null } else { Write-Verbose "XDR Incidents cache is missing or expired (Page $currentPageIndex)" $incidents = $null } if (-not $incidents) { Write-Verbose "Retrieving XDR Incidents (Page $currentPageIndex)" try { Write-Verbose "Request body: $(($body | ConvertTo-Json -Compress))" $bodyJson = $body | ConvertTo-Json -Compress $incidents = Invoke-RestMethod -Uri "https://security.microsoft.com/apiproxy/mtp/incidentQueue/incidents/alerts" -Method Post -ContentType "application/json" -Body $bodyJson -WebSession $script:session -Headers $script:headers Set-XdrCache -CacheKey $cacheKey -Value $incidents -TTLMinutes 10 Write-Verbose "Found $($incidents.Count) incidents on page $currentPageIndex" } catch { throw "Failed to retrieve XDR Incidents: $($_.Exception.Message)" } } # Process incidents to add friendly names foreach ($incident in $incidents) { # Add severity name $IncidentSeverity = [int]$incident.Severity if ($severityMap.ContainsKey($IncidentSeverity)) { $incident | Add-Member -NotePropertyName "SeverityName" -NotePropertyValue $severityMap[$IncidentSeverity] -Force } else { $incident | Add-Member -NotePropertyName "SeverityName" -NotePropertyValue "Unknown ($($IncidentSeverity))" -Force } # Add detection source names if ($incident.DetectionSources) { $detectionSourceNames = $incident.DetectionSources | ForEach-Object { ConvertFrom-XdrDetectionSourceId -Id $_ } $incident | Add-Member -NotePropertyName "DetectionSourceNames" -NotePropertyValue $detectionSourceNames -Force } } $allIncidents += $incidents if ($All) { $currentPageIndex++ # If we got fewer results than page size, we've reached the end if ($incidents.Count -lt $PageSize) { break } } else { break } } while ($All) return $allIncidents } end { } } |