functions/Merge-XdrIncident.ps1

function Merge-XdrIncident {
    <#
    .SYNOPSIS
        Merges multiple incidents into a single incident in Microsoft Defender XDR.

    .DESCRIPTION
        Combines multiple incidents into one incident in Microsoft Defender XDR.
        All incidents must exist before merging. The cmdlet validates each incident ID before proceeding.
        This operation requires confirmation due to its high impact.

    .PARAMETER IncidentIds
        Array of incident IDs to merge. Must contain at least 2 incident IDs.
        All incidents will be validated before the merge operation.

    .PARAMETER Comment
        Comment explaining the reason for merging the incidents.
        This will be recorded in the incident history.
    
    .PARAMETER Confirm
    Prompts for confirmation before executing the merge operation.

    .PARAMETER WhatIf
        Shows what would happen if the cmdlet runs. The JSON body for the merge operation will be displayed.

    .EXAMPLE
        Merge-XdrIncident -IncidentIds 2821, 2823 -Comment "Related phishing attacks"
        Merges incidents 2821 and 2823 with a comment.

    .EXAMPLE
        Merge-XdrIncident -IncidentIds 100, 101, 102 -Comment "Same threat actor campaign"
        Merges three incidents into one.

    .EXAMPLE
        $incidents = 2821, 2823, 2825
        Merge-XdrIncident -IncidentIds $incidents -Comment "Coordinated attack"
        Merges multiple incidents using a variable.

    .OUTPUTS
        Object
        Returns the result of the merge operation from the API.

    .NOTES
        This operation cannot be undone. Use with caution.
        All specified incidents must exist in the tenant.
        The operation requires user confirmation unless -Confirm:$false is specified.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')]
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateCount(2, [int]::MaxValue)]
        [int[]]$IncidentIds,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Comment
    )

    begin {
        Update-XdrConnectionSettings

        # Get current user for AadUserId field
        Write-Verbose "Retrieving current user information"
        try {
            $tenantContext = Get-XdrTenantContext -ErrorAction SilentlyContinue
            $aadUserId = $tenantContext.AuthInfo.UserName
            if (-not $aadUserId) {
                throw "Unable to determine current user principal name from tenant context"
            }
            Write-Verbose "Current user: $aadUserId"
        } catch {
            throw "Failed to retrieve tenant context: $($_.Exception.Message)"
        }
    }

    process {
        # Validate all incidents exist using search (faster than individual Get calls)
        Write-Verbose "Validating incident IDs: $($IncidentIds -join ', ')"
        $validatedIncidents = @()
        $invalidIncidents = @()

        # Build a search term with all incident IDs for batch validation
        foreach ($incidentId in $IncidentIds) {
            Write-Verbose "Validating incident ID: $incidentId"
            try {
                # Use search endpoint for faster validation
                $searchResults = Get-XdrIncidentSearch -Term $incidentId.ToString() -ErrorAction Stop
                $incident = $searchResults | Where-Object { $_.IncidentId -eq $incidentId }
                
                if ($incident) {
                    $validatedIncidents += $incident
                    Write-Verbose "Incident $incidentId validated: $($incident.Title)"
                } else {
                    $invalidIncidents += $incidentId
                    Write-Warning "Incident ID $incidentId not found"
                }
            } catch {
                $invalidIncidents += $incidentId
                Write-Warning "Failed to validate incident ID $incidentId : $($_.Exception.Message)"
            }
        }

        # Check if any incidents were invalid
        if ($invalidIncidents.Count -gt 0) {
            throw "The following incident IDs could not be validated: $($invalidIncidents -join ', '). All incidents must exist before merging."
        }

        if ($validatedIncidents.Count -lt 2) {
            throw "At least 2 valid incidents are required for merging. Only $($validatedIncidents.Count) incident(s) validated successfully."
        }

        Write-Verbose "All $($validatedIncidents.Count) incidents validated successfully"

        # Build incident titles for confirmation message
        $incidentTitles = $validatedIncidents | ForEach-Object { " - [$($_.IncidentId)] $($_.Title)" }
        $confirmMessage = "Merge $($validatedIncidents.Count) incidents:`n$($incidentTitles -join "`n")`n`nComment: $Comment"

        # Build API request body
        $body = @{
            IncidentIds     = $IncidentIds
            Comment         = $Comment
            AadUserId       = $aadUserId
            FeedbackContent = @{
                ClientMergeReasons = @()
            }
        } | ConvertTo-Json -Depth 10

        $Uri = "https://security.microsoft.com/apiproxy/mtp/incidents/merge"

        # If WhatIf is specified, output the JSON body
        if ($WhatIfPreference) {
            Write-Host "JSON Body for merging incidents:"
            Write-Host $body
            return
        }

        if ($PSCmdlet.ShouldProcess($confirmMessage, "Merge incidents")) {
            Write-Verbose "Merging incidents: $($IncidentIds -join ', ')"

            try {
                $result = Invoke-RestMethod -Uri $Uri -Method Post -ContentType "application/json" -Body $body -WebSession $script:session -Headers $script:headers

                Write-Verbose "Successfully merged $($validatedIncidents.Count) incidents"
                return $result
            } catch {
                throw "Failed to merge incidents: $($_.Exception.Message)"
            }
        }
    }

    end {

    }
}