Public/Queries/Invoke-FleetSavedQuery.ps1
function Invoke-FleetSavedQuery { <# .SYNOPSIS Executes a saved query and returns results immediately .DESCRIPTION Runs a saved FleetDM query against specified hosts and returns the results directly. Unlike Invoke-FleetQuery which starts a campaign, this function waits for and returns results. The query will stop if targeted hosts haven't responded within the configured timeout period. .PARAMETER QueryId The ID of the saved query to execute .PARAMETER HostId Array of host IDs to run the query on. Accepts pipeline input. .EXAMPLE Invoke-FleetSavedQuery -QueryId 42 -HostId 1,2,3 Runs saved query 42 on hosts 1, 2, and 3 .EXAMPLE Get-FleetHost -Status online | Select-Object -ExpandProperty id | Invoke-FleetSavedQuery -QueryId 15 Runs saved query 15 on all online hosts .EXAMPLE $results = Invoke-FleetSavedQuery -QueryId 10 -HostId 5 $results.results | ForEach-Object { Write-Host "Host $($_.host_id):" $_.rows | Format-Table } Runs query and formats results .LINK https://fleetdm.com/docs/using-fleet/rest-api#run-live-query #> [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateRange(1, [int]::MaxValue)] [int]$QueryId, [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('Id')] [int[]]$HostId ) begin { $hostIds = @() } process { # Collect host IDs from pipeline if ($HostId) { $hostIds += $HostId } } end { if ($hostIds.Count -eq 0) { throw "No host IDs provided" } Write-Verbose "Running saved query $QueryId on $($hostIds.Count) host(s)" $body = @{ host_ids = $hostIds } try { # Note: Timeout is handled by the server-side FLEET_LIVE_QUERY_REST_PERIOD setting Write-Verbose "Note: Query timeout is controlled by server configuration (FLEET_LIVE_QUERY_REST_PERIOD)" $result = Invoke-FleetDMRequest -Endpoint "queries/$QueryId/run" -Method POST -Body $body # Process and format results $formattedResult = [PSCustomObject]@{ PSTypeName = 'FleetDM.QueryResult' QueryId = $result.query_id TargetedHostCount = $result.targeted_host_count RespondedHostCount = $result.responded_host_count ResponseRate = if ($result.targeted_host_count -gt 0) { [Math]::Round(($result.responded_host_count / $result.targeted_host_count) * 100, 2) } else { 0 } Results = @() Errors = @() } # Separate successful results and errors foreach ($hostResult in $result.results) { if ($hostResult.error) { $formattedResult.Errors += [PSCustomObject]@{ PSTypeName = 'FleetDM.QueryError' HostId = $hostResult.host_id Error = $hostResult.error } } else { $formattedResult.Results += [PSCustomObject]@{ PSTypeName = 'FleetDM.QueryHostResult' HostId = $hostResult.host_id Rows = $hostResult.rows RowCount = $hostResult.rows.Count } } } # Display summary Write-Host "Query completed: $($formattedResult.RespondedHostCount)/$($formattedResult.TargetedHostCount) hosts responded ($($formattedResult.ResponseRate)%)" -ForegroundColor Green if ($formattedResult.Errors.Count -gt 0) { Write-Warning "$($formattedResult.Errors.Count) host(s) returned errors" } return $formattedResult } catch { throw $_ } } } |