Public/Software/Get-FleetSoftware.ps1
function Get-FleetSoftware { <# .SYNOPSIS Retrieves software inventory from FleetDM .DESCRIPTION Gets software inventory information from FleetDM. Can retrieve all software or filter by various criteria. Software inventory includes installed applications, versions, and vulnerability information. .PARAMETER Id The specific software ID to retrieve .PARAMETER Name Filter software by name (partial match) .PARAMETER Version Filter software by version .PARAMETER Cve Filter software by CVE (Common Vulnerabilities and Exposures) ID .PARAMETER VulnerableOnly Only return software with known vulnerabilities .PARAMETER Page Page number for pagination (0-based) .PARAMETER PerPage Number of results per page (default: 100) .PARAMETER OrderKey Sort results by this field (name, hosts_count, cve_published, cve_resolved) .PARAMETER OrderDirection Sort direction (asc or desc) .EXAMPLE Get-FleetSoftware Gets all software inventory .EXAMPLE Get-FleetSoftware -Name "Chrome" Gets all software with "Chrome" in the name .EXAMPLE Get-FleetSoftware -VulnerableOnly Gets only software with known vulnerabilities .EXAMPLE Get-FleetSoftware -Cve "CVE-2023-1234" Gets software affected by specific CVE .LINK https://fleetdm.com/docs/using-fleet/rest-api#list-software #> [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'ById', Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateRange(1, [int]::MaxValue)] [int]$Id, [Parameter(ParameterSetName = 'List')] [string]$Name, [Parameter(ParameterSetName = 'List')] [string]$Version, [Parameter(ParameterSetName = 'List')] [string]$Cve, [Parameter(ParameterSetName = 'List')] [switch]$VulnerableOnly, [Parameter(ParameterSetName = 'List')] [int]$Page, [Parameter(ParameterSetName = 'List')] [ValidateRange(1, 500)] [int]$PerPage = 100, [Parameter(ParameterSetName = 'List')] [ValidateSet('name', 'hosts_count', 'cve_published', 'cve_resolved')] [string]$OrderKey, [Parameter(ParameterSetName = 'List')] [ValidateSet('asc', 'desc')] [string]$OrderDirection = 'asc' ) process { if ($PSCmdlet.ParameterSetName -eq 'ById') { # Get specific software $endpoint = "software/$Id" Write-Verbose "Retrieving software with ID: $Id" try { $result = Invoke-FleetDMRequest -Endpoint $endpoint -Method GET # Add custom type for formatting if ($result.software) { $result.software.PSObject.TypeNames.Insert(0, 'FleetDM.Software') return $result.software } else { Write-Warning "No software data returned for ID: $Id" return $null } } catch { if ($_.Exception.Message -like "*not found*") { Write-Warning "Software with ID $Id not found" return $null } throw } } else { # List software with filters $endpoint = "software" $queryParams = @{ per_page = $PerPage } # Add optional parameters if ($PSBoundParameters.ContainsKey('Page')) { $queryParams['page'] = $Page } if ($VulnerableOnly) { $queryParams['vulnerable'] = 'true' } if ($OrderKey) { $queryParams['order_key'] = $OrderKey $queryParams['order_direction'] = $OrderDirection } # Server-side filtering parameters if ($Name) { $queryParams['query'] = $Name } if ($Version) { # Note: API might not support version filtering directly Write-Verbose "Version filtering will be applied client-side" } if ($Cve) { # Note: API might require different parameter name $queryParams['cve'] = $Cve } Write-Verbose "Query parameters: $($queryParams | ConvertTo-Json -Compress)" # Determine if we should follow pagination $followPagination = -not $PSBoundParameters.ContainsKey('Page') if ($followPagination) { $result = Invoke-FleetDMRequest -Endpoint $endpoint -QueryParameters $queryParams -FollowPagination } else { $response = Invoke-FleetDMRequest -Endpoint $endpoint -QueryParameters $queryParams # Handle response structure - API returns object with software array if ($response -and $response.PSObject.Properties.Name -contains 'software') { $result = $response.software } else { $result = @() } } # Apply client-side filtering if needed if ($Version -and $result) { $result = $result | Where-Object { $_.version -like "*$Version*" } Write-Verbose "Filtered to $($result.Count) software items matching version '*$Version*'" } # Add custom type for formatting if ($result) { for ($i = 0; $i -lt $result.Count; $i++) { $result[$i].PSObject.TypeNames.Insert(0, 'FleetDM.Software') # Add calculated properties if ($result[$i].vulnerabilities) { $cveCount = @($result[$i].vulnerabilities).Count Add-Member -InputObject $result[$i] -MemberType NoteProperty -Name 'cve_count' -Value $cveCount -Force # Find highest severity - handle cases where severity might be missing $severities = @($result[$i].vulnerabilities | Where-Object { $_.severity } | ForEach-Object { $_.severity }) $highestSeverity = if ($severities.Count -eq 0 -and $result[$i].vulnerabilities.Count -gt 0) { # Has vulnerabilities but no severity info - default to 'medium' 'medium' } elseif ($severities -contains 'critical') { 'critical' } elseif ($severities -contains 'high') { 'high' } elseif ($severities -contains 'medium') { 'medium' } elseif ($severities -contains 'low') { 'low' } else { 'none' } Add-Member -InputObject $result[$i] -MemberType NoteProperty -Name 'highest_severity' -Value $highestSeverity -Force } else { Add-Member -InputObject $result[$i] -MemberType NoteProperty -Name 'cve_count' -Value 0 -Force Add-Member -InputObject $result[$i] -MemberType NoteProperty -Name 'highest_severity' -Value 'none' -Force } } } Write-Verbose "Retrieved $($result.Count) software items" return $result } } } |