functions/public/Export-SplunkData.ps1
<# .Synopsis Returns data from Splunk based on search parameters .DESCRIPTION Returns data from Splunk based on search parameters .PARAMETER Credential Service account username and password with access to the search index being used in Splunk .PARAMETER CloudDeploymentName Name of your Splunk cloud deployment name ie 'illinois' for illinois.splunkcloud.com .PARAMETER Search Splunk search query for the data you would like returned .PARAMETER OutputMode Format of the data to return. Default is CSV and CSVs will output as a file Valid values: (csv | json | json_cols | json_rows | xml) .PARAMETER ConsoleOutput Specify to return the data of the given format to the console. No file will be created. .PARAMETER App Specify the Splunk app to search if required .PARAMETER Timeout Number of minutes to wait for search results before timing out. Default is 5 .PARAMETER EarliestTime Sets the earliest (inclusive), respectively, time bounds for the search. Can be a UTC time or a time relative to now ex: -5h for 5 hours ago. 1 indicates all time. Default is 30m ago .PARAMETER LatestTime Sets the latest (exclusive), respectively, time bounds for the search. Can be a UTC time or a time relative to now ex: -30m for 30m ago. Default is now .PARAMETER Offset Specifies the number of results to return for each Page offsetting by this amount for each Page. Maximum value is 50,000 .PARAMETER MaxResults Use this parameter if the number of results you want returned is greater than 50000. Sets the number of maximum results to return. You must specify an Offset with this parameter. .EXAMPLE Export-SplunkData -CloudDeploymentName 'illinois' -Search 'index=test test_event' -Credential $Credential -ConsoleOutput -EarliestTime '-15m' .EXAMPLE Export-SplunkData -CloudDeploymentName 'illinois' -Search 'index=test | append [ | inputlookup test ]' -Credential $Credential -App 'illinois-urbana-security-techsvc-APP' Note like in the above example, search commands that begin with | such as inputlookup and mstats must be fed a dummy index and an append to complete the search succesfully with the API. https://github.com/splunk/splunk-tableau-wdc/issues/6#issuecomment-499229594 #> function Export-SplunkData { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential]$Credential, [Parameter(Mandatory=$true)] [String]$CloudDeploymentName, [Parameter(Mandatory=$true)] [String]$Search, [ValidateSet("csv","json","json_cols","json_rows","xml")] [String]$OutputMode = "csv", [Switch]$ConsoleOutput, [String]$App, [Int]$Timeout = 5, [String]$EarliestTime = '-30m', [String]$LatestTime, [ValidateRange(1,50000)] [int]$Offset, [int]$MaxResults ) process { #Validate that Pages and Offset are set together If($MaxResults -and -not $Offset){ Write-Error "MaxResults must be specified with Offset" } #Set the Base URI depending on whether or not an app was specified If($App){ $BaseURI = "https://$($CloudDeploymentName).splunkcloud.com:8089/servicesNS/$($Credential.UserName)/$($App)" } Else{ $BaseURI = "https://$($CloudDeploymentName).splunkcloud.com:8089/services" } #Create the search, this returns an SID for the search $IVRSplat = @{ Credential = $Credential Method = 'POST' URI = "$($BaseURI)/search/jobs" Body = @{ search = "search $($Search)" output_mode = 'json' earliest_time = $EarliestTime latest_time = $LatestTime } } If($MaxResults){ $IVRSplat.Body["max_count"] = $MaxResults } $SearchJob = Invoke-RestMethod @IVRSplat #Check the status of the search to ensure it is finished before we get the results $IVRSplat = @{ Credential = $Credential Method = 'GET' URI = "$($BaseURI)/search/jobs/$($SearchJob.sid)/" Body = @{ output_mode = 'json' } } $SearchMetaData = Invoke-RestMethod @IVRSplat $Status = $SearchMetaData.entry.content.dispatchState $Seconds = 0 #Wait for the search to parse and keep checking its status until it's no longer running or the timeout elapses While((($Status -eq 'PARSING') -or ($Status -eq 'RUNNING')) -and ($Seconds -le ($Timeout*60))){ Start-Sleep -Seconds 5 $Seconds += 5 Write-Verbose -Message 'Search is still running...' $SearchMetaData = Invoke-RestMethod @IVRSplat $Status = $SearchMetaData.entry.content.dispatchState } If($Seconds -ge ($Timeout*60)){ If($Status -eq 'RUNNING'){ Throw "Search timeout has elapsed while the search was still running. Try increasing the timeout." } Else{ Throw "Search timeout has elapsed. Try increasing the timeout. The status of your search at the time of this error was: $($Status)" } } If($Status -eq 'FAILED'){ Throw "Search has FAILED. `n $($SearchMetaData.entry.Content.messages.text)" } ElseIf($Status -ne 'DONE'){ Throw "Search did not complete successfully. The status of your search is $($Status). `n $($SearchMetaData.entry.Content.messages.text)" } #Now that the search is 'DONE', use the SID for our search to get the results if($Offset){ [int]$Index=0 [int]$NewOffset=0 $Pages = [math]::Ceiling($MaxResults/$Offset) While($Index -lt $Pages){ $NewOffset = $Index * $Offset $IVRSplat = @{ Credential = $Credential Method = 'GET' URI = "$($BaseURI)/search/jobs/$($SearchJob.sid)/results?offset=$($NewOffset)" Body = @{ output_mode = $OutputMode count = '0' } } $Results = Invoke-RestMethod @IVRSplat $Index++ #Return results If(!($Results)){ Write-Output -InputObject "No results" } ElseIf($ConsoleOutput){ $Results } ElseIf($OutputMode -eq 'csv'){ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).csv" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).csv" } ElseIf($OutputMode -like 'json*'){ $Results | ConvertTo-Json -Depth 10 | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).json" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).json" } ElseIf($OutputMode -eq 'xml'){ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).xml" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).xml" } else{ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss)" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss)" } } } Else{ $IVRSplat = @{ Credential = $Credential Method = 'GET' URI = "$($BaseURI)/search/jobs/$($SearchJob.sid)/results" Body = @{ output_mode = $OutputMode count = '0' } } $Results = Invoke-RestMethod @IVRSplat #Return results If(!($Results)){ Write-Output -InputObject "No results" } ElseIf($ConsoleOutput){ $Results } ElseIf($OutputMode -eq 'csv'){ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).csv" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).csv" } ElseIf($OutputMode -like 'json*'){ $Results | ConverTo-Json -Depth 10 | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).json" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).json" } ElseIf($OutputMode -eq 'xml'){ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).xml" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss).xml" } else{ $Results | Out-File -Path ".\SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss)" Write-Output -InputObject "SearchResults_$(Get-Date -Format yyyyMMdd-HHmmss)" } } } end { } } |