private/Get-WinPEDriverPackageIntelEthernet.ps1

#Requires -PSEdition Core

function Get-WinPEDriverPackageIntelEthernet {
    <#
    .SYNOPSIS
        Gets Intel Ethernet driver pack metadata
 
    .DESCRIPTION
        Reads the Intel Ethernet UpdateUri from the global WinPE driver configuration,
        requests the download page with curl.exe, and extracts the current amd64 release
        ZIP, mirror identifier, version, optional readme, SHA256 checksum, file size, and
        release date. The function downloads no driver package. Failures produce a warning
        and no object.
 
    .EXAMPLE
        PS> Get-WinPEDriverPackageIntelEthernet
 
        Returns current Intel Ethernet package metadata parsed from the configured page.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns one object with PackageId,
        Architecture, ReadmeUri, ReleaseDate, Version, FileName, FileSizeMB, DownloadUri,
        and Checksums properties, or no object on failure. Optional metadata can be null or
        empty when it is absent from the page.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Dependencies:
                    Executables: curl.exe
          Network Resources: Configured Intel Ethernet UpdateUri
          DotNet Classes: System.Globalization.CultureInfo,
                          System.Management.Automation.PSCustomObject
    #>

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

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

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

            foreach ($format in @('M/d/yyyy', 'MM/dd/yyyy', 'MMMM d, yyyy', 'MMM d, 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 }
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Fetching Intel Ethernet download page '$searchUri'"
        $html = curl.exe --location --fail --silent --show-error --retry 3 $searchUri
        if ($LASTEXITCODE -ne 0) {
            throw "curl.exe failed (exit $LASTEXITCODE) requesting '$searchUri'."
        }
        $html = $html -join [Environment]::NewLine

        $downloadUriMatch = [regex]::Match(
            $html,
            '(?i)(https://downloadmirror\.intel\.com/(?<Id>\d{6,7})/(?<FileName>Release_(?<Version>[\d\.]+)\.zip))'
        )
        if (-not $downloadUriMatch.Success) {
            Write-Warning "[$(Get-Date -Format s)] Could not find Intel Ethernet zip download URL on page '$searchUri'. Page format may have changed."
            return
        }

        $downloadUri = $downloadUriMatch.Groups[1].Value
        $mirrorId = $downloadUriMatch.Groups['Id'].Value
        $fileName = $downloadUriMatch.Groups['FileName'].Value
        $version  = $downloadUriMatch.Groups['Version'].Value

        $readmeMatch = [regex]::Match(
            $html,
            '(?i)(https://downloadmirror\.intel\.com/' + [regex]::Escape($mirrorId) + '/readme\.txt)'
        )
        $readmeUri = if ($readmeMatch.Success) { $readmeMatch.Groups[1].Value } else { $searchUri }

        $sha256Match = [regex]::Match($html, '(?i)SHA256[:\s]+([A-Fa-f0-9]{64})')
        $sha256 = $sha256Match.Groups[1].Value.Trim()

        $fileSizeMB = $null
        $sizeMatch = [regex]::Match($html, '(?i)Size:\s*(\d+(?:\.\d+)?)\s*MB')
        if ($sizeMatch.Success) {
            $fileSizeMB = [double]$sizeMatch.Groups[1].Value
        }

        $releaseDate = $null
        $dateMatch = [regex]::Match(
            $html,
            '(?i)<meta[^>]+name="(?:lastModifieddate|LastUpdate)"[^>]+content="(?<Date>\d{1,2}/\d{1,2}/\d{4})(?:\s+\d{2}:\d{2}:\d{2})?"'
        )
        if ($dateMatch.Success) {
            $releaseDate = & $convertReleaseDate $dateMatch.Groups['Date'].Value
        }

        $checksums = @{}
        if ($sha256) { $checksums['SHA256'] = $sha256 }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] PackageId='$mirrorId' Version='$version' ReleaseDate='$releaseDate'"

        @(
            [PSCustomObject]@{
                PackageId    = $mirrorId
                Architecture = 'amd64'
                ReadmeUri    = $readmeUri
                ReleaseDate  = $releaseDate
                Version      = $version
                FileName     = $fileName
                FileSizeMB   = $fileSizeMB
                DownloadUri  = $downloadUri
                Checksums    = [PSCustomObject]$checksums
            }
        )
    }
    catch {
        Write-Warning "[$(Get-Date -Format s)] $($_.Exception.Message)"
        if ($searchUri) {
            Write-Warning "[$(Get-Date -Format s)] URL: $searchUri"
        }
    }
}