Private/Get-IntunePackageLatestVersion.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    Resolves the latest installer artifact for an App.json definition via its
    Application.Filter expression.
 
.DESCRIPTION
    Invokes the Evergreen or VcRedist filter command stored in
    Application.Filter and returns the highest-version artifact that matches
    the optional Architecture and Language hints. Only Get-EvergreenApp and
    Get-VcList filter expressions are executed; any other expression causes an
    early failure.
 
.PARAMETER DefinitionObject
    The parsed App.json object (PSCustomObject) containing at minimum an
    Application.Filter property.
 
.OUTPUTS
    PSCustomObject with:
        Succeeded : bool
        Version : string - resolved version string
        URI : string - resolved download URI
        ResolvedArtifact : object - the full artifact row from the filter
        FilterExpression : string - the expression that was evaluated
        Error : string - populated on failure
 
.EXAMPLE
    $def = Get-Content '.\App.json' | ConvertFrom-Json
    $result = Get-IntunePackageLatestVersion -DefinitionObject $def
    if ($result.Succeeded) { Write-Host "Latest: $($result.Version)" }
#>

function Get-IntunePackageLatestVersion {
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)]
        [PSCustomObject]$DefinitionObject
    )

    $fail = {
        param([string]$Msg)
        return [PSCustomObject]@{
            Succeeded        = $false
            Version          = ''
            URI              = ''
            ResolvedArtifact = $null
            FilterExpression = ''
            Error            = $Msg
        }
    }

    if ($null -eq $DefinitionObject -or $null -eq $DefinitionObject.Application) {
        return (& $fail 'Definition object is null or has no Application property.')
    }

    $filterExpr = [string]$DefinitionObject.Application.Filter
    if ([string]::IsNullOrWhiteSpace($filterExpr)) {
        return (& $fail 'Application.Filter is empty or missing.')
    }

    # Safety gate: only Evergreen and VcRedist commands are permitted
    if ($filterExpr -notmatch 'Get-EvergreenApp|Get-VcList') {
        return (& $fail "Unsupported filter expression. Only Get-EvergreenApp and Get-VcList are supported. Got: $filterExpr")
    }

    $results = $null
    try {
        $results = @(Invoke-Expression -Command $filterExpr -ErrorAction Stop)
    }
    catch {
        return (& $fail "Filter execution failed: $($_.Exception.Message)")
    }

    if ($null -eq $results -or $results.Count -eq 0) {
        return (& $fail "Filter returned no results for expression: $filterExpr")
    }

    # Apply optional architecture and language preference from definition
    $preferredArch = [string]$DefinitionObject.Application.Architecture
    $preferredLang = [string]$DefinitionObject.Application.Language

    $filtered = @($results)

    if (-not [string]::IsNullOrWhiteSpace($preferredArch)) {
        $archFiltered = @($filtered | Where-Object {
                $_.PSObject.Properties.Name -contains 'Architecture' -and
                [string]$_.Architecture -ieq $preferredArch
            })
        if ($archFiltered.Count -gt 0) {
            $filtered = $archFiltered
        }
    }

    if (-not [string]::IsNullOrWhiteSpace($preferredLang)) {
        $langFiltered = @($filtered | Where-Object {
                $_.PSObject.Properties.Name -contains 'Language' -and
                [string]$_.Language -ieq $preferredLang
            })
        if ($langFiltered.Count -gt 0) {
            $filtered = $langFiltered
        }
    }

    # Select the highest version artifact
    $best = $null
    foreach ($item in $filtered) {
        if ($null -eq $best) {
            $best = $item
            continue
        }

        $candidateRaw = ([string]$item.Version) -replace '^[^0-9]*', '' -replace '[^0-9\.]', ''
        $bestRaw      = ([string]$best.Version) -replace '^[^0-9]*', '' -replace '[^0-9\.]', ''

        if ([string]::IsNullOrWhiteSpace($candidateRaw) -or [string]::IsNullOrWhiteSpace($bestRaw)) {
            continue
        }

        try {
            if ([version]$candidateRaw -gt [version]$bestRaw) {
                $best = $item
            }
        }
        catch {
            # Keep existing best if version parse fails
        }
    }

    if ($null -eq $best) {
        return (& $fail 'No suitable artifact found after applying architecture/language filters.')
    }

    $uriValue = ''
    foreach ($uriPropName in @('URI', 'Uri', 'uri', 'URL', 'Url', 'url', 'DownloadUri', 'DownloadUrl')) {
        if ($best.PSObject.Properties.Name -contains $uriPropName -and
            -not [string]::IsNullOrWhiteSpace([string]$best.$uriPropName)) {
            $uriValue = [string]$best.$uriPropName
            break
        }
    }

    return [PSCustomObject]@{
        Succeeded        = $true
        Version          = [string]$best.Version
        URI              = $uriValue
        ResolvedArtifact = $best
        FilterExpression = $filterExpr
        Error            = ''
    }
}