private/Save-WinPEDriverPackageSurface.ps1

#Requires -PSEdition Core

function Save-WinPEDriverPackageSurface {
    <#
    .SYNOPSIS
        Downloads and prepares a Microsoft Surface driver package
 
    .DESCRIPTION
        Downloads a Surface MSI to the OSDeployCore download cache and verifies its SHA256
        checksum when the package provides one. Unless DownloadOnly is specified, the
        function expands the MSI into an architecture-specific winpedrivers folder
        named from the package name and package ID when that folder contains no files.
 
        The function then reduces the SurfaceUpdate payload by removing directories whose
        names match known non-WinPE component patterns, directories larger than 100 MB, and
        directories containing BIN or PPKG files. Cleanup targets are reduced to their
        highest selected ancestor before recursive removal.
 
    .PARAMETER DriverPackage
        Specifies the OSDeployWinPEDriver.Package object to download. The object supplies
        the package name, package ID, architecture, URIs, filename, and optional checksum.
 
    .PARAMETER Force
        Downloads the package again even when a cached file is available. Cleanup of the
        expanded SurfaceUpdate payload occurs regardless of Force.
 
    .PARAMETER DownloadOnly
        Returns after downloading the MSI without expanding or cleaning Surface driver content.
 
    .EXAMPLE
        PS> $package = Get-WinPEDriverPackageCore | Where-Object Name -Match '^Surface' | Select-Object -First 1; Save-WinPEDriverPackageSurface -DriverPackage $package
 
        Downloads the first Surface package, expands it when needed, and removes non-WinPE content.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.IO.FileInfo. Returns the downloaded MSI file, or no object when the download fails.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Cleanup recursively deletes selected directories beneath SurfaceUpdate.
 
    .LINK
        Save-WinPEDriverPackageCore
    #>

    [CmdletBinding()]
    [OutputType([System.IO.FileInfo])]
    param (
        [Parameter(Mandatory)]
        [PSTypeName('OSDeployWinPEDriver.Package')]
        [PSCustomObject]$DriverPackage,

        [Parameter()]
        [switch]$Force,

        [Parameter()]
        [switch]$DownloadOnly
    )

    $package     = $DriverPackage
    $idPrefix    = ($package.Name -split '-')[0]
    $downloadDir = Join-Path $script:OSDeployCoreDownloadsPath $idPrefix
    $targetPath  = Join-Path $downloadDir $package.FileName
    $driverDir   = Join-Path $script:OSDeployBootAssetsPath "winpedrivers-$($package.Architecture)" |
                   Join-Path -ChildPath "$($package.Name)-$($package.PackageId)"

    $expectedSha256 = $null
    if ($package.Checksums -and $package.Checksums.SHA256) {
        $expectedSha256 = $package.Checksums.SHA256
    }

    $downloadedFile = Invoke-WinPEDriverPackageDownload `
        -Uri             $package.DownloadUri `
        -DestinationPath $targetPath `
        -SearchUri       $package.SearchUri `
        -ExpectedSHA256  $expectedSha256 `
        -Force:$Force

    if (-not $downloadedFile) {
        return
    }

    if ($DownloadOnly) {
        return $downloadedFile
    }

    $expandedFiles = Get-ChildItem -Path $driverDir -Recurse -File -ErrorAction SilentlyContinue
    if (-not $expandedFiles) {
        if (-not (Test-Path -Path $driverDir)) {
            New-Item -ItemType Directory -Path $driverDir -Force | Out-Null
        }

        Write-HostDateTimeDarkGray -Message "Expand: $targetPath"
        Write-HostDateTimeDarkGray -Message "Output: $driverDir"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Expanding Surface package '$($package.FileName)' to '$driverDir'"
        Expand-WinPEDriverPackageMsi -Path $targetPath -DestinationPath $driverDir | Out-Null
    }
    else {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] '$driverDir' already contains expanded files. Skipping expansion."
    }

    $surfaceUpdateDir = Join-Path $driverDir 'SurfaceUpdate'
    if (Test-Path -Path $surfaceUpdateDir) {
        $largeDirectoryThresholdBytes = 100MB
        $cleanupPatterns = @('*audio*','*RealtekAPO*','cam*','*iclsclient*','*telemetry*', '*bluetooth*', '*microsofteffectpack*','*fw*', '*dax*', '*capsule*', '*icpscomponent*','*machinelearning*', '*update*', '*camera*', '*graphics*','*capabilitylicensingsvcclient*','*hdx*', '*dptf*')
        $cleanupTargets = @(Get-ChildItem -Path $surfaceUpdateDir -Directory -ErrorAction SilentlyContinue |
            Where-Object {
                $directoryName = $_.Name
                foreach ($pattern in $cleanupPatterns) {
                    if ($directoryName -like $pattern) {
                        return $true
                    }
                }

                return $false
            })

        $largeCleanupTargets = @(Get-ChildItem -Path $surfaceUpdateDir -Directory -Recurse -ErrorAction SilentlyContinue |
            Where-Object {
                $directorySize = [long]((Get-ChildItem -LiteralPath $_.FullName -File -Recurse -Force -ErrorAction SilentlyContinue |
                    Measure-Object -Property Length -Sum).Sum ?? 0)

                $directorySize -gt $largeDirectoryThresholdBytes
            })

        $binCleanupTargets = @(Get-ChildItem -Path $surfaceUpdateDir -Recurse -File -Filter '*.bin' -ErrorAction SilentlyContinue |
            ForEach-Object {
                $parentPath = Split-Path -Path $_.FullName -Parent
                if (-not [string]::IsNullOrWhiteSpace($parentPath) -and (Test-Path -Path $parentPath -PathType Container)) {
                    Get-Item -Path $parentPath
                }
            })

        $ppkgCleanupTargets = @(Get-ChildItem -Path $surfaceUpdateDir -Recurse -File -Filter '*.ppkg' -ErrorAction SilentlyContinue |
            ForEach-Object {
                $parentPath = Split-Path -Path $_.FullName -Parent
                if (-not [string]::IsNullOrWhiteSpace($parentPath) -and (Test-Path -Path $parentPath -PathType Container)) {
                    Get-Item -Path $parentPath
                }
            })

        $selectedCleanupPaths = [System.Collections.Generic.List[string]]::new()
        $cleanupTargets = @($cleanupTargets + $largeCleanupTargets + $binCleanupTargets + $ppkgCleanupTargets |
            Where-Object { $_ -and -not [string]::IsNullOrWhiteSpace($_.FullName) } |
            Sort-Object -Property @{ Expression = { $_.FullName.Length } }, FullName -Unique |
            Where-Object {
                $currentPath = $_.FullName
                $hasSelectedAncestor = $false

                foreach ($selectedPath in $selectedCleanupPaths) {
                    if ($currentPath.StartsWith("$selectedPath$([System.IO.Path]::DirectorySeparatorChar)", [System.StringComparison]::OrdinalIgnoreCase)) {
                        $hasSelectedAncestor = $true
                        break
                    }
                }

                if ($hasSelectedAncestor) {
                    return $false
                }

                if (-not (Test-Path -LiteralPath $currentPath -PathType Container)) {
                    return $false
                }

                $selectedCleanupPaths.Add($currentPath) | Out-Null
                return $true
            })

        foreach ($cleanupTarget in $cleanupTargets) {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Removing '$($cleanupTarget.FullName)'"
            if (Test-Path -LiteralPath $cleanupTarget.FullName -PathType Container) {
                Remove-Item -LiteralPath $cleanupTarget.FullName -Recurse -Force
            }
        }
    }

    $downloadedFile
}