private/Get-WinPEDriverPackageHp.ps1

#Requires -PSEdition Core

function Get-WinPEDriverPackageHp {
    <#
    .SYNOPSIS
        Gets HP WinPE 10 and 11 driver pack metadata
 
    .DESCRIPTION
        Reads the HP UpdateUri from the global WinPE driver configuration, downloads the HP
        DriverPack HTML, and parses the WinPE 10/11 row. The function derives its package
        identifier and links from that row, normalizes the release date, and downloads no
        driver package. Configuration, request, or parsing failures produce a warning and
        no object.
 
    .EXAMPLE
        PS> Get-WinPEDriverPackageHp
 
        Returns the current amd64 HP WinPE 10/11 package metadata from the configured page.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns one object with Architecture,
        ReadmeUri, PackageId, Version, ReleaseDate, FileName, FileSizeMB, DownloadUri, and
        Checksums properties, or no object on failure. FileSizeMB can be null.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Dependencies:
          Network Resources: Configured HP UpdateUri
          DotNet Classes: System.Globalization.CultureInfo, System.IO.Path,
                          System.Net.WebUtility,
                          System.Management.Automation.PSCustomObject
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject[]])]
    param ()

    try {
        $searchUri = $global:OSDeployModule.WinPEDrivers.'hp'.UpdateUri
        if ([string]::IsNullOrWhiteSpace($searchUri)) {
            throw "hp UpdateUri is not defined in winpedrivers.json."
        }

        $normalizeHtml = {
            param([AllowNull()][string]$Value)

            if ([string]::IsNullOrWhiteSpace($Value)) {
                return ''
            }

            $decoded = [System.Net.WebUtility]::HtmlDecode($Value)
            $text = [regex]::Replace($decoded, '<[^>]+>', ' ')
            ([regex]::Replace($text, '\s+', ' ')).Trim()
        }

        $convertReleaseDate = {
            param([string]$Value)

            foreach ($format in @('M/d/yyyy', 'MM/dd/yyyy', 'dd MMM yyyy', 'yyyy-MM-dd')) {
                try {
                    return [datetime]::ParseExact(
                        $Value,
                        $format,
                        [System.Globalization.CultureInfo]::InvariantCulture
                    ).ToString('yyyy-MM-dd')
                }
                catch {
                }
            }

            try { ([datetime]$Value).ToString('yyyy-MM-dd') }
            catch { $Value }
        }

        $getCellValue = {
            param(
                [string[]]$Cells,
                [int]$Index
            )

            if ($Index -lt $Cells.Count) {
                return $Cells[$Index]
            }

            $null
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Fetching HP WinPE DriverPack page '$searchUri'"
        $response = Invoke-WebRequest -Uri $searchUri -UseBasicParsing -ErrorAction Stop
        $html = $response.Content

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Parsing WinPEDriverPacks table"
        $tableMatch = [regex]::Match(
            $html,
            '(?is)<table[^>]+id=["'']WinPEDriverPacks["''][^>]*>(?<Table>.*?)</table>'
        )

        $driverInfo = $null
        if ($tableMatch.Success) {
            foreach ($rowMatch in [regex]::Matches($tableMatch.Groups['Table'].Value, '(?is)<tr[^>]*>(?<Row>.*?)</tr>')) {
                $rowHtml = $rowMatch.Groups['Row'].Value
                $cells = @(
                    [regex]::Matches($rowHtml, '(?is)<t[dh][^>]*>(?<Cell>.*?)</t[dh]>') |
                        ForEach-Object { & $normalizeHtml $_.Groups['Cell'].Value }
                )

                if ($cells.Count -lt 4) {
                    continue
                }

                $packName = & $getCellValue $cells 0
                if ($packName -notmatch '(?i)^winpe\s*10/11$') {
                    continue
                }

                $links = [regex]::Matches($rowHtml, '(?is)<a[^>]+href=["''](?<Uri>[^"'']+)["''][^>]*>')
                $downloadUri = $null
                $readmeUri = $searchUri
                foreach ($link in $links) {
                    $uri = [System.Net.WebUtility]::HtmlDecode($link.Groups['Uri'].Value)
                    if (-not $downloadUri -and $uri -match '(?i)\.exe(?:\?|$)') {
                        $downloadUri = $uri
                        continue
                    }

                    if ($uri -match '(?i)WinPE(?:10|11)?\.html(?:\?|$)') {
                        $readmeUri = $uri
                    }
                }

                $id = & $getCellValue $cells 2
                if (-not $id -and $downloadUri) {
                    $id = [System.IO.Path]::GetFileNameWithoutExtension(($downloadUri -split '\?')[0])
                }

                $driverInfo = [PSCustomObject]@{
                    PackageId    = $id
                    Version      = & $getCellValue $cells 1
                    ReleaseDate  = & $convertReleaseDate (& $getCellValue $cells 3)
                    FileSizeMB   = $null
                    DownloadUri  = $downloadUri
                    FileName     = if ($downloadUri) { Split-Path -Path (($downloadUri -split '\?')[0]) -Leaf } else { $null }
                    ReadmeUri    = $readmeUri
                }
                break
            }
        }

        if (-not $driverInfo) {
            Write-Warning "[$(Get-Date -Format s)] Could not locate the HP WinPE 10/11 driver pack on '$searchUri'."
            return
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] PackageId='$($driverInfo.PackageId)' Version='$($driverInfo.Version)' ReleaseDate='$($driverInfo.ReleaseDate)' FileName='$($driverInfo.FileName)'"

        @(
            [PSCustomObject]@{
                Architecture = 'amd64'
                ReadmeUri    = $driverInfo.ReadmeUri
                PackageId    = $driverInfo.PackageId
                Version      = $driverInfo.Version
                ReleaseDate  = $driverInfo.ReleaseDate
                FileName     = $driverInfo.FileName
                FileSizeMB   = $driverInfo.FileSizeMB
                DownloadUri  = $driverInfo.DownloadUri
                Checksums    = [PSCustomObject]@{}
            }
        )
    }
    catch {
        Write-Warning "[$(Get-Date -Format s)] $($_.Exception.Message)"
    }
}