private/Get-WinPEDriverPackageCore.ps1

#Requires -PSEdition Core

function Get-WinPEDriverPackageCore {
    <#
    .SYNOPSIS
        Gets normalized WinPE driver package metadata
 
    .DESCRIPTION
        Resolves active WinPE driver sources from the global module configuration. Static
        sources obtain metadata directly from that configuration. Dynamic sources refresh
        their catalog entries unless SkipCatalogRefresh is specified, then combine catalog
        metadata with configured architecture and expansion settings. Missing, disabled, or
        unresolved sources are skipped with warning or verbose output.
 
    .PARAMETER Name
        Specifies one or more configured source names. The positional parameter includes
        argument completion for active sources. When omitted, all enabled sources with an
        UpdateUri or DownloadUri are processed.
 
    .PARAMETER SkipCatalogRefresh
        Prevents Update-OSDeployCoreDriversCatalog from refreshing requested dynamic source
        entries. Existing user catalog data is still loaded and must already be current.
 
    .EXAMPLE
        PS> Get-WinPEDriverPackageCore -Name 'dell','hp' -SkipCatalogRefresh
 
        Returns normalized metadata for the configured Dell and HP sources without
        refreshing their dynamic catalog entries.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns zero or more objects with the
        type name OSDeployWinPEDriver.Package and Name, Architecture, UpdateUri,
        ExpandCommand, ReadmeUri, Id, PackageId, Version, ReleaseDate, FileName, FileSizeMB,
        DownloadUri, and Checksums properties.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 0.1.0
        Date: 2026-08-28
 
        Dependencies:
          Module Functions: Update-OSDeployCoreDriversCatalog for dynamic catalog refreshes
          DotNet Classes: System.Management.Automation.CompletionResult,
                          System.Management.Automation.PSCustomObject
    #>

    [CmdletBinding()]
    [OutputType('OSDeployWinPEDriver.Package')]
    param (
        [Parameter(Position = 0)]
        [ArgumentCompleter({
            param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
            $global:OSDeployModule.WinPEDrivers.PSObject.Properties |
                Where-Object { ($_.Value.UpdateUri -or $_.Value.DownloadUri) -and -not $_.Value.Disabled -and $_.Name -like "$wordToComplete*" } |
                ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.Name) }
        })]
        [string[]]$Name,

        [Parameter()]
        [switch]$SkipCatalogRefresh
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Starting"

        $catalog = $null
    }

    process {
        if (-not $Name) {
            $Name = $global:OSDeployModule.WinPEDrivers.PSObject.Properties |
                Where-Object { ($_.Value.UpdateUri -or $_.Value.DownloadUri) -and -not $_.Value.Disabled } |
                Select-Object -ExpandProperty Name
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] No -Name specified — resolving all active sources: $($Name -join ', ')"
        }
        else {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Processing requested source(s): $($Name -join ', ')"
        }

        $dynamicTargets = @(
            foreach ($sourceName in $Name) {
                $source = $global:OSDeployModule.WinPEDrivers.$sourceName
                if ($source -and $source.UpdateUri) {
                    $sourceName
                }
            }
        )

        if ($dynamicTargets -and -not $SkipCatalogRefresh) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Refreshing dynamic catalog entries: $($dynamicTargets -join ', ')"
            Update-OSDeployCoreDriversCatalog -Name $dynamicTargets | Out-Null
        }
        elseif ($dynamicTargets) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] SkipCatalogRefresh specified — assuming catalog entries are current for: $($dynamicTargets -join ', ')"
        }
        else {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] No dynamic sources requested — catalog refresh skipped"
        }

        $hasDynamic = $global:OSDeployModule.WinPEDrivers.PSObject.Properties |
            Where-Object { $_.Value.UpdateUri }

        if ($hasDynamic) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Loading catalog from '$Script:OSDeployWinPEDriversUserConfig'"
            if (Test-Path -Path $Script:OSDeployWinPEDriversUserConfig) {
                $catalog = Get-Content -Path $Script:OSDeployWinPEDriversUserConfig -Raw | ConvertFrom-Json
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] Catalog loaded successfully"
            }
            else {
                Write-Warning "[$(Get-Date -Format s)] Catalog not found at '$Script:OSDeployWinPEDriversUserConfig'. Run Update-OSDeployCoreDrivers to generate it."
            }
        }
        else {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] No Dynamic sources — catalog load skipped"
        }

        foreach ($n in $Name) {
            $sourceData = $global:OSDeployModule.WinPEDrivers.$n
            if (-not $sourceData) {
                Write-Warning "[$(Get-Date -Format s)] '$n' not found in winpedrivers.json"
                continue
            }

            if ($sourceData.Disabled) {
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$n' — Disabled, skipping"
                continue
            }

            $arch = $sourceData.Architecture
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$n' — Architecture='$arch'"

            if ($sourceData.DownloadUri) {
                Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$n' — Reading metadata from winpedrivers.json (Static)"
                [PSCustomObject]@{
                    PSTypeName    = 'OSDeployWinPEDriver.Package'
                    Name          = $n
                    Architecture  = $arch
                    UpdateUri    = $null
                    ExpandCommand = $sourceData.ExpandCommand
                    ReadmeUri     = $null
                    Id            = $n
                    PackageId     = $sourceData.PackageId
                    Version       = $null
                    ReleaseDate   = $null
                    FileName      = $sourceData.FileName
                    FileSizeMB    = $sourceData.FileSizeMB
                    DownloadUri   = $sourceData.DownloadUri
                    Checksums     = [PSCustomObject]@{}
                }
            }
            elseif ($sourceData.UpdateUri) {
                if (-not $catalog) {
                    Write-Warning "[$(Get-Date -Format s)] No catalog available for Dynamic source '$n'. Run Update-OSDeployCoreDrivers."
                    continue
                }

                Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$n' — Looking up catalog entry"
                $catalogEntry = $catalog.Sources.$n

                if (-not $catalogEntry) {
                    Write-Warning "[$(Get-Date -Format s)] No catalog entry for '$n'. Run Update-OSDeployCoreDrivers."
                    continue
                }

                Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$n' — Catalog entry found: PackageId='$($catalogEntry.PackageId)' Version='$($catalogEntry.Version)' ReleaseDate='$($catalogEntry.ReleaseDate)'"
                [PSCustomObject]@{
                    PSTypeName    = 'OSDeployWinPEDriver.Package'
                    Name          = $n
                    Architecture  = $arch
                    UpdateUri    = $sourceData.UpdateUri
                    ExpandCommand = $sourceData.ExpandCommand
                    ReadmeUri     = $catalogEntry.ReadmeUri
                    Id            = $n
                    PackageId     = $catalogEntry.PackageId
                    Version       = $catalogEntry.Version
                    ReleaseDate   = $catalogEntry.ReleaseDate
                    FileName      = $catalogEntry.FileName
                    FileSizeMB    = $catalogEntry.FileSizeMB
                    DownloadUri   = $catalogEntry.DownloadUri
                    Checksums     = $catalogEntry.Checksums
                }
            }
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Finished"
    }
}