functions/Get-XdrEndpointConfigurationCustomCollectionRule.ps1
|
function Get-XdrEndpointConfigurationCustomCollectionRule { <# .SYNOPSIS Retrieves custom collection rules for Microsoft Defender for Endpoint. .DESCRIPTION Gets the custom collection rules configured for Microsoft Defender for Endpoint. Custom collection rules allow you to collect specific file, registry, process, and network events based on defined criteria to support advanced hunting and detection scenarios. This function includes caching support with a 30-minute TTL to reduce API calls. It incorporates the same YAML schema as used by Telemetry Collection Manager https://github.com/FalconForceTeam/TelemetryCollectionManager for easy export and version control of custom collection rules. .PARAMETER Output Specifies the output format. Valid values are 'PSObject' (default) and 'YAML'. - PSObject: Returns PowerShell objects - YAML: Returns rules formatted as YAML text for easy export and version control .PARAMETER Force Bypasses the cache and forces a fresh retrieval from the API. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule Retrieves all custom collection rules using cached data if available. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule -Force Forces a fresh retrieval of custom collection rules, bypassing the cache. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule | Where-Object { $_.isEnabled -eq $true } Retrieves only enabled custom collection rules. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule | Where-Object { $_.table -eq "DeviceFileEvents" } | Format-Table ruleName, actionType, platform, isEnabled -AutoSize Retrieves custom collection rules for file events and displays them in a table. .EXAMPLE $rules = Get-XdrEndpointConfigurationCustomCollectionRule $rules | Where-Object { $_.createdBy -eq "admin@contoso.com" } Retrieves all rules created by a specific user. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule | Select-Object ruleName, table, actionType, scope, isEnabled Retrieves custom collection rules and displays key properties. .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule -Output YAML Retrieves custom collection rules in YAML format for export. YAML format is intended to use with https://github.com/FalconForceTeam/TelemetryCollectionManager .EXAMPLE Get-XdrEndpointConfigurationCustomCollectionRule -Output YAML | Out-File "rules.yaml" Exports all custom collection rules to a YAML file. .OUTPUTS Object[] or String When Output is 'PSObject' (default): Returns an array of custom collection rule objects. When Output is 'YAML': Returns a string containing YAML-formatted rules. When Output is 'PSObject' (default): Returns an array of custom collection rule objects containing: - ruleId: Unique identifier for the rule (GUID) - ruleName: Name of the collection rule - ruleDescription: Description of the rule - scope: Rule scope (e.g., "Organization") - isEnabled: Boolean indicating if the rule is active - table: Target table (e.g., DeviceFileEvents, DeviceNetworkEvents) - actionType: Event type to collect (e.g., FileDeleted, ConnectionSuccess) - createdBy: User who created the rule - creationDateTimeUtc: Creation timestamp - lastModifiedBy: User who last modified the rule - lastModificationDateTimeUtc: Last modification timestamp - platform: Target platform (e.g., Windows, Linux, macOS) - filters: Filter criteria for the collection rule - version: Rule version number - updateKey: Optimistic concurrency control key #> [CmdletBinding()] param ( [Parameter()] [ValidateSet('PSObject', 'YAML')] [string]$Output = 'PSObject', [Parameter()] [switch]$Force ) begin { Update-XdrConnectionSettings # Check if ConvertTo-Yaml is available for YAML output if ($Output -eq 'YAML' -and -not (Get-Command ConvertTo-Yaml -ErrorAction SilentlyContinue)) { # Try to import powershell-yaml module if (-not (Get-Module -Name powershell-yaml -ListAvailable)) { throw "YAML output requires either PowerShell 7+ or the 'powershell-yaml' module. Install with: Install-Module -Name powershell-yaml" } Import-Module powershell-yaml -ErrorAction Stop } } process { try { $currentCacheValue = Get-XdrCache -CacheKey "XdrEndpointConfigurationCustomCollectionRule" -ErrorAction SilentlyContinue } catch { $currentCacheValue = $null } if (-not $Force -and $currentCacheValue.NotValidAfter -gt (Get-Date)) { Write-Verbose "Using cached XDR Endpoint custom collection rules" if ($Output -eq 'YAML') { Write-Verbose "Converting custom collection rules to YAML format" return ConvertTo-CustomCollectionYaml -Rules $currentCacheValue.Value } else { return $currentCacheValue.Value } } elseif ($Force) { Write-Verbose "Force parameter specified, bypassing cache" Clear-XdrCache -CacheKey "XdrEndpointConfigurationCustomCollectionRule" } else { Write-Verbose "XDR Endpoint custom collection rules cache is missing or expired" } try { $Uri = "https://security.microsoft.com/apiproxy/mtp/mdeCustomCollection/rules" Write-Verbose "Retrieving XDR Endpoint custom collection rules" $result = Invoke-RestMethod -Uri $Uri -Method Get -ContentType "application/json" -WebSession $script:session -Headers $script:headers } catch { Write-Error "Failed to retrieve custom collection rules: $_" return } if ($null -eq $result) { $result = @() } Write-Verbose "Retrieved $($result.Count) custom collection rule(s)" Set-XdrCache -CacheKey "XdrEndpointConfigurationCustomCollectionRule" -Value $result -TTLMinutes 30 # If YAML output is requested, convert to YAML format if ($Output -eq 'YAML') { Write-Verbose "Converting custom collection rules to YAML format" return ConvertTo-CustomCollectionYaml -Rules $result } else { return $result } } end { } } function ConvertTo-CustomCollectionYaml { <# .SYNOPSIS Converts custom collection rules to YAML format. .DESCRIPTION Internal helper function to convert rule objects to YAML format using ConvertTo-Yaml. .PARAMETER Rules Array of rule objects to convert. #> [OutputType([System.String])] [CmdletBinding()] param ( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$Rules ) if ($Rules.Count -eq 0) { return "# No custom collection rules found" } $yamlOutput = [System.Text.StringBuilder]::new() foreach ($rule in $Rules) { # Add rule header with separator if ($yamlOutput.Length -gt 0) { [void]$yamlOutput.AppendLine("---") } # Prepare rule object for YAML conversion (exclude metadata, only keep schema fields) $yamlRule = [ordered]@{ name = $rule.ruleName enabled = $rule.isEnabled platform = $rule.platform scope = $rule.scope table = $rule.table actionType = $rule.actionType } # Add description if present if (-not [string]::IsNullOrWhiteSpace($rule.ruleDescription)) { $yamlRule.Insert(1, 'description', $rule.ruleDescription) } # Convert filters to simplified format (remove expressionType properties) $yamlRule.filters = ConvertTo-YamlFilterFormat -Expression $rule.filters # Convert to YAML $ruleYaml = ConvertTo-Yaml -Data $yamlRule [void]$yamlOutput.Append($ruleYaml) # Add metadata as comments [void]$yamlOutput.AppendLine("# Metadata:") [void]$yamlOutput.AppendLine("# ruleId: $($rule.ruleId)") [void]$yamlOutput.AppendLine("# createdBy: $($rule.createdBy)") [void]$yamlOutput.AppendLine("# creationDateTimeUtc: $($rule.creationDateTimeUtc)") [void]$yamlOutput.AppendLine("# lastModifiedBy: $($rule.lastModifiedBy)") [void]$yamlOutput.AppendLine("# lastModificationDateTimeUtc: $($rule.lastModificationDateTimeUtc)") [void]$yamlOutput.AppendLine("# version: $($rule.version)") } return $yamlOutput.ToString() } function ConvertTo-YamlFilterFormat { <# .SYNOPSIS Converts API filter format to simplified YAML format. .DESCRIPTION Removes expressionType properties and simplifies the filter structure for YAML export. .PARAMETER Expression The filter expression object to convert. #> [OutputType([System.Collections.Specialized.OrderedDictionary])] [CmdletBinding()] param ( [Parameter(Mandatory)] [object]$Expression ) $result = [ordered]@{ operator = $Expression.operator expressions = @() } foreach ($expr in $Expression.expressions) { if ($expr.expressionType -eq "Predicate") { # Predicate expression - remove expressionType $result.expressions += [ordered]@{ source = $expr.source filter = $expr.filter values = $expr.values } } elseif ($expr.expressionType -eq "Nested") { # Nested group - recurse and wrap in group key $result.expressions += [ordered]@{ group = ConvertTo-YamlFilterFormat -Expression $expr } } } return $result } |