functions/Set-XdrAdvancedHuntingFunction.ps1
|
function Set-XdrAdvancedHuntingFunction { <# .SYNOPSIS Updates an existing Advanced Hunting function in Microsoft Defender XDR. .DESCRIPTION Updates a saved function for Advanced Hunting queries in Microsoft Defender XDR. The function must exist before it can be updated. The cmdlet will verify the function exists before attempting the update. .PARAMETER Id The ID of the function to update. This is mandatory to ensure the correct function is updated. .PARAMETER Name The new name of the function. If not specified, the existing name is preserved. .PARAMETER KQLQuery The new KQL (Kusto Query Language) body of the function. If not specified, the existing query is preserved. .PARAMETER Description The new description of the function. If not specified, the existing description is preserved. .PARAMETER IsShared Switch to make the function shared with the organization. If not specified, the existing sharing status is preserved. .PARAMETER FolderPath The new folder path for organizing the function. Use forward slashes (/) or backslashes (\) - they will be automatically converted to double backslashes. If not specified, the existing path is preserved. .PARAMETER InputObject PSObject containing the function to update. The object must include an Id property. Typically obtained from Get-XdrAdvancedHuntingFunction. .PARAMETER WhatIf Shows what would happen if the cmdlet runs. The function is not created. .PARAMETER Confirm Prompts you for confirmation before running the cmdlet. .EXAMPLE Set-XdrAdvancedHuntingFunction -Id 6 -Name "UpdatedFunctionName" Updates the name of function with ID 6. .EXAMPLE Set-XdrAdvancedHuntingFunction -Id 6 -KQLQuery $newQuery -Description "Updated description" Updates the query and description of a function. .EXAMPLE $function = Get-XdrAdvancedHuntingFunction -Id 6 $function.IsShared = $false Set-XdrAdvancedHuntingFunction -InputObject $function Gets a function, modifies it, and updates it. .EXAMPLE Set-XdrAdvancedHuntingFunction -Id 6 -IsShared -FolderPath "NewFolder/SubFolder" Makes a function shared and moves it to a new folder path. .OUTPUTS Object Returns the updated function object from the API. .NOTES The function must exist before it can be updated. All unspecified parameters will preserve their existing values. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding(DefaultParameterSetName = 'Parameters', SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] [int]$Id, [Parameter(ParameterSetName = 'Parameters')] [string]$Name, [Parameter(ParameterSetName = 'Parameters')] [string]$KQLQuery, [Parameter(ParameterSetName = 'Parameters')] [string]$Description, [Parameter(ParameterSetName = 'Parameters')] [switch]$IsShared, [Parameter(ParameterSetName = 'Parameters')] [string]$FolderPath, [Parameter(Mandatory = $true, ParameterSetName = 'InputObject', ValueFromPipeline = $true)] [object]$InputObject ) begin { Update-XdrConnectionSettings } process { try { if ($PSCmdlet.ParameterSetName -eq 'InputObject') { # Extract parameters from InputObject if (-not $InputObject.Id) { throw "InputObject must contain an 'Id' property. Ensure you're passing an object from Get-XdrAdvancedHuntingFunction." } $Id = $InputObject.Id } # Verify the function exists by forcing a fresh retrieval Write-Verbose "Verifying function with ID $Id exists" $existingFunction = Get-XdrAdvancedHuntingFunction -Id $Id -Force if (-not $existingFunction) { throw "No Advanced Hunting function found with ID '$Id'. Use New-XdrAdvancedHuntingFunction to create a new function." } # Build the update body based on parameter set if ($PSCmdlet.ParameterSetName -eq 'InputObject') { # Use values from InputObject $functionName = $InputObject.Name $functionBody = $InputObject.Body $functionDescription = if ($InputObject.Description) { $InputObject.Description } else { "" } $functionIsShared = $InputObject.IsShared $functionPath = if ($InputObject.Path) { $InputObject.Path } else { "" } $functionInputParameters = if ($InputObject.InputParameters) { $InputObject.InputParameters } else { @() } } else { # Use provided parameters or existing values $functionName = if ($PSBoundParameters.ContainsKey('Name')) { $Name } else { $existingFunction.Name } $functionBody = if ($PSBoundParameters.ContainsKey('KQLQuery')) { $KQLQuery } else { $existingFunction.Body } $functionDescription = if ($PSBoundParameters.ContainsKey('Description')) { $Description } else { if ($existingFunction.Description) { $existingFunction.Description } else { "" } } $functionIsShared = if ($PSBoundParameters.ContainsKey('IsShared')) { $IsShared.IsPresent } else { $existingFunction.IsShared } # Handle folder path if ($PSBoundParameters.ContainsKey('FolderPath')) { if (-not [string]::IsNullOrWhiteSpace($FolderPath)) { # Replace forward slashes with backslashes first $functionPath = $FolderPath -replace '/', '\' # Then double the backslashes for JSON $functionPath = $functionPath -replace '\\', '\\' } else { $functionPath = "" } } else { $functionPath = if ($existingFunction.Path) { $existingFunction.Path } else { "" } } $functionInputParameters = if ($existingFunction.InputParameters) { $existingFunction.InputParameters } else { @() } } # Build API request body $body = @{ Id = $Id Name = $functionName Path = $functionPath Description = $functionDescription InputParameters = $functionInputParameters IsShared = $functionIsShared Body = $functionBody } | ConvertTo-Json -Depth 10 $Uri = "https://security.microsoft.com/apiproxy/mtp/huntingService/savedFunctions/$Id" # If WhatIf is specified, output the JSON body if ($WhatIfPreference) { Write-Host "JSON Body for function '$functionName' (ID: $Id):" Write-Host $body return } if ($PSCmdlet.ShouldProcess("$functionName (ID: $Id)", "Update Advanced Hunting function")) { Write-Verbose "Updating Advanced Hunting function: $functionName (ID: $Id)" $result = Invoke-RestMethod -Uri $Uri -Method PATCH -ContentType "application/json" -Body $body -WebSession $script:session -Headers $script:headers # Clear the cache for the Get cmdlet Clear-XdrCache -CacheKey "XdrAdvancedHuntingFunction" -ErrorAction SilentlyContinue Write-Verbose "Successfully updated function with ID: $($result.Id)" Write-Host $result } } catch { Write-Error "Failed to update Advanced Hunting function with ID '$Id': $($_.Exception.Message)" } } end { } } |