Public/Functions/Catalogs/Update/Update-MicrosoftDriverPackCatalog.ps1

<#
.SYNOPSIS
Updates the local Microsoft Surface DriverPacks in the OSD Module
 
.DESCRIPTION
Updates the local Microsoft Surface DriverPacks in the OSD Module
 
.LINK
https://github.com/OSDeploy/OSD/tree/master/Docs
 
.NOTES
#>

function Update-MicrosoftDriverPackCatalog {
    [CmdletBinding()]
    param (
        #Updates the OSD Module Offline Catalog. Requires Admin rights
        [System.Management.Automation.SwitchParameter]
        $UpdateModuleCatalog,

        #Verifies that the DriverPack is reachable. This will take some time to complete
        [System.Management.Automation.SwitchParameter]
        $Verify
    )
    #=================================================
    # Reference
    #=================================================
    # Device List
    # https://docs.microsoft.com/en-us/surface/surface-system-sku-reference
    #
    # Supported Operating Systems
    # https://support.microsoft.com/en-us/surface/surface-supported-operating-systems-9559cc3c-7a38-31b6-d9fb-571435e84cd1
    #
    # Download Links
    # https://support.microsoft.com/en-us/surface/download-drivers-and-firmware-for-surface-09bb2e09-2a4b-cb69-0951-078a7739e120#bkmk_update-manually
    #
    # https://docs.microsoft.com/en-us/surface/manage-surface-driver-and-firmware-updates
    # https://www.reddit.com/r/Surface/comments/mlhqw5/all_direct_download_links_for_surface/
    # https://dancharblog.wordpress.com/2021/04/06/all-direct-download-links-for-surface-firmware-drivers/
    #=================================================
    # Defaults
    #=================================================
    $OfflineCatalogName = 'MicrosoftDriverPackCatalog.json'

    $OnlineCatalogName = 'MicrosoftDriverPackCatalog.json'
    $OnlineBaseUri = 'https://www.microsoft.com/en-us/download/details.aspx?id='
    $OnlineDownloadUri = 'https://www.microsoft.com/en-us/download/confirmation.aspx?id='
    $OnlineCatalogUri = 'https://support.microsoft.com/en-us/surface/download-drivers-and-firmware-for-surface-09bb2e09-2a4b-cb69-0951-078a7739e120'

    $MicrosoftSurfaceModels = Get-Content -Path "$($MyInvocation.MyCommand.Module.ModuleBase)\Catalogs\MicrosoftSurfaceModels.json" -Raw
    #=================================================
    # Additional Paths
    #=================================================
    $CatalogBuildFolder = Join-Path $env:TEMP 'OSD'
    if (-not(Test-Path $CatalogBuildFolder)) {
        $null = New-Item -Path $CatalogBuildFolder -ItemType Directory -Force
    }
    $RawCatalogFile            = Join-Path $env:TEMP (Join-Path 'OSD' $OnlineCatalogName)
    $RawCatalogCabName      = [string]($OnlineCatalogUri | Split-Path -Leaf)
    $RawCatalogCabPath         = Join-Path $env:TEMP (Join-Path 'OSD' $RawCatalogCabName)
    $TempCatalogFile        = Join-Path $env:TEMP (Join-Path 'OSD' $OfflineCatalogName)
    $ModuleCatalogXml       = "$($MyInvocation.MyCommand.Module.ModuleBase)\Catalogs\MicrosoftDriverPackCatalog.xml"
    $ModuleCatalogJson      = "$($MyInvocation.MyCommand.Module.ModuleBase)\Catalogs\MicrosoftDriverPackCatalog.json"
    #=================================================
    # UseCatalog Cloud
    #=================================================
    $SurfaceModels = $MicrosoftSurfaceModels | ConvertFrom-Json
    $MasterResults = @()

    $MasterResults = foreach ($Surface in $SurfaceModels) {
        Write-Verbose -Verbose "Processing $($Surface.Name)"
        $DriverPage = $OnlineDownloadUri + $Surface.PackageID
        $Downloads = (Invoke-WebRequest -Uri $DriverPage).Links
        $Downloads = $Downloads | Where-Object {$_.href -match 'download.microsoft.com'}
        $Downloads = $Downloads | Where-Object {($_.href -match 'Win11') -or ($_.href -match 'Win10')}
        $Downloads = $Downloads | Sort-Object href | Select-Object href -Unique
        #$Downloads = $Downloads | Select-Object -Last 1
        #$Surface.Url = ($Downloads).href
        #$Surface.FileName = Split-Path $Surface.Url -Leaf
        #=================================================
        # Create Object
        #=================================================
        foreach ($Download in $Downloads) {
            $DownloadUrl = $Download.href
            Write-Verbose -Verbose "Verify: $DownloadUrl"

            $GetUrl = Invoke-WebRequest -Method Head -Uri $DownloadUrl
            $GetHeaders = $GetUrl.Headers
            $GetLastModified = $GetHeaders['Last-Modified']
            Write-Verbose -Verbose "Last Modified: $GetLastModified"

            $ReleaseDate = (Get-Date $GetLastModified).ToString('yy.MM.dd')
            $FileName = Split-Path $DownloadUrl -Leaf

            if ($FileName -match 'Win11') {
                $OSVersion = 'Windows 11 x64'
            }
            else {
                $OSVersion = 'Windows 10 x64'
            }
            
            $ByteArray = [System.Convert]::FromBase64String($GetHeaders['Content-MD5'])
            $HexObject = $ByteArray | Format-Hex
            $HashMD5 = ($HexObject.Bytes | ForEach-Object {"{0:X}" -f $_}) -join ''

            $UniqueFileName = $FileName
            $UniqueFileName = $UniqueFileName -replace '_Win', ' Win'
            $UniqueFileName = $UniqueFileName.Split(' ')[1]
            $UniqueFileName = $UniqueFileName -replace 'Win10_', 'Win10 '
            $UniqueFileName = $UniqueFileName -replace 'Win11_', 'Win11 '
            $UniqueFileName = $UniqueFileName.Split('_')[0]

            $UniqueName = "Microsoft $($Surface.Name) $UniqueFileName"

            $ObjectProperties = [ordered] @{
                CatalogVersion          = Get-Date -Format yy.MM.dd
                Status                  = $null
                Component               = 'DriverPack'
                ReleaseDate             = $ReleaseDate
                Manufacturer            = 'Microsoft'
                Model                   = $Surface.Model
                Product                 = $Surface.Product
                Name                    = $UniqueName
                PackageID               = $Surface.PackageID
                FileName                = $FileName
                Url                     = $DownloadUrl
                DownloadCenter          = $OnlineBaseUri + $Surface.PackageID
                OSVersion               = $OSVersion
                OSReleaseId             = ''
                OSBuild                 = ''    
                HashMD5                 = $HashMD5
            }
            New-Object -TypeName PSObject -Property $ObjectProperties
        }
    }

    foreach ($Item in $MasterResults) {
        $Item.OSBuild = $Item.Name.Split(' ')[-1]
    }

    foreach ($Item in $MasterResults) {
        if ($Item.Name -match 'Win10 10240') {
            $Item.OSReleaseId = '1507'
            $Item.Name = $Item.Name -replace 'Win10 10240', 'Win10 1507'
        }
        if ($Item.Name -match 'Win10 10586') {
            $Item.OSReleaseId = '1511'
            $Item.Name = $Item.Name -replace 'Win10 10586', 'Win10 1511'
        }
        if ($Item.Name -match 'Win10 14393') {
            $Item.OSReleaseId = '1607'
            $Item.Name = $Item.Name -replace 'Win10 14393', 'Win10 1607'
        }
        if ($Item.Name -match 'Win10 15063') {  
            $Item.OSReleaseId = '1703'
            $Item.Name = $Item.Name -replace 'Win10 15063', 'Win10 1703'
        }
        if ($Item.Name -match 'Win10 16299') {
            $Item.OSReleaseId = '1709'
            $Item.Name = $Item.Name -replace 'Win10 16299', 'Win10 1709'
        }
        if ($Item.Name -match 'Win10 17134') {
            $Item.OSReleaseId = '1803'
            $Item.Name = $Item.Name -replace 'Win10 17134', 'Win10 1803'
        }
        if ($Item.Name -match 'Win10 17763') {
            $Item.OSReleaseId = '1809'
            $Item.Name = $Item.Name -replace 'Win10 17763', 'Win10 1809'
        }
        if ($Item.Name -match 'Win10 18362') {
            $Item.OSReleaseId = '1903'
            $Item.Name = $Item.Name -replace 'Win10 18362', 'Win10 1903'
        }
        if ($Item.Name -match 'Win10 18363') {
            $Item.OSReleaseId = '1909'
            $Item.Name = $Item.Name -replace 'Win10 18363', 'Win10 1909'
        }
        if ($Item.Name -match 'Win10 19041') {
            $Item.OSReleaseId = '2004'
            $Item.Name = $Item.Name -replace 'Win10 19041', 'Win10 2004'
        }
        if ($Item.Name -match 'Win10 19042') {
            $Item.OSReleaseId = '20H2'
            $Item.Name = $Item.Name -replace 'Win10 19042', 'Win10 20H2'
        }
        if ($Item.Name -match 'Win10 19043') {
            $Item.OSReleaseId = '21H1'
            $Item.Name = $Item.Name -replace 'Win10 19043', 'Win10 21H1'
        }
        if ($Item.Name -match 'Win10 19044') {
            $Item.OSReleaseId = '21H2'
            $Item.Name = $Item.Name -replace 'Win10 19044', 'Win10 21H2'
        }
        if ($Item.Name -match 'Win10 19045') {
            $Item.OSReleaseId = '22H2'
            $Item.Name = $Item.Name -replace 'Win10 19045', 'Win10 22H2'
        }
        if ($Item.Name -match 'Win11 22000') {
            $Item.OSReleaseId = '21H2'
            $Item.Name = $Item.Name -replace 'Win11 22000', 'Win11 21H2'
        }
        if ($Item.Name -match 'Win11 22621') {
            $Item.OSReleaseId = '22H2'
            $Item.Name = $Item.Name -replace 'Win11 22621', 'Win11 22H2'
        }
        if ($Item.Name -match 'Win11 22631') {
            $Item.OSReleaseId = '23H2'
            $Item.Name = $Item.Name -replace 'Win11 22631', 'Win11 23H2'
        }
        if ($Item.Name -match 'Win11 26100') {
            $Item.OSReleaseId = '24H2'
            $Item.Name = $Item.Name -replace 'Win11 26100', 'Win11 24H2'
        }
    }
    #=================================================
    # UpdateModule
    #=================================================
    if ($UpdateModuleCatalog) {
        Write-Verbose -Verbose "UpdateModule: Exporting to OSD Module Catalogs at $ModuleCatalogXml"
        $MasterResults | Export-Clixml -Path $ModuleCatalogXml -Force
        Write-Verbose -Verbose "UpdateModule: Exporting to OSD Module Catalogs at $ModuleCatalogJson"
        $MasterResults | ConvertTo-Json | Out-File $ModuleCatalogJson -Encoding ascii -Width 2000 -Force
        #=================================================
        # UpdateCatalog
        #=================================================
        $MasterDriverPacks = @()
        $MasterDriverPacks += Get-DellDriverPack
        $MasterDriverPacks += Get-HPDriverPack
        $MasterDriverPacks += Get-LenovoDriverPack
        $MasterDriverPacks += Get-MicrosoftDriverPack
    
        $MasterResults = $MasterDriverPacks | `
        Select-Object CatalogVersion, Status, ReleaseDate, Manufacturer, Model, `
        Product, Name, PackageID, FileName, `
        @{Name='Url';Expression={([array]$_.DriverPackUrl)}}, `
        @{Name='OS';Expression={([array]$_.DriverPackOS)}}, `
        OSReleaseId,OSBuild,HashMD5, `
        @{Name='Guid';Expression={([guid]((New-Guid).ToString()))}}
    
        $MasterResults | Export-Clixml -Path (Join-Path (Get-Module -Name OSD -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).ModuleBase "Catalogs\CloudDriverPacks.xml") -Force
        Import-Clixml -Path (Join-Path (Get-Module -Name OSD -ListAvailable | `
        Sort-Object Version -Descending | `
        Select-Object -First 1).ModuleBase "Catalogs\CloudDriverPacks.xml") | `
        ConvertTo-Json | `
        Out-File (Join-Path (Get-Module -Name OSD -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).ModuleBase "Catalogs\CloudDriverPacks.json") -Encoding ascii -Width 2000 -Force
    }
    #=================================================
    # Results
    #=================================================
    Write-Verbose -Verbose 'Complete: Results have been stored $Global:MicrosoftDriverPackCatalog'
    $Global:MicrosoftDriverPackCatalog = $MasterResults | Sort-Object -Property Name
    #=================================================
}