Public/Core/Invoke-FleetDMMethod.ps1
|
function Invoke-FleetDMMethod { <# .SYNOPSIS Invokes a custom FleetDM API method .DESCRIPTION Provides direct access to any FleetDM API endpoint not covered by specific cmdlets. This is useful for accessing new or undocumented API endpoints. .PARAMETER Endpoint The API endpoint path (without /api/v1/fleet/ prefix) .PARAMETER Method The HTTP method to use (GET, POST, PUT, PATCH, DELETE) .PARAMETER Body The request body as a hashtable (will be converted to JSON) .PARAMETER QueryParameters Query parameters as a hashtable .PARAMETER FollowPagination Automatically follow pagination to retrieve all results (for GET requests) .PARAMETER MaxRetries Maximum number of additional attempts after the first request. The default is 3 when this is omitted. HTTP 429 is retried for every method. HTTP 502, 503, and 504 are retried for GET. Gateway retries wait 2, 4, then 8 seconds. A 429, and a gateway response that sends one, waits for Retry-After or for "retry after: Ns" in the error. Each wait is capped by -MaxRetryDelaySeconds. .PARAMETER MaxRetryDelaySeconds Longest wait before one retry, in seconds. The default is 120 when this is omitted. Retry-After and the backoff cannot sleep longer than this. .PARAMETER RetryNonIdempotent Also retry POST, PUT, PATCH, and DELETE after HTTP 502, 503, or 504. HTTP 429 is retried without this switch. .PARAMETER Raw Return the raw response object without processing .EXAMPLE Invoke-FleetDMMethod -Endpoint "config" -Method GET Gets the FleetDM configuration .EXAMPLE Invoke-FleetDMMethod -Endpoint "users" -Method GET -QueryParameters @{query = "admin"} Searches for users with "admin" in their name .EXAMPLE $body = @{ name = "New Team" description = "Created via API" } Invoke-FleetDMMethod -Endpoint "teams" -Method POST -Body $body Creates a new team .EXAMPLE Invoke-FleetDMMethod -Endpoint "hosts/123/refetch" -Method POST Triggers a refetch for host ID 123 .EXAMPLE Invoke-FleetDMMethod -Endpoint "labels" -Method GET -FollowPagination Gets all labels, automatically following pagination .EXAMPLE Invoke-FleetDMMethod -Endpoint "hosts" -MaxRetries 0 Sends one GET and does not retry HTTP 429 or a gateway error. .EXAMPLE Invoke-FleetDMMethod -Endpoint "hosts/123/refetch" -Method POST -RetryNonIdempotent Retries that POST after HTTP 502, 503, or 504. Leave the switch off when repeating the call could apply the change twice. HTTP 429 is retried either way. .LINK https://fleetdm.com/docs/using-fleet/rest-api #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Endpoint, [Parameter()] [ValidateSet('GET', 'POST', 'PUT', 'PATCH', 'DELETE')] [string]$Method = 'GET', [Parameter()] [hashtable]$Body, [Parameter()] [hashtable]$QueryParameters, [Parameter()] [switch]$FollowPagination, [Parameter()] [ValidateRange(0, 100)] [int]$MaxRetries = 3, [Parameter()] [ValidateRange(1, 2147483)] [int]$MaxRetryDelaySeconds = 120, [Parameter()] [switch]$RetryNonIdempotent, [Parameter()] [switch]$Raw ) process { Write-Verbose "Invoking FleetDM method: $Method $Endpoint" # Validate that we can use FollowPagination if ($FollowPagination -and $Method -ne 'GET') { Write-Warning "FollowPagination is only supported for GET requests. Ignoring parameter." $FollowPagination = $false } # Build parameters for Invoke-FleetDMRequest $requestParams = @{ Endpoint = $Endpoint Method = $Method } if ($Body) { $requestParams['Body'] = $Body Write-Verbose "Request body: $(Get-FleetRedactedLogText -Text $Body)" } if ($QueryParameters) { $requestParams['QueryParameters'] = $QueryParameters Write-Verbose "Query parameters: $(Get-FleetRedactedLogText -Text $QueryParameters)" } if ($FollowPagination) { $requestParams['FollowPagination'] = $true } # Pass these only when the caller set them. The request function owns the # defaults, and callers that mock it declare a fixed parameter list. if ($PSBoundParameters.ContainsKey('MaxRetries')) { $requestParams['MaxRetries'] = $MaxRetries } if ($PSBoundParameters.ContainsKey('MaxRetryDelaySeconds')) { $requestParams['MaxRetryDelaySeconds'] = $MaxRetryDelaySeconds } if ($RetryNonIdempotent) { $requestParams['RetryNonIdempotent'] = $true } if ($Method -ne 'GET' -and -not $PSCmdlet.ShouldProcess($Endpoint, $Method)) { return } try { $result = Invoke-FleetDMRequest @requestParams Write-Verbose "Request completed successfully" # Try to add type information if we can identify the object type if (-not $Raw -and $result) { # For collections, add type information to the nested data if ($result.PSObject.Properties.Name -contains 'hosts') { $result.hosts | Add-FleetTypeName -TypeName 'FleetDM.Host' } elseif ($result.PSObject.Properties.Name -contains 'policies') { $result.policies | Add-FleetTypeName -TypeName 'FleetDM.Policy' } elseif ($result.PSObject.Properties.Name -contains 'queries') { $result.queries | Add-FleetTypeName -TypeName 'FleetDM.Query' } elseif ($result.PSObject.Properties.Name -contains 'software') { $result.software | Add-FleetTypeName -TypeName 'FleetDM.Software' } elseif ($result.PSObject.Properties.Name -contains 'users') { $result.users | Add-FleetTypeName -TypeName 'FleetDM.User' } elseif ($result.PSObject.Properties.Name -contains 'teams') { $result.teams | Add-FleetTypeName -TypeName 'FleetDM.Team' } elseif ($result.PSObject.Properties.Name -contains 'labels') { $result.labels | Add-FleetTypeName -TypeName 'FleetDM.Label' } # For single objects elseif ($result.PSObject.Properties.Name -contains 'host') { $result.host | Add-FleetTypeName -TypeName 'FleetDM.Host' } elseif ($result.PSObject.Properties.Name -contains 'policy') { $result.policy | Add-FleetTypeName -TypeName 'FleetDM.Policy' } elseif ($result.PSObject.Properties.Name -contains 'query') { $result.query | Add-FleetTypeName -TypeName 'FleetDM.Query' } elseif ($result.PSObject.Properties.Name -contains 'user') { $result.user | Add-FleetTypeName -TypeName 'FleetDM.User' } elseif ($result.PSObject.Properties.Name -contains 'team') { $result.team | Add-FleetTypeName -TypeName 'FleetDM.Team' } elseif ($result.PSObject.Properties.Name -contains 'label') { $result.label | Add-FleetTypeName -TypeName 'FleetDM.Label' } } return $result } catch { Write-Error "Failed to invoke FleetDM method: $_" throw } } } |