private/Get-WinPEDriverPackageSurface.ps1

#Requires -PSEdition Core

function Get-WinPEDriverPackageSurface {
    <#
    .SYNOPSIS
        Gets Microsoft Surface driver package metadata
 
    .DESCRIPTION
        Resolves a named Surface source from the global WinPE driver configuration and
        downloads its Microsoft Download Center details page. The function selects a current
        MSI link, preferring a file name containing Win11, derives version and release date,
        and attempts a HEAD request for file size. It emits one metadata row for each
        configured DriverPacks entry. Missing configuration and download-page failures are
        terminating; a failed HEAD request leaves FileSizeMB null.
 
    .PARAMETER Name
        Specifies the Surface source name in the global WinPE driver configuration. The
        source must define SearchUri and DriverPacks properties.
 
    .EXAMPLE
        PS> Get-WinPEDriverPackageSurface -Name 'surface-laptop-7'
 
        Returns metadata rows for each architecture configured for surface-laptop-7.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject. Returns zero or more objects with
        Architecture, ReadmeUri, PackageId, Version, ReleaseDate, FileName, FileSizeMB,
        DownloadUri, and Checksums properties. Version, ReleaseDate, or FileSizeMB can be
        null when the page does not expose usable values.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Dependencies:
          Network Resources: Configured Microsoft Download Center SearchUri and MSI URI
          DotNet Classes: System.IO.Path,
                          System.Management.Automation.PSCustomObject
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )

    $sourceData = $global:OSDeployModule.WinPEDrivers.$Name
    if (-not $sourceData) {
        throw "Surface source '$Name' was not found in winpedrivers.json."
    }

    $searchUri = $sourceData.SearchUri
    if ([string]::IsNullOrWhiteSpace($searchUri)) {
        throw "Surface SearchUri is not defined for '$Name' in winpedrivers.json."
    }

    Write-Verbose "[$($MyInvocation.MyCommand.Name)] Fetching Surface page '$searchUri' for '$Name'"
    $response = Invoke-WebRequest -Uri $searchUri -UseBasicParsing -ErrorAction Stop

    $msiLinks = @(
        $response.Links |
            Where-Object { $_.href -match '(?i)^https://download\.microsoft\.com/.+\.msi(?:\?|$)' } |
            ForEach-Object { $_.href } |
            Select-Object -Unique
    )

    if (-not $msiLinks) {
        throw "Could not locate any MSI download links on '$searchUri'. Page format may have changed."
    }

    $preferredLinks = @($msiLinks | Where-Object { $_ -match '(?i)Win11' })
    $selectedUri = if ($preferredLinks) { $preferredLinks[0] } else { $msiLinks[0] }
    $fileName = [System.IO.Path]::GetFileName(($selectedUri -split '\?')[0])

    if ([string]::IsNullOrWhiteSpace($fileName)) {
        throw "Could not derive a file name from Surface download URI '$selectedUri'."
    }

    $versionMatch = [regex]::Match($fileName, '_(?<Version>\d+(?:\.\d+){3})\.msi$')
    $version = if ($versionMatch.Success) { $versionMatch.Groups['Version'].Value } else { $null }

    $releaseDate = $null
    $releaseDateMatch = [regex]::Match(
        $response.Content,
        '(?is)Date Published:\s*</h3>\s*<p[^>]*>\s*(?<Date>[^<]+?)\s*</p>'
    )
    if ($releaseDateMatch.Success) {
        try {
            $releaseDate = (Get-Date -Date $releaseDateMatch.Groups['Date'].Value.Trim()).ToString('yyyy-MM-dd')
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Could not parse release date '$($releaseDateMatch.Groups['Date'].Value.Trim())' for '$Name'"
        }
    }

    $fileSizeMb = $null
    try {
        $headResponse = Invoke-WebRequest -Uri $selectedUri -Method Head -UseBasicParsing -ErrorAction Stop
        $contentLength = @($headResponse.Headers['Content-Length']) | Select-Object -First 1
        if ($contentLength) {
            $fileSizeMb = [math]::Round(([double]$contentLength) / 1MB, 1)
        }
    }
    catch {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] HEAD request failed for '$selectedUri': $($_.Exception.Message)"
    }

    $packResults = foreach ($pack in $sourceData.DriverPacks) {
        [PSCustomObject]@{
            Architecture = $pack.Architecture
            ReadmeUri    = $searchUri
            PackageId    = if ($pack.PackageId) { $pack.PackageId } else { (($searchUri -split 'id=')[-1] -split '&')[0] }
            Version      = $version
            ReleaseDate  = $releaseDate
            FileName     = $fileName
            FileSizeMB   = $fileSizeMb
            DownloadUri  = $selectedUri
            Checksums    = [PSCustomObject]@{}
        }
    }

    foreach ($entry in $packResults) {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$Name' — Architecture='$($entry.Architecture)' Version='$($entry.Version)' ReleaseDate='$($entry.ReleaseDate)' FileName='$($entry.FileName)'"
    }

    $packResults
}