Public/Functions/DriverPack.ps1

function Enable-SpecializeDriverPack {
    <#
    .SYNOPSIS
    Configures driver pack expansion during Windows Specialize phase
 
    .DESCRIPTION
    Sets up an unattend XML file to automatically expand driver packs during the Windows Specialize pass. Requires admin rights and Windows 10 or later.
 
    .EXAMPLE
    Enable-SpecializeDriverPack
    Configures the system to expand driver packs during Specialize phase
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param ()
$UnattendXml = @'
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="specialize">
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <RunSynchronous>
                <RunSynchronousCommand wcm:action="add">
                    <Order>1</Order>
                    <Description>Expand-StagedDriverPack</Description>
                    <Path>Powershell -ExecutionPolicy Bypass -Command Expand-StagedDriverPack</Path>
                </RunSynchronousCommand>
            </RunSynchronous>
        </component>
    </settings>
</unattend>
'@

    #=================================================
    # Block
    #=================================================
    Block-WinOS
    Block-WindowsVersionNe10
    Block-PowerShellVersionLt5
    #=================================================
    # Set Unattend in the Registry
    # HKEY_LOCAL_MACHINE\System\Setup\UnattendFile
    # Specifies a pointer in the registry to an answer file
    # The answer file is not required to be named Unattend.xml
    # https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-setup-automation-overview
    #=================================================
    reg load HKLM\TempSYSTEM "C:\Windows\System32\Config\SYSTEM"
    reg add HKLM\TempSYSTEM\Setup /v UnattendFile /d "C:\Windows\Panther\Expand-StagedDriverPack.xml" /f
    reg unload HKLM\TempSYSTEM
    #=================================================
    # Set Unattend
    #=================================================
    $UnattendXml | Out-File -FilePath "C:\Windows\Panther\Expand-StagedDriverPack.xml" -Encoding utf8 -Width 2000 -Force
    #=================================================
}
function Expand-StagedDriverPack {
    <#
    .SYNOPSIS
    Expands staged driver pack archives during Windows Setup
 
    .DESCRIPTION
    Extracts and processes staged driver pack files (CAB, EXE, MSI, ZIP) from the C:\Drivers directory. Supports multiple vendor formats including Dell, HP, Lenovo, and generic packages.
 
    .PARAMETER Apply
    Applies drivers during PnP unattend phase
 
    .EXAMPLE
    Expand-StagedDriverPack
    Expands all driver packs in C:\Drivers
 
    .EXAMPLE
    Expand-StagedDriverPack -Apply
    Expands driver packs and applies them during setup
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param (
        [System.Management.Automation.SwitchParameter]$Apply
    )
    #=================================================
    # Specialize
    #=================================================
    $ImageState = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\State' -ErrorAction Ignore).ImageState
    if ($ImageState -eq 'IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE') {
        $Apply = $true
        reg delete HKLM\System\Setup /v UnattendFile /f
    }
    #=================================================
    # Specialize
    #=================================================
    if (Test-Path 'C:\Drivers') {
        $DriverPacks = Get-ChildItem -Path 'C:\Drivers' -File

        foreach ($Item in $DriverPacks) {
            $ExpandFile = $Item.FullName
            Write-Verbose -Verbose "DriverPack: $ExpandFile"
            #=================================================
            # Cab
            #=================================================
            if ($Item.Extension -eq '.cab') {
                $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                if (-NOT (Test-Path "$DestinationPath")) {
                    New-Item $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null

                    Write-Verbose -Verbose "Expanding CAB Driver Pack to $DestinationPath"
                    Expand -R "$ExpandFile" -F:* "$DestinationPath" | Out-Null

                    if ($Apply) {
                        New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                        pnpunattend.exe AuditSystem /L
                        Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                    }
                }
                Continue
            }
            #=================================================
            # Dell
            #=================================================
            if ($Item.Extension -eq '.exe') {
                if ($Item.VersionInfo.FileDescription -match 'Dell') {
                    Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                    Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                    $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                    if (-NOT (Test-Path "$DestinationPath")) {
                        Write-Verbose -Verbose "Expanding Dell Driver Pack to $DestinationPath"
                        $null = New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null
                        Start-Process -FilePath $ExpandFile -ArgumentList "/s /e=`"$DestinationPath`"" -Wait

                        if ($Apply) {
                            New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                            New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                            pnpunattend.exe AuditSystem /L
                            Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                        }
                    }
                    Continue
                }
            }
            #=================================================
            # HP
            #=================================================
            if ($Item.Extension -eq '.exe') {
                if (($Item.VersionInfo.InternalName -match 'hpsoftpaqwrapper') -or ($Item.VersionInfo.OriginalFilename -match 'hpsoftpaqwrapper.exe') -or ($Item.VersionInfo.FileDescription -like "HP *")) {
                    Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                    Write-Verbose -Verbose "InternalName: $($Item.VersionInfo.InternalName)"
                    Write-Verbose -Verbose "OriginalFilename: $($Item.VersionInfo.OriginalFilename)"
                    Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                    $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                    if (-NOT (Test-Path "$DestinationPath")) {
                        Write-Verbose -Verbose "Expanding HP Driver Pack to $DestinationPath"
                        Start-Process -FilePath $ExpandFile -ArgumentList "/s /e /f `"$DestinationPath`"" -Wait

                        if ($Apply) {
                            New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                            New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                            pnpunattend.exe AuditSystem /L
                            Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                        }
                    }
                    Continue
                }
            }
            #=================================================
            # Lenovo
            #=================================================
            if ($Item.Extension -eq '.exe') {
                if (($Item.VersionInfo.FileDescription -match 'Lenovo') -or ($Item.Name -match 'tc_') -or ($Item.Name -match 'tp_') -or ($Item.Name -match 'ts_') -or ($Item.Name -match '500w') -or ($Item.Name -match 'sccm_') -or ($Item.Name -match 'm710e') -or ($Item.Name -match 'tp10') -or ($Item.Name -match 'tp8') -or ($Item.Name -match 'yoga')) {
                    Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                    Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                    $DestinationPath = Join-Path $Item.Directory 'SCCM'

                    if (-NOT (Test-Path "$DestinationPath")) {
                        Write-Verbose -Verbose "Expanding Lenovo Driver Pack to $DestinationPath"
                        Start-Process -FilePath $ExpandFile -ArgumentList "/SILENT /SUPPRESSMSGBOXES" -Wait

                        if ($Apply) {
                            New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                            New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                            pnpunattend.exe AuditSystem /L
                            Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                        }
                    }
                    Continue
                }
            }
            #=================================================
            # MSI
            #=================================================
            if ($Item.Extension -eq '.msi') {
                $DateStamp = Get-Date -Format yyyyMMddTHHmmss
                $logFile = '{0}-{1}.log' -f $ExpandFile,$DateStamp
                $MSIArguments = @(
                    "/i"
                    ('"{0}"' -f $ExpandFile)
                    "/qb"
                    "/norestart"
                    "/L*v"
                    $logFile
                )
                Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
                Continue
            }
            #=================================================
            # Zip
            #=================================================
            if ($Item.Extension -eq '.zip') {
                $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                if (-NOT (Test-Path "$DestinationPath")) {
                    Write-Verbose -Verbose "Expanding ZIP Driver Pack to $DestinationPath"
                    Expand-Archive -Path $ExpandFile -DestinationPath $DestinationPath -Force

                    if ($Apply) {
                        New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                        pnpunattend.exe AuditSystem /L
                        Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                    }
                }
                Continue
            }
            #=================================================
            # Everything Else
            #=================================================
            Write-Warning "Unable to expand $ExpandFile"
            Write-Verbose -Verbose ""
            #=================================================
        }
    }
}
function Expand-ZTIDriverPack {
    <#
    .SYNOPSIS
    Expands driver packs during Lite Touch or Zero Touch deployment
 
    .DESCRIPTION
    Processes and extracts driver pack files from C:\Drivers directory during MDT/ConfigMgr task sequence execution. Supports CAB, EXE, MSI, and ZIP formats from multiple vendors.
 
    .EXAMPLE
    Expand-ZTIDriverPack
    Expands all driver packs in C:\Drivers during task sequence
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param ()
    #=================================================
    # Set some Variables
    #=================================================
    $OSDiskDrivers = 'C:\Drivers'
    #=================================================
    # Create $OSDiskDrivers
    #=================================================
    if (-NOT (Test-Path -Path $OSDiskDrivers)) {
        Write-Warning "Could not find $OSDiskDrivers"
        Start-Sleep -Seconds 5
        Continue
    }
    #=================================================
    # Start-Transcript
    #=================================================
    Start-Transcript -OutputDirectory $OSDiskDrivers
    #=================================================
    # Expand
    #=================================================
    $DriverPacks = Get-ChildItem -Path $OSDiskDrivers -File

    foreach ($Item in $DriverPacks) {
        $ExpandFile = $Item.FullName
        Write-Verbose -Verbose "DriverPack: $ExpandFile"
        #=================================================
        # Cab
        #=================================================
        if ($Item.Extension -eq '.cab') {
            $DestinationPath = Join-Path $Item.Directory $Item.BaseName

            if (-NOT (Test-Path "$DestinationPath")) {
                New-Item $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null

                Write-Verbose -Verbose "Expanding CAB Driver Pack to $DestinationPath"
                Expand -R "$ExpandFile" -F:* "$DestinationPath" | Out-Null

                New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                pnpunattend.exe AuditSystem /L
                Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
            }
            Continue
        }
        #=================================================
        # Dell
        #=================================================
        if ($Item.Extension -eq '.exe') {
            if ($Item.VersionInfo.FileDescription -match 'Dell') {
                Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                if (-NOT (Test-Path "$DestinationPath")) {
                    Write-Verbose -Verbose "Expanding Dell Driver Pack to $DestinationPath"
                    $null = New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null
                    Start-Process -FilePath $ExpandFile -ArgumentList "/s /e=`"$DestinationPath`"" -Wait

                    if ($Apply) {
                        New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                        pnpunattend.exe AuditSystem /L
                        Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                    }
                }
                Continue
            }
        }
        #=================================================
        # HP
        #=================================================
        if ($Item.Extension -eq '.exe') {
            if (($Item.VersionInfo.InternalName -match 'hpsoftpaqwrapper') -or ($Item.VersionInfo.OriginalFilename -match 'hpsoftpaqwrapper.exe') -or ($Item.VersionInfo.FileDescription -like "HP *")) {
                Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                Write-Verbose -Verbose "InternalName: $($Item.VersionInfo.InternalName)"
                Write-Verbose -Verbose "OriginalFilename: $($Item.VersionInfo.OriginalFilename)"
                Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                $DestinationPath = Join-Path $Item.Directory $Item.BaseName

                if (-NOT (Test-Path "$DestinationPath")) {
                    Write-Verbose -Verbose "Expanding HP Driver Pack to $DestinationPath"
                    Start-Process -FilePath $ExpandFile -ArgumentList "/s /e /f `"$DestinationPath`"" -Wait

                    New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                    New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                    pnpunattend.exe AuditSystem /L
                    Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                }
                Continue
            }
        }
        #=================================================
        # Lenovo
        #=================================================
        if ($Item.Extension -eq '.exe') {
            if (($Item.VersionInfo.FileDescription -match 'Lenovo') -or ($Item.Name -match 'tc_') -or ($Item.Name -match 'tp_') -or ($Item.Name -match 'ts_') -or ($Item.Name -match '500w') -or ($Item.Name -match 'sccm_') -or ($Item.Name -match 'm710e') -or ($Item.Name -match 'tp10') -or ($Item.Name -match 'tp8') -or ($Item.Name -match 'yoga')) {
                Write-Verbose -Verbose "FileDescription: $($Item.VersionInfo.FileDescription)"
                Write-Verbose -Verbose "ProductVersion: $($Item.VersionInfo.ProductVersion)"

                $DestinationPath = Join-Path $Item.Directory 'SCCM'

                if (-NOT (Test-Path "$DestinationPath")) {
                    Write-Verbose -Verbose "Expanding Lenovo Driver Pack to $DestinationPath"
                    Start-Process -FilePath $ExpandFile -ArgumentList "/SILENT /SUPPRESSMSGBOXES" -Wait

                    New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                    New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                    pnpunattend.exe AuditSystem /L
                    Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
                }
                Continue
            }
        }
        #=================================================
        # MSI
        #=================================================
        if ($Item.Extension -eq '.msi') {
            $DateStamp = Get-Date -Format yyyyMMddTHHmmss
            $logFile = '{0}-{1}.log' -f $ExpandFile,$DateStamp
            $MSIArguments = @(
                "/i"
                ('"{0}"' -f $ExpandFile)
                "/qb"
                "/norestart"
                "/L*v"
                $logFile
            )
            Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
            Continue
        }
        #=================================================
        # Zip
        #=================================================
        if ($Item.Extension -eq '.zip') {
            $DestinationPath = Join-Path $Item.Directory $Item.BaseName

            if (-NOT (Test-Path "$DestinationPath")) {
                Write-Verbose -Verbose "Expanding ZIP Driver Pack to $DestinationPath"
                Expand-Archive -Path $ExpandFile -DestinationPath $DestinationPath -Force

                New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths" -Name 1 -Force
                New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Name Path -Value $DestinationPath -Force
                pnpunattend.exe AuditSystem /L
                Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UnattendSettings\PnPUnattend\DriverPaths\1" -Recurse -Force
            }
            Continue
        }
        #=================================================
        # Everything Else
        #=================================================
        Write-Warning "Unable to expand $ExpandFile"
        #=================================================
    }
}
function Get-MyDriverPack {
    <#
    .SYNOPSIS
    Retrieves the driver pack for the current computer from OSDCloud
 
    .DESCRIPTION
    Queries OSDCloud for a matching driver pack based on computer manufacturer and product model.
 
    .PARAMETER Manufacturer
    Computer manufacturer. Default is auto-detected from current system
 
    .PARAMETER Product
    Computer product model. Default is auto-detected from current system
 
    .EXAMPLE
    Get-MyDriverPack
    Returns the driver pack for the current computer
 
    .EXAMPLE
    Get-MyDriverPack -Manufacturer 'Lenovo' -Product 'ThinkPad X1'
    Returns the driver pack for the specified model
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param (
        [System.String]$Manufacturer = (Get-MyComputerManufacturer -Brief),
        [System.String]$Product = (Get-MyComputerProduct)
    )
    #=================================================
    # Set ErrorActionPreference
    #=================================================
    $ErrorActionPreference = 'SilentlyContinue'
    #=================================================
    # Action
    #=================================================
    $Results = Get-OSDCloudDriverPacks | Where-Object {($_.Product -contains $Product)}
    #=================================================
    # Results
    #=================================================
    if ($Results) {
        $Results = $Results | Sort-Object -Property Name -Descending
        $Results[0]
    }
    else {
        Write-Verbose "$Manufacturer $Product is not supported"
    }
    #=================================================
}
function Save-MyDriverPack {
    <#
    .SYNOPSIS
    Downloads and optionally expands the driver pack for the current computer
 
    .DESCRIPTION
    Downloads the matching driver pack from OSDCloud for the current or specified computer. Can optionally extract and expand the driver pack after download.
 
    .PARAMETER DownloadPath
    Directory where the driver pack will be saved. Default is C:\Drivers
 
    .PARAMETER Expand
    Automatically expands the driver pack archive after download
 
    .PARAMETER Manufacturer
    Computer manufacturer. Default is auto-detected
 
    .PARAMETER Product
    Computer product model. Default is auto-detected
 
    .PARAMETER Guid
    GUID of a specific driver pack to download
 
    .EXAMPLE
    Save-MyDriverPack
    Downloads the driver pack for the current computer to C:\Drivers
 
    .EXAMPLE
    Save-MyDriverPack -DownloadPath 'D:\DriverPacks' -Expand
    Downloads and expands the driver pack to D:\DriverPacks
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [System.String]$DownloadPath = 'C:\Drivers',
        [System.Management.Automation.SwitchParameter]$Expand,
        [System.String]$Manufacturer = (Get-MyComputerManufacturer -Brief),
        [System.String]$Product = (Get-MyComputerProduct),
        [System.String]
        $Guid
    )
    Write-Verbose "Manufacturer: $Manufacturer"
    Write-Verbose "Product: $Product"
    #=================================================
    # Block
    #=================================================
    if ($Expand) {
        $CurrentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
        $CurrentPrincipal = [Security.Principal.WindowsPrincipal]::new($CurrentIdentity)
        if (-not $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
            Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Administrative rights are required"
            return
        }
    }
    Block-WindowsVersionNe10
    #=================================================
    # Get-MyDriverPack
    #=================================================
    if ($Guid) {
        $GetMyDriverPack = Get-OSDCloudDriverPacks | Where-Object {$_.Guid -eq $Guid} | Select-Object -First 1
    }
    else {
        $GetMyDriverPack = Get-MyDriverPack -Manufacturer $Manufacturer -Product $Product
    }

    if ($GetMyDriverPack) {
        $OutFile = Join-Path $DownloadPath $GetMyDriverPack.FileName
        #=================================================
        # Save-WebFile
        #=================================================
        if (-NOT (Test-Path "$DownloadPath")) {
            New-Item $DownloadPath -ItemType Directory -Force -ErrorAction Stop | Out-Null
        }

        Write-Verbose "CatalogVersion: $($GetMyDriverPack.CatalogVersion)"
        Write-Verbose "Name: $($GetMyDriverPack.Name)"
        Write-Verbose "Product: $($GetMyDriverPack.Product)"
        Write-Verbose "Url: $($GetMyDriverPack.Url)"
        Write-Verbose "OutFile: $OutFile"

        Save-WebFile -SourceUrl $GetMyDriverPack.Url -DestinationDirectory $DownloadPath -DestinationName $GetMyDriverPack.FileName

        if (! (Test-Path $OutFile)) {
            Write-Warning "[$(Get-Date -format s)] Driver Pack failed to download"
        }
        else {
            $GetItemOutFile = Get-Item $OutFile
        }
        $GetMyDriverPack | ConvertTo-Json | Out-File "$OutFile.json" -Encoding ascii -Width 2000 -Force
        #=================================================
        # Expand
        #=================================================
        if ($GetItemOutFile) {
            if ($PSBoundParameters.ContainsKey('Expand')) {

                $ExpandFile = $GetItemOutFile.FullName
                Write-Verbose "DriverPack: $ExpandFile"
                #=================================================
                # Cab
                #=================================================
                if ($GetItemOutFile.Extension -eq '.cab') {
                    $DestinationPath = Join-Path $GetItemOutFile.Directory $GetItemOutFile.BaseName

                    if (-NOT (Test-Path "$DestinationPath")) {
                        New-Item $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null

                        Write-Verbose -Verbose "Expanding CAB Driver Pack to $DestinationPath"
                        Expand -R "$ExpandFile" -F:* "$DestinationPath" | Out-Null
                    }
                }
                #=================================================
                # Dell
                #=================================================
                if ($GetItemOutFile.Extension -eq '.exe') {
                    if ($GetItemOutFile.VersionInfo.FileDescription -match 'Dell') {
                        Write-Verbose -Verbose "FileDescription: $($GetItemOutFile.VersionInfo.FileDescription)"
                        Write-Verbose -Verbose "ProductVersion: $($GetItemOutFile.VersionInfo.ProductVersion)"

                        $DestinationPath = Join-Path $GetItemOutFile.Directory $GetItemOutFile.BaseName

                        if (-NOT (Test-Path "$DestinationPath")) {
                            Write-Verbose -Verbose "Expanding Dell Driver Pack to $DestinationPath"
                            $null = New-Item -Path $DestinationPath -ItemType Directory -Force -ErrorAction Ignore | Out-Null
                            Start-Process -FilePath $ExpandFile -ArgumentList "/s /e=`"$DestinationPath`"" -Wait
                        }
                    }
                }
                #=================================================
                # HP
                #=================================================
                if (($GetItemOutFile.Extension -eq '.exe') -and ($env:SystemDrive -ne 'X:')) {
                    if (($GetItemOutFile.VersionInfo.InternalName -match 'hpsoftpaqwrapper') -or ($GetItemOutFile.VersionInfo.OriginalFilename -match 'hpsoftpaqwrapper.exe') -or ($GetItemOutFile.VersionInfo.FileDescription -like "HP *")) {
                        Write-Verbose "FileDescription: $($GetItemOutFile.VersionInfo.FileDescription)"
                        Write-Verbose "InternalName: $($GetItemOutFile.VersionInfo.InternalName)"
                        Write-Verbose "OriginalFilename: $($GetItemOutFile.VersionInfo.OriginalFilename)"
                        Write-Verbose "ProductVersion: $($GetItemOutFile.VersionInfo.ProductVersion)"

                        $DestinationPath = Join-Path $GetItemOutFile.Directory $GetItemOutFile.BaseName

                        if (-NOT (Test-Path "$DestinationPath")) {
                            Write-Verbose -Verbose "Expanding HP Driver Pack to $DestinationPath"
                            Start-Process -FilePath $ExpandFile -ArgumentList "/s /e /f `"$DestinationPath`"" -Wait
                        }
                    }
                }
                #=================================================
                # Lenovo
                #=================================================
                if (($GetItemOutFile.Extension -eq '.exe') -and ($env:SystemDrive -ne 'X:')) {
                    if (($GetItemOutFile.VersionInfo.FileDescription -match 'Lenovo') -or ($GetItemOutFile.Name -match 'tc_') -or ($GetItemOutFile.Name -match 'tp_') -or ($GetItemOutFile.Name -match 'ts_') -or ($GetItemOutFile.Name -match '500w') -or ($GetItemOutFile.Name -match 'sccm_') -or ($GetItemOutFile.Name -match 'm710e') -or ($GetItemOutFile.Name -match 'tp10') -or ($GetItemOutFile.Name -match 'tp8') -or ($GetItemOutFile.Name -match 'yoga')) {
                        Write-Verbose "FileDescription: $($GetItemOutFile.VersionInfo.FileDescription)"
                        Write-Verbose "ProductVersion: $($GetItemOutFile.VersionInfo.ProductVersion)"

                        $DestinationPath = Join-Path $GetItemOutFile.Directory 'SCCM'

                        if (-NOT (Test-Path "$DestinationPath")) {
                            Write-Verbose -Verbose "Expanding Lenovo Driver Pack to $DestinationPath"
                            Start-Process -FilePath $ExpandFile -ArgumentList "/SILENT /SUPPRESSMSGBOXES" -Wait
                        }
                    }
                }
                #=================================================
                # MSI
                #=================================================
                if (($GetItemOutFile.Extension -eq '.msi') -and ($env:SystemDrive -ne 'X:')) {
                    $DestinationPath = Join-Path $GetItemOutFile.Directory $GetItemOutFile.BaseName

                    if (-NOT (Test-Path "$DestinationPath")) {
                        #Need to sort out what to do here
                    }
                }
                #=================================================
                # Everything Else
                #=================================================
                #Write-Warning "Unable to expand $ExpandFile"
            }
        }
    }
}
function Save-ZTIDriverPack {
    <#
    .SYNOPSIS
    Downloads the driver pack for a computer during MDT/ConfigMgr task sequence
 
    .DESCRIPTION
    Downloads and stages the matching driver pack from OSDCloud during Lite Touch or Zero Touch deployment. Requires an active task sequence environment.
 
    .PARAMETER Manufacturer
    Computer manufacturer. Default is auto-detected
 
    .PARAMETER Product
    Computer product model. Default is auto-detected
 
    .EXAMPLE
    Save-ZTIDriverPack
    Downloads the driver pack for the current computer during task sequence
 
    .EXAMPLE
    Save-ZTIDriverPack -Manufacturer 'Dell' -Product 'Latitude 5420'
    Downloads the driver pack for a specific Dell model
 
    .LINK
    https://github.com/OSDeploy/OSD/tree/master/docs
 
    .NOTES
    Author: David Segura - Recast Software
    2026-07-10 - Added comment-based help
    #>

    [CmdletBinding()]
    param (
        [string]$Manufacturer = (Get-MyComputerManufacturer -Brief),
        [string]$Product = (Get-MyComputerProduct)
    )
    #=================================================
    # Make sure we are running in a Task Sequence first
    #=================================================
    try {
        $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
    }
    catch {
        $TSEnv = $false
    }

    if ($TSEnv -eq $false) {
        Write-Warning "This functions requires a running Task Sequence"
        Start-Sleep -Seconds 5
        Continue
    }
    #=================================================
    # Get some Task Sequence variables
    #=================================================
    $DEPLOYROOT = $TSEnv.Value("DEPLOYROOT")
    $DEPLOYDRIVE = $TSEnv.Value("DEPLOYDRIVE") # Z:
    $OSVERSION = $TSEnv.Value("OSVERSION") # WinPE
    $RESOURCEDRIVE = $TSEnv.Value("RESOURCEDRIVE") # Z:
    $OSDISK = $TSEnv.Value("OSDISK") # E:
    $OSDANSWERFILEPATH = $TSEnv.Value("OSDANSWERFILEPATH") # E:\MININT\Unattend.xml
    $TARGETPARTITIONIDENTIFIER = $TSEnv.Value("TARGETPARTITIONIDENTIFIER") # [SELECT * FROM Win32_LogicalDisk WHERE Size = '134343553024' and VolumeName = 'Windows' and VolumeSerialNumber = '90D39B87']
    #=================================================
    # Set some Variables
    # DeployRootDriverPacks are where DriverPacks must be staged
    # This is not working out so great at the moment, so I would suggest
    # not doing this yet
    #=================================================
    $DeployRootDriverPacks = Join-Path $DEPLOYROOT 'DriverPacks'
    $OSDiskDrivers = Join-Path $OSDISK 'Drivers'
    #=================================================
    # Create $OSDiskDrivers
    #=================================================
    if (-NOT (Test-Path -Path $OSDiskDrivers)) {
        New-Item -Path $OSDiskDrivers -ItemType Directory -Force -ErrorAction Ignore | Out-Null
    }
    if (-NOT (Test-Path -Path $OSDiskDrivers)) {
        Write-Warning "Could not create $OSDiskDrivers"
        Start-Sleep -Seconds 5
        Continue
    }
    #=================================================
    # Start-Transcript
    #=================================================
    Start-Transcript -OutputDirectory $OSDiskDrivers
    #=================================================
    # Copy-PSModuleToFolder
    # The OSD Module needs to be available on the next boot for Specialize
    # Drivers to work
    #=================================================
    if ($env:SystemDrive -eq 'X:') {
        Copy-PSModuleToFolder -Name OSD -Destination "$OSDISK\Program Files\WindowsPowerShell\Modules"
    }
    #=================================================
    # Get-MyDriverPack
    #=================================================
    Write-Verbose -Verbose "Processing function Get-MyDriverPack"
    if ($Manufacturer -in ('Dell','HP','Lenovo','Microsoft')) {
        $GetMyDriverPack = Get-MyDriverPack -Manufacturer $Manufacturer -Product $Product
    }
    else {
        $GetMyDriverPack = Get-MyDriverPack -Product $Product
    }
    if (-NOT ($GetMyDriverPack)) {
        Write-Warning "There are no DriverPacks for this computer"
        Start-Sleep -Seconds 5
        Continue
    }
    #=================================================
    # Get-MyDriverPack
    #=================================================
    Write-Verbose -Verbose "Name: $($GetMyDriverPack.Name)"
    Write-Verbose -Verbose "Product: $($GetMyDriverPack.Product)"
    Write-Verbose -Verbose "FileName: $($GetMyDriverPack.FileName)"
    Write-Verbose -Verbose "Url: $($GetMyDriverPack.Url)"
    $OSDiskDriversFile = Join-Path $OSDiskDrivers $GetMyDriverPack.FileName
    #=================================================
    # MDT DeployRoot DriverPacks
    # See if the DriverPack we need exists in $DeployRootDriverPacks
    #=================================================
    $DeployRootDriverPack = @()
    $DeployRootDriverPack = Get-ChildItem "$DeployRootDriverPacks\" -Include $GetMyDriverPack.FileName -File -Recurse -Force -ErrorAction Ignore | Select-Object -First 1
    if ($DeployRootDriverPack) {
        Write-Verbose -Verbose "Source: $($DeployRootDriverPack.FullName)"
        Write-Verbose -Verbose "Destination: $OSDiskDriversFile"
        Copy-Item -Path $($DeployRootDriverPack.FullName) -Destination $OSDiskDrivers -Force
    }

    if (Test-Path $OSDiskDriversFile) {
        Write-Verbose -Verbose "DriverPack is in place and ready to go"
        Stop-Transcript
        Continue
    }
    #=================================================
    # Curl
    # Make sure Curl is available
    #=================================================
    if ((-NOT (Test-Path "$env:SystemRoot\System32\curl.exe")) -and (-NOT (Test-Path "$OSDISK\Windows\System32\curl.exe"))) {
        Write-Warning "Curl is required for this to function"
        Start-Sleep -Seconds 5
        Continue
    }
    if ((-NOT (Test-Path "$env:SystemRoot\System32\curl.exe")) -and (Test-Path "$OSDISK\Windows\System32\curl.exe")) {
        Copy-Item -Path "$OSDISK\Windows\System32\curl.exe" -Destination "$env:SystemRoot\System32\curl.exe" -Force
    }

    if (-NOT (Test-Path "$env:SystemRoot\System32\curl.exe")) {
        Write-Warning "Curl is required for this to function"
        Start-Sleep -Seconds 5
        Continue
    }
    #=================================================
    # OSDCloud DriverPacks
    # Finally, let's download the file and see where this goes
    #=================================================
    Save-WebFile -SourceUrl $GetMyDriverPack.Url -DestinationDirectory $OSDiskDrivers -DestinationName $GetMyDriverPack.FileName

    if (Test-Path $OSDiskDriversFile) {
        Write-Verbose -Verbose "DriverPack is in place and ready to go"
        Stop-Transcript
    }
    else {
        Write-Warning "Could not download the DriverPack. Sorry!"
        Stop-Transcript
    }
    #=================================================
}