function Search-Graylog { <# .SYNOPSIS Queries Graylog for log data using the provided query and log stream name. .DESCRIPTION Query Graylog for log data using the provided query and log stream name. The query should contain the key:value pairs to search for, and the key should be the CASE-SENSITIVE field name to search within. .PARAMETER Query The search query to execute, should contain the key:value pairs to search for. Example: "EventID:4740 && TargetUserName:ab123456" will search for all account lockouts for the user ab123456. (Note that the LogId would need to be changed to the unique identifier for the Active Directory log stream in the above example) .PARAMETER TimeSpan The time span to search within, defaults to 7 days. .PARAMETER LogName The name of the log stream to search within, defaults to "Windows Security". .PARAMETER Limit The maximum number of results to return, defaults to 150. .PARAMETER SortField The field to sort the results by, defaults to "timestamp". .PARAMETER SortOrder The order to sort the results by, defaults to "desc". .PARAMETER AsJob An optional switch to run the search job as a background job. .PARAMETER Detailed An optional switch to return the search job details instead of the results (only does anything when -AsJob is not used). .OUTPUTS A PSCustomObject containing the SearchId, QueryId, and FilterId of the search job. .EXAMPLE Start-GraylogJob -Query "EventID:4740 && TargetUserName:ab123456" Starts a search job for all account lockouts for the user ab123456. .NOTES A identifier for various parts of the search job (SearchId, QueryId, FilterId) are generated and returned in a PSCustomObject, which can be used to retrieve the results of the search job. The SearchId, QueryId, and FilterId are used to retrieve the results of the search job using the Receive-GraylogJob function. #> [Alias("Search-Graylog")] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Query, [Parameter()] [TimeSpan] $TimeSpan = [TimeSpan]::FromDays(7), [Parameter()] [ValidateSet("Infoblox", "Infoblox DNS", "Windows Application", "Windows Security", "Windows System")] [string] $LogName = "Windows Security", [Parameter()] [int] $Limit = 150, [Parameter()] [string] $SortField = "timestamp", [Parameter()] [ValidateSet("desc", "asc")] [string] $SortOrder = "desc", [Parameter()] [switch] $AsJob, [Parameter()] [switch] $Detailed ) $LogId = Get-GraylogLogStreamId -LogName $LogName if ($null -eq $LogId) { throw "The log stream '$LogName' does not exist." } $SearchId = [String]::Join('', [GUID]::NewGUID().GUID.Replace("-", "")[0..23]) # Generate a unique identifier for the search $QueryId = [GUID]::NewGUID().GUID.ToString() # Generate a unique identifier for the query $FilterId = [GUID]::NewGUID().GUID.ToString() # Generate a unique identifier for the filter $Request = @{ Method = "POST" Path = "/views/search" Body = ConvertTo-JSON -Depth 7 @{ id = $SearchId queries = @( @{ id = $QueryId query = @{ type = "elasticsearch" query_string = $Query } timerange = @{ type = "relative" from = $TimeSpan.TotalSeconds } filter = @{ type = "or" filters = @(@{ type = "stream" id = $LogId }) } filters = @() search_types = @(@{ id = $FilterId query = $null timerange = $null offset = 0 streams = @() decorators = @() type = "messages" limit = $Limit filters = @() sort = @(@{ field = $SortField.ToLower() order = $SortOrder.ToUpper() }) }) } ) parameters = @() } } $QuerySuccess = $true try { $null = Invoke-GraylogRequest @Request } catch { $QuerySuccess = $false } if ($AsJob) { return [PSCustomObject]@{ Success = $QuerySuccess SearchId = $SearchId QueryId = $QueryId FilterId = $FilterId Request = $Request } } else { $RetrievalSuccess = $true try { $Data = Receive-GraylogSearchJob -SearchId $SearchId -QueryId $QueryId -FilterId $FilterId } catch { $RetrievalSuccess = $false } if (-NOT $Detailed) { return $Data } else { return [PSCustomObject]@{ QuerySuccess = $QuerySuccess RetrievalSuccess = $RetrievalSuccess Data = $Data SearchId = $SearchId QueryId = $QueryId FilterId = $FilterId Request = $Request } } } }