Public/Search-JuribaAppRKnowledgeBase.ps1
|
function Search-JuribaAppRKnowledgeBase { <# .SYNOPSIS Searches the Juriba Knowledge Base for applications. .DESCRIPTION Searches the Juriba KB for known applications by name, or returns the version/source list for a specific KB application id. Used to find an application before adding it to App Readiness, so the installer can be downloaded directly instead of uploaded by hand. v6 changed the search endpoint contract from a flat `?search=<term>` query that returned a flat array to an OData query (`?$filter=contains(tolower(applicationName),'<term>')&$top=N`) that returns a wrapped `{ paginationMetadata, data: [...] }` envelope. This function speaks the v6 contract first and unwraps the `data` array transparently. If the v6 call fails (e.g. older v5.x instances that still expect `?search=`), it retries against the legacy shape so the same client code works against both. In v6.0.x there is a known server-side regression where every variation of the search endpoint returns HTTP 500 with no body — see the JuribaKB ticket on appr-server. When that's hit, the verbose-stream messages will say so. Per-app sources (`/api/kb/application/{id}/version/sources`) are unaffected. The instance's own API key is used throughout — there is no UDA fallback by default. `-UseUDA` is kept as an explicit escape hatch for users who already have a UDA key, but it is no longer reached automatically. .PARAMETER Instance The URL of the App Readiness instance. Not required if connected via Connect-JuribaAppR. .PARAMETER APIKey The API key for authentication. Not required if connected via Connect-JuribaAppR. .PARAMETER Search The search term to use when querying the Knowledge Base. .PARAMETER ApplicationId Optional. The KB application ID to get version/source details for. .PARAMETER Limit Optional. Maximum number of results to return. Default: 25. Maps to `$top` on v6 and `limit=` on the legacy UDA path. .PARAMETER UseUDA Optional escape hatch — call the UDA API directly (uda.api.juriba.app) instead of the instance-proxied endpoint. Most callers should NOT need this; the AppR instance proxies the same data. Provide `-UDAKey` if your UDA key differs from your AppR key. .PARAMETER UDAKey Optional. Separate UDA API key. Only used when `-UseUDA` is set. Defaults to the AppR connection key (UDA may reject it). .PARAMETER UDAHost Optional. Override the UDA API host. Defaults to "https://uda.api.juriba.app". .EXAMPLE Search-JuribaAppRKnowledgeBase -Search "Firefox" Searches the Juriba KB for applications matching "Firefox". .EXAMPLE Search-JuribaAppRKnowledgeBase -ApplicationId "b5108d80-8ee5-47be-b007-7f12451f0806" Returns version/source details for a specific KB application. #> [CmdletBinding()] [OutputType([object[]])] param ( [Parameter(Mandatory = $false)] [string]$Instance, [Parameter(Mandatory = $false)] [string]$APIKey, [Parameter(Mandatory = $true, ParameterSetName = 'Search')] [string]$Search, [Parameter(Mandatory = $true, ParameterSetName = 'ById')] [string]$ApplicationId, [Parameter(Mandatory = $false)] [int]$Limit = 25, [Parameter(Mandatory = $false)] [switch]$UseUDA, [Parameter(Mandatory = $false)] [string]$UDAKey, [Parameter(Mandatory = $false)] [string]$UDAHost = "https://uda.api.juriba.app" ) $conn = Get-JuribaAppRConnection -Instance $Instance -APIKey $APIKey # Explicit UDA opt-in. Not used as a fallback any more — see the # description block. Caller must pass `-UseUDA` deliberately. if ($UseUDA) { $udaApiKey = if ($UDAKey) { $UDAKey } else { $conn.APIKey } return Invoke-UDARequest -UDAHost $UDAHost -APIKey $udaApiKey ` -Search $Search -ApplicationId $ApplicationId -Limit $Limit } # By-id lookup is the same on v5 and v6 — flat array of source rows # (versionId, version, sourceId, packageType, fileName, fileHash, # architecture, productName, vendor, sourceVersion, downloadUrl). if ($ApplicationId) { $uri = "api/kb/application/$ApplicationId/version/sources" return Invoke-JuribaAppRRestMethod -Instance $conn.Instance -APIKey $conn.APIKey ` -Uri $uri -Method GET } # ── Search ───────────────────────────────────────────────────────── # Try the v6 OData contract first. The escape on the search term # handles single quotes (OData literal escape: '' for '). $needle = ($Search ?? '').ToLower().Replace("'", "''") $filter = "contains(tolower(applicationName),'$needle')" $v6Query = '$filter={0}&$top={1}' -f ` [System.Uri]::EscapeDataString($filter), ` $Limit try { Write-Verbose "KB search (v6 OData): $v6Query" $response = Invoke-JuribaAppRRestMethod -Instance $conn.Instance -APIKey $conn.APIKey ` -Uri ("api/kb/application?$v6Query") -Method GET # Normalise both response shapes into the same flat array of # ApplicationSearchResponseProduct items so callers don't have to # branch on server version. if ($null -eq $response) { return @() } if ($response -is [array]) { return $response } # legacy shape leaked through if ($response.PSObject.Properties['data']) { return @($response.data) } # v6 envelope return @($response) } catch { $msg = $_.Exception.Message Write-Verbose "v6 OData KB search failed ($msg); retrying with legacy v5 ?search= shape." # On v6, the server is documented as OData but currently 500s on # every input (open ticket). On v5 the legacy shape works. # Re-throw with both attempts in the message so a user hitting # the v6 regression sees what's going on. try { $legacyUri = "api/kb/application?search={0}" -f [System.Uri]::EscapeDataString($Search) return Invoke-JuribaAppRRestMethod -Instance $conn.Instance -APIKey $conn.APIKey ` -Uri $legacyUri -Method GET } catch { $legacyMsg = $_.Exception.Message throw "Juriba KB search failed against both v6 OData and legacy ?search= shapes. v6: $msg. legacy: $legacyMsg. If the instance is on v6.0.x, this matches the open server-side regression on /api/kb/application — sister endpoints (/api/kb/application/{id}/version/sources) are unaffected." } } } function Invoke-UDARequest { [CmdletBinding()] param ( [string]$UDAHost, [string]$APIKey, [string]$Search, [string]$ApplicationId, [int]$Limit ) $headers = @{ "X-API-KEY" = $APIKey } $UDAHost = $UDAHost.TrimEnd('/') if ($ApplicationId) { $uri = "$UDAHost/v1/application/$ApplicationId/version/sources" } else { $encodedSearch = [System.Uri]::EscapeDataString($Search) $uri = "$UDAHost/v2/application?search=$encodedSearch&limit=$Limit" } $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET $response } |