OpenDriverTool.psm1

#Region './public/Get-KnownModels.ps1' -1

function Get-KnownModels {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [ValidateSet('Dell', 'Microsoft')]
        [string]
        $Make,

        [Parameter(Mandatory)]
        [string]
        $SiteCode,

        [Parameter(Mandatory)]
        [string]
        $SiteServerFQDN
    )

    Connect-SCCM -SiteCode $SiteCode -SiteServerFQDN $SiteServerFQDN

    Push-Location ('{0}:' -f $SiteCode)

    switch ($Make) {
        'Dell' {
            $DellCompSys = "Select Distinct Manufacturer, Model from SMS_G_System_COMPUTER_SYSTEM Where Manufacturer = 'Dell Inc.' and (Model like 'Optiplex%' or Model like 'Latitude%' or Model like 'Precision%' or Model like 'XPS%')"
            $DellMSInfo = "Select Distinct SystemManufacturer, SystemProductName, SystemSKU from SMS_G_System_MS_SystemInformation Where BaseBoardManufacturer = 'Dell Inc.'"
            
            try {
                $Result = Invoke-CMWmiQuery -Query $DellMSInfo -Option FastExpectResults
                break
            } catch {
                Write-Warning -Message "Unable to query the MS_SystemInformation class. Is this class enabled in your hardware inventory?"
                Write-Warning -Message "Will query SMS_G_System_COMPUTER_SYSTEM instead."
            }

            $Result = Invoke-CMWmiQuery -Query $DellCompSys -Option FastExpectResults

        }
        'Microsoft' {
            $MicrosoftMSInfo = "Select Distinct SystemManufacturer, SystemProductName, SystemSKU from SMS_G_System_MS_SYSTEMINFORMATION Where SystemManufacturer like 'Microsoft%' and SystemProductName like 'Surface%'"

            try {
                $Result = Invoke-CMWmiQuery -Query $MicrosoftMSInfo -Option FastExpectResults
            } catch {
                Write-Error -Message "Unable to query the MS_SystemInformation class. Is this class enabled in your hardware inventory?"
            }
        }
    }

    Pop-Location

    Write-Output $Result
}
#EndRegion './public/Get-KnownModels.ps1' 54
#Region './public/Remove-Packages.ps1' -1

function Remove-Packages {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param (
        [Parameter(Mandatory)]
        [ValidateSet('Dell', 'Microsoft')]
        [string]
        $Make,

        [Parameter(Mandatory)]
        [ValidateSet('Drivers', 'BIOS Update')]
        [string]
        $PackageType,

        [Parameter(Mandatory)]
        [string]
        $SiteCode,

        [Parameter(Mandatory)]
        [string]
        $SiteServerFQDN
    )

    $SearchString = '{0} - {1} *' -f $PackageType, $Make

    Write-Debug -Message $SearchString

    Connect-SCCM -SiteCode $SiteCode -SiteServerFQDN $SiteServerFQDN

    Push-Location ('{0}:' -f $SiteCode)

    $QueryResult = Get-CMPackage -Name $SearchString -Fast

    $CMPackages = $QueryResult | Group-Object Name | Where-Object Count -gt 1

    foreach ($Group in $CMPackages) {

        $PkgsToDelete = $Group.Group | Sort-Object -Property SourceDate | Select-Object -First ($Group.Count - 1)

        foreach ($Package in $PkgsToDelete) {
            if ($PSCmdlet.ShouldProcess("$($Package.Name) Version: $($Package.Version)", "Remove Package")) {

                Remove-CMPackage -InputObject $Package -Force

                Pop-Location

                if (Test-Path $Package.PkgSourcePath) {
                   Remove-Item -Path $Package.PkgSourcePath -Recurse -Force
                }

                Push-Location ('{0}:' -f $SiteCode)
            }
        }
    }

    Pop-Location
}
#EndRegion './public/Remove-Packages.ps1' 57
#Region './public/Update-DellBios.ps1' -1

function Update-DellBios {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [string]
        $Model,

        [Parameter()]
        [io.directoryInfo]
        $WorkingDir,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [Alias('Destination')]
        [io.directoryInfo]
        $ContentShare,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteCode,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteServerFQDN,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPoints,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPointGroups,
        
        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [switch]
        $DownloadOnly
    )

    if (-not $WorkingDir) {
        $WorkingDir = Path-Creator -Parent $env:TEMP -Child 'OpenDriverTool'
    }

    "Updating Bios for Dell $Model" | Log

    Path-Creator -Parent $WorkingDir -Child 'Content' | Out-Null

    $DriverPackCatalogUrl = 'https://downloads.dell.com/catalog/DriverPackCatalog.CAB'
    $CatalogPCUrl         = 'https://downloads.dell.com/catalog/CatalogPC.cab'
    

    ' Getting Dell cabinet files...' | Log
    ' Downloading: {0}' -f $DriverPackCatalogUrl | Log
    $DriverPackCatalogCAB = $DriverPackCatalogUrl | Get-RemoteFile -Destination $WorkingDir

    ' Downloading: {0}' -f $CatalogPCUrl | Log
    $CatalogPCCAB = $CatalogPCUrl | Get-RemoteFile -Destination $WorkingDir

    Expand-Cab -Path $DriverPackCatalogCAB -Destination $WorkingDir\Content
    Expand-Cab -Path $CatalogPCCAB -Destination $WorkingDir\Content

    [xml] $DriverPackCatalog = Get-Content -Path "$WorkingDir\Content\DriverPackCatalog.xml"
    [xml] $CatalogPC = Get-Content -Path "$WorkingDir\Content\CatalogPC.xml"

    $BIOS = Find-DellBIOS -Model $Model -DriverPackCatalog $DriverPackCatalog -CatalogPC $CatalogPC

    if (-not $BIOS) {
        Write-Error -Message "Failed to find BIOS. Please verify the name of your model is correct." -ErrorAction Stop
    }

    ' Found BIOS: {0}' -f $BIOS.path | Log

    $BIOSPackage = @{
        Name = 'BIOS Update - {0} {1}' -f 'Dell', $Model
        Manufacturer = 'Dell'
        Version = $BIOS.dellVersion
        Description = '(Models included:{0})' -f ($BIOS.SupportedSystems.Brand.Model.systemID -join ';')
    }

    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {
        Connect-SCCM -SiteCode $SiteCode -SiteServerFQDN $SiteServerFQDN
        $ExistingPackage = Confirm-ExistingPackage -Package $BIOSPackage -SiteCode $SiteCode
    }

    if ($ExistingPackage) {
        ' Latest driver already in configmgr.' | Log
        return
    }

    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {

        $Flash64Url = 'https://downloads.dell.com/FOLDER08405216M/1/Ver3.3.16.zip'

        "`n BIOS version not found in configmgr" | Log

        ' Downloading: {0}' -f $BIOS.path | Log
        $BIOSFile = Get-RemoteFile -Url ('{0}/{1}' -f 'https://downloads.dell.com', $BIOS.path) -Destination $WorkingDir -Hash $BIOS.hashMD5 -Algorithm MD5

        ' Downloading: {0}' -f $Flash64Url | Log
        $Flash64Zip = Get-RemoteFile -Url $Flash64Url -Destination $WorkingDir

        $Flash64Extract = Expand-Archive -Path $Flash64Zip -DestinationPath $WorkingDir -Force -PassThru | Where-Object Name -eq 'Flash64W.exe'

        $BIOSPath = (
            'Dell',
            $Model,
            'BIOS',
            $BIOS.dellVersion
        )

        $BIOSContent = Path-Creator -Parent $ContentShare -Child $BIOSPath

        Copy-Item -Path $BIOSFile -Destination $BIOSContent
        Copy-Item -Path $Flash64Extract -Destination $BIOSContent

        ' Creating bios package in sccm.'
        $CMPackage = New-Package -Package $BIOSPackage -Type 'BIOS' -SiteCode $SiteCode -ContentPath $BIOSContent -Make $Make

        switch ($PSBoundParameters.Keys) {
            'DistributionPoints'      { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPoints $DistributionPoints }
            'DistributionPointGroups' { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPointGroups $DistributionPointGroups }
        }

    }

    if ($PSCmdlet.ParameterSetName -eq 'DownloadOnly') {
        if (-not (Test-Path $ContentShare)) {
            New-Item -Path $ContentShare -ItemType Directory | Out-Null
        }

        ' Downloading: {0}' -f $BIOS.path | Log
        $BIOSFile = Get-RemoteFile -Url ('{0}/{1}' -f 'https://downloads.dell.com', $BIOS.path) -Destination $ContentShare -Hash $BIOS.hashMD5 -Algorithm MD5

        ' Downloaded: {0}' -f $BIOSFile.FullName | Log
    }
}
#EndRegion './public/Update-DellBios.ps1' 147
#Region './public/Update-DellDriver.ps1' -1

function Update-DellDriver {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [string]
        $Model,

        [Parameter(Mandatory)]
        [ValidateSet('Windows 10', 'Windows 11')]
        [string]
        $OSVersion,

        [Parameter()]
        [io.directoryInfo]
        $WorkingDir,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [Alias('Destination')]
        [io.directoryInfo]
        $ContentShare,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteCode,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteServerFQDN,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPoints,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPointGroups,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [switch]
        $DownloadOnly
    )

    if (-not $WorkingDir) {
        $WorkingDir = Path-Creator -Parent $env:TEMP -Child 'OpenDriverTool'
    }

    "Updating drivers for Dell $Model" | Log

    Path-Creator -Parent $WorkingDir -Child 'Content' | Out-Null

    $DriverPackCatalogUrl = 'https://downloads.dell.com/catalog/DriverPackCatalog.CAB'

    ' Getting Dell cabinet files...' | Log
    ' Downloading: {0}' -f $DriverPackCatalogUrl | Log
    $DriverPackCatalogCAB = $DriverPackCatalogUrl | Get-RemoteFile -Destination $WorkingDir

    Expand-Cab -Path $DriverPackCatalogCAB -Destination $WorkingDir\Content

    [xml] $DriverPackCatalog = Get-Content -Path "$WorkingDir\Content\DriverPackCatalog.xml"

    $Driver = Find-DellDrivers -DriverPackCatalog $DriverPackCatalog -Model $Model -OSVersion ($OSVersion -replace '\s', '')

    if (-not $Driver) {
        Write-Error "Failed to find a driver. Verify that the name of the model is correct and a pack is published for $OSVersion" -ErrorAction Stop
    } 

    ' Found Driver: {0}' -f $Driver.path | Log

    $DriverPackage = @{
        Name = 'Drivers - {0} {1} - {2} {3}' -f 'Dell', $Model, $OSVersion, $Driver.SupportedOperatingSystems.OperatingSystem.osArch
        Version = $Driver.dellVersion
        Manufacturer = 'Dell'
        Description = '(Models included:{0})' -f ($Driver.SupportedSystems.brand.model.systemID -join ';')
    }

    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {
        Connect-SCCM -SiteCode $SiteCode -SiteServerFQDN $SiteServerFQDN
        $ExistingPackage = Confirm-ExistingPackage -Package $DriverPackage -SiteCode $SiteCode
    }

    if ($ExistingPackage) {
        ' Latest driver already in configmgr.' | Log
        return
    }

    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {
        "`n Driver version not found in configmgr" | Log
        
        ' Downloading: {0}' -f $Driver.path  | Log
        $DriverFile = Get-RemoteFile -Url ('{0}/{1}' -f 'https://downloads.dell.com', $Driver.path) -Destination $WorkingDir -Hash $Drivers.hashMD5 -Algorithm MD5

        ' Extracting: {0}' -f $DriverFile.FullName| Log
        $ExtractedContent = Expand-Drivers -Make 'Dell' -Path $DriverFile -Destination $WorkingDir

        ' Compressing driver package.'
        $Archive = Compress-Drivers -ContentPath $ExtractedContent

        $DriverPath = (
            'Dell',
            $Model,
            'Driver',
            $OSVersion,
            $Driver.dellVersion
        )

        $DriverContent = Path-Creator -Parent $ContentShare -Child $DriverPath

        Copy-Item -Path $Archive -Destination $DriverContent


        ' Creating driver package in sccm.'
        $CMPackage = New-Package -Package $DriverPackage -Type 'Driver' -SiteCode $SiteCode -ContentPath $DriverContent -Make 'Dell'

        switch ($PSBoundParameters.Keys) {
            'DistributionPoints'      { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPoints $DistributionPoints }
            'DistributionPointGroups' { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPointGroups $DistributionPointGroups }
        }

    }

    if ($PSCmdlet.ParameterSetName -eq 'DownloadOnly') {
        if (-not (Test-Path $ContentShare)) {
            New-Item -Path $ContentShare -ItemType Directory | Out-Null
        }

        ' Downloading: {0}' -f $Driver.path  | Log
        $DriverFile = Get-RemoteFile -Url ('{0}/{1}' -f 'https://downloads.dell.com', $Driver.path) -Destination $ContentShare -Hash $Drivers.hashMD5 -Algorithm MD5

        ' Downloaded: {0}' -f $DriverFile.FullName | Log
    }

}
#EndRegion './public/Update-DellDriver.ps1' 145
#Region './public/Update-MicrosoftDriver.ps1' -1

function Update-MicrosoftDriver {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [string]
        $Model,

        [Parameter(Mandatory)]
        [ValidateSet('Windows 10', 'Windows 11')]
        [string]
        $OSVersion,

        [Parameter()]
        [io.directoryInfo]
        $WorkingDir,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [Alias('Destination')]
        [io.directoryInfo]
        $ContentShare,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteCode,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteServerFQDN,
  
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPoints,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPointGroups,
        
        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [switch]
        $DownloadOnly
    )
    
    if (-not $WorkingDir) {
        $WorkingDir = Path-Creator -Parent $env:TEMP -Child 'OpenDriverTool'
    }

    "Updating drivers for Microsoft $Model" | Log

    ' Checking catalog for available driver.' | Log
    
    $Driver = Find-MicrosoftDriver -Model $Model -OSVersion $OSVersion

    if (-not $Driver) {
        Write-Error -Message 'Unable to find a driver for the specified model. Please reference https://raw.githubusercontent.com/OSDeploy/OSD/master/Catalogs/MicrosoftDriverPackCatalog.json for "Product" models.' -ErrorAction Stop
    } 

    ' Found Driver: {0}' -f $Driver.FileName | Log

    $DriverPackage = @{
        Name = 'Drivers - {0} {1} - {2}' -f 'Microsoft', $Model, $Driver.OSVersion
        Version = ($Driver.FileName -split '_' | Select-Object -last 1).trim('.msi')
        Manufacturer = 'Microsoft'
        Description = '(Models included:{0})' -f $Driver.Product
    }

    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {
        Connect-SCCM -SiteCode $SiteCode -SiteServerFQDN $SiteServerFQDN
        $ExistingPackage = Confirm-ExistingPackage -Package $DriverPackage -SiteCode $SiteCode
    }

    if ($ExistingPackage) {
        ' Latest driver already in configmgr.' | Log
        return
    }
    
    if ($PSCmdlet.ParameterSetName -ne 'DownloadOnly') {

        "`n Driver version not found in configmgr" | Log
        
        ' Downloading: {0}' -f $Driver.FileName  | Log
        $DriverFile = Get-RemoteFile -Url $Driver.Url -Destination $WorkingDir

        ' Extracting: {0}' -f $DriverFile.FullName | Log
        $ExtractedContent = Expand-Drivers -Make 'Microsoft' -Path $DriverFile -Destination $WorkingDir

        ' Compressing driver package.'
        $Archive = Compress-Drivers -ContentPath $ExtractedContent

        $DriverPath = (
            'Microsoft',
            $Model,
            'Driver',
            $OSVersion,
            $DriverPackage.Version
        )

        $DriverContent = Path-Creator -Parent $ContentShare -Child $DriverPath

        Copy-Item -Path $Archive -Destination $DriverContent


        ' Creating driver package in sccm.'
        $CMPackage = New-Package -Package $DriverPackage -Type 'Driver' -SiteCode $SiteCode -ContentPath $DriverContent -Make 'Microsoft'

        switch ($PSBoundParameters.Keys) {
            'DistributionPoints'      { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPoints $DistributionPoints }
            'DistributionPointGroups' { Start-ContentDistribution -CMPackage $CMPackage -SiteCode $SiteCode -DistributionPointGroups $DistributionPointGroups }
        }

    } 

    if ($PSCmdlet.ParameterSetName -eq 'DownloadOnly') {
        if (-not (Test-Path $ContentShare)) {
            New-Item -Path $ContentShare -ItemType Directory | Out-Null
        }

        ' Downloading: {0}' -f $Driver.FileName  | Log
        $DriverFile = Get-RemoteFile -Url $Driver.Url -Destination $ContentShare

        ' Downloaded: {0}' -f $DriverFile.FullName | Log
    }

}
#EndRegion './public/Update-MicrosoftDriver.ps1' 136
#Region './public/Update-Model.ps1' -1

function Update-Model {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [ValidateSet('Dell', 'Microsoft')]
        [string]
        $Make,

        [Parameter(Mandatory)]
        [string]
        $Model,

        [Parameter(Mandatory)]
        [ValidateSet('Windows 10', 'Windows 11')]
        [string]
        $OSVersion,

        [Parameter()]
        [ValidateSet('Driver', 'Bios', 'Both')]
        [string]
        $DownloadType = 'Both',

        [Parameter()]
        [io.directoryInfo]
        $WorkingDir,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [Alias('Destination')]
        [io.directoryInfo]
        $ContentShare,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteCode,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [string]
        $SiteServerFQDN,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPoints,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [Parameter(Mandatory, ParameterSetName = 'PointAndGroup')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPointGroups,

        [Parameter(Mandatory, ParameterSetName = 'DownloadOnly')]
        [switch]
        $DownloadOnly
    )

    if (-not $WorkingDir) {
        $WorkingDir = Path-Creator -Parent $env:TEMP -Child 'OpenDriverTool'
    }

    "Updating $Make $Model" | Log

    $Driver = @{
        Model = $Model
        OSVersion = $OSVersion
        WorkingDir = $WorkingDir
        ContentShare = $ContentShare
    }

    $Bios = @{
        Model = $Model
        WorkingDir = $WorkingDir
        ContentShare = $ContentShare
    }

    if ($PSCmdlet.ParameterSetName -eq 'DownloadOnly') {
        $Driver.Add('DownloadOnly', $true)
        $Bios.Add('DownloadOnly', $true)
    } else {
        $Driver.Add('SiteCode', $SiteCode)
        $Driver.Add('SiteServerFQDN', $SiteServerFQDN)
        $Bios.Add('SiteCode', $SiteCode)
        $Bios.Add('SiteServerFQDN', $SiteServerFQDN)
    }

    if ($DistributionPoints) {
        $Driver.Add('DistributionPoints', $DistributionPoints)
        $Bios.Add('DistributionPoints', $DistributionPoints)
    }

    if ($DistributionPointGroups) {
        $Driver.Add('DistributionPointGroup', $DistributionPointGroups)
        $Bios.Add('DistributionPointGroup', $DistributionPointGroups)
    }

    switch ($Make) {
        'Dell' {
            if ($DownloadType -eq 'Driver' -or $DownloadType -eq 'Both') {
                Update-DellDriver @Driver
            }

            if ($DownloadType -eq 'Bios' -or $DownloadType -eq 'Both') {
                Update-DellBios @Bios
            }
        }

        'Microsoft' {
            Update-MicrosoftDriver @Driver
        }
    }

    Clean-Temp -Path $WorkingDir
}
#EndRegion './public/Update-Model.ps1' 122
#Region './private/Clean-Temp.ps1' -1

function Clean-Temp {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [io.directoryInfo]
        $Path
    )
    
    Get-ChildItem -Path $Path | Remove-Item -Recurse -Force
}
#EndRegion './private/Clean-Temp.ps1' 11
#Region './private/Compress-Drivers.ps1' -1

function Compress-Drivers {
    param (
        [Parameter(Mandatory)]
        [io.directoryInfo]
        $ContentPath
    )

    $Child = Get-ChildItem $ContentPath

    Compress-Archive -Path $Child -DestinationPath $ContentPath\DriverPackage.zip -PassThru

}
#EndRegion './private/Compress-Drivers.ps1' 13
#Region './private/Confirm-ExistingPackage.ps1' -1

function Confirm-ExistingPackage {
    [CmdletBinding()]
    param (

        [Parameter(Mandatory)]
        [hashtable]
        $Package,


        [Parameter(Mandatory)]
        [string]
        $SiteCode
    )
    
    Push-Location ('{0}:' -f $SiteCode)

    Get-CMPackage -Name $Package.Name -Fast | Where-Object Version -EQ $Package.Version
    
    Pop-Location
}
#EndRegion './private/Confirm-ExistingPackage.ps1' 21
#Region './private/Connect-SCCM.ps1' -1

function Connect-SCCM {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $SiteCode,

        [Parameter(Mandatory)]
        [string]
        $SiteServerFQDN
    )
    
    try {
        Import-Module (Join-Path (Split-Path $env:SMS_ADMIN_UI_PATH -Parent) 'ConfigurationManager.psd1')
    } catch {
        throw 'The specified module ''ConfigurationManager'' was not loaded because no valid module file was found. Is the admin console installed?'
    }

    if (-not (Get-PSDrive -Name $SiteCode -ErrorAction SilentlyContinue)) {
        New-PSDrive -Name $SiteCode -PSProvider "CMSite" -Root $SiteServerFQDN -Description "SCCM Site" | Out-Null
    }
}
#EndRegion './private/Connect-SCCM.ps1' 23
#Region './private/Expand-Cab.ps1' -1

function Expand-Cab {
    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter()]
        [io.fileinfo]
        $Path,

        # Parameter help description
        [Parameter()]
        [io.directoryinfo]
        $DestinationPath,

        # Filename
        [Parameter()]
        [string]
        $FileName
    )

    process {
        $Proc = @{
            FilePath     = 'expand.exe'
            Wait         = $true
            ArgumentList = @(
                '-R',
                '-F:*',
                "$($Path.FullName)",
                "$($DestinationPath.FullName)"
            )
        }

        Start-Process @Proc | Out-Null

    }
}
#EndRegion './private/Expand-Cab.ps1' 36
#Region './private/Expand-Drivers.ps1' -1

function Expand-Drivers {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateSet('Dell', 'Microsoft')]
        [string]
        $Make,

        [Parameter(Mandatory)]
        [object]
        $Path,

        [Parameter(Mandatory)]
        [object]
        $DestinationPath 
    )
    
    $ExtractDir = Join-Path $DestinationPath (New-Guid).Guid

    New-Item $ExtractDir -ItemType Directory -ErrorAction Stop | Out-Null

    $Actions = @{
        'Dell.exe' = {
            Start-Process -FilePath $Path -ArgumentList ('/s /e="{0}"' -f $ExtractDir) -PassThru -Wait
        }

        'Dell.cab' = {
            Expand-Cab -Path $Path -Destination $ExtractDir
        }

        'Microsoft.msi' = {
            Start-Process msiexec.exe -ArgumentList ('/a {0} /QN TARGETDIR="{1}"' -f $Path.FullName, $ExtractDir) -PassThru -Wait
        }
    }

    $result = & ($Actions["$Make$($Path.Extension)"] ?? { throw 'Attempted unhanled driver extraction: {0}' -f "$Make$($Path.Extension)" })

    if ($result.ExitCode -ne 0) {
        throw 'Driver extraction reported non-zero exit code. {0}' -f $result.ExitCode
    }

    $ExtractDir
}
#EndRegion './private/Expand-Drivers.ps1' 44
#Region './private/Find-DellBios.ps1' -1

function Find-DellBIOS {
    [CmdletBinding()]
    param (
        # Model name to search for
        [Parameter(mandatory)]
        [string]
        $Model,

        [Parameter(Mandatory)]
        [psobject]
        $DriverPackCatalog,

        [Parameter(Mandatory)]
        [psobject]
        $CatalogPC
    )

    begin {

        # Get Models from Dell, contains systemID.
        $Models = $DriverPackCatalog.GetElementsByTagName('Model')

        # BIOS files. Find by systemID.
        $SoftwareComponents = $CatalogPC.GetElementsByTagName('SoftwareComponent')        

    }

    process {

        $systemID = ($Models.Where({ $_.Name -eq $Model}, 'First')).systemID

        # BIOS that matches our systemID
        $BIOSInstallers = $SoftwareComponents.Where( 
                { $_.Name.Display.'#cdata-section' -match 'BIOS' -and $_.SupportedSystems.Brand.Model.systemID -eq $systemID }
            )

        if ($BIOSInstallers.Count -gt 1) {
            $BIOSInstallers = $BIOSInstallers | Sort-Object -Property dateTime | Select-Object -Last 1 
        }

        $BIOSInstallers
    }
}
#EndRegion './private/Find-DellBios.ps1' 44
#Region './private/Find-DellDrivers.ps1' -1

function Find-DellDrivers {
    [CmdletBinding()]
    param (
        # Driver Packages, Typically comes from DriverPackCatalog.xml
        [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        [psobject]
        $DriverPackCatalog,

        # Model e.g. 'Optiplex 7080'
        [Parameter(Mandatory = $true)]
        [string]
        $Model,

        # OS version e.g. 'win10'
        [Parameter(Mandatory = $false)]
        [string[]]
        $OSVersion
    )
   
    process {
        $DriverPackCatalog.DriverPackManifest.DriverPackage | Where-Object { $_.SupportedSystems.Brand.Model.name -eq $Model -and $_.SupportedOperatingSystems.OperatingSystem.osCode -eq $OSVersion}
    }       
}
#EndRegion './private/Find-DellDrivers.ps1' 24
#Region './private/Find-MicrosoftDriver.ps1' -1

function Find-MicrosoftDriver {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $Model,

        [Parameter(Mandatory)]
        [string]
        $OSVersion
    )
    
    $Catalog = 'https://raw.githubusercontent.com/OSDeploy/OSD/master/Catalogs/MicrosoftDriverPackCatalog.json'

    $Content = Invoke-RestMethod -Uri $Catalog

    $Content | Where-Object { $_.Product -EQ $Model -and $_.OSVersion -match $OSVersion } 
}
#EndRegion './private/Find-MicrosoftDriver.ps1' 19
#Region './private/Get-DellCatalog.ps1' -1

function Get-DellCatalog {
    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter()]
        [string]
        $URL = 'https://downloads.dell.com/catalog/'
    )

    process {

        $Request = Invoke-WebRequest -Uri $URL -UseBasicParsing

        # Using the operator due to powershell 5s split method behavior
        ($Request.Content -split '<br>').foreach({
            if ($PSItem -match '^\s*(?<date>\d.+?[A|P]M)\s+(?<size>\d+)\s+?<A HREF=".+?">(?<filename>.+)<\/A>$') {
                [PSCustomObject]@{
                    Filename = $Matches['filename']
                    Date     = [datetime] $Matches['date']
                    Size     = [int] $Matches['size']
                    URL      = $URL + $Matches['filename']
                }
            }
        })
    }
}
#EndRegion './private/Get-DellCatalog.ps1' 27
#Region './private/Get-RemoteFile.ps1' -1

function Get-RemoteFile {
    [CmdletBinding()]
    param (
        # Url to download
        [Parameter(Mandatory = $true, ValueFromPipeline)]
        [string]
        $Url,
        
        # Destination
        [Parameter(Mandatory = $true)]
        [io.directoryInfo]
        $Destination,

        # Checksum
        [Parameter(Mandatory = $false,
            ParameterSetName = 'Hash')]
        [string]
        $Hash,

        # Algorithm
        [Parameter(Mandatory = $false,
            ParameterSetName = 'Hash')]
        [ValidateSet('MD5', 'SHA1', 'SHA256', 'SHA384', 'SHA512')]
        [string]
        $Algorithm
    )
    
    process {

        $Filename = ([uri] $Url).Segments[-1]
        
        $OutFile = [System.IO.Path]::Combine($Destination, $Filename)

        Invoke-WebRequest -Uri $Url -OutFile $OutFile | Out-Null

        if ($Hash) {

            $FileHash = (Get-FileHash $OutFile -Algorithm $Algorithm).Hash

            if ($Hash -ne $FileHash) {
                throw 'Failed to verify hash'
            }
        }

        [io.fileinfo] $OutFile

    }
}
#EndRegion './private/Get-RemoteFile.ps1' 49
#Region './private/New-Log.ps1' -1

function New-Log {
    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter(Mandatory, ValueFromPipeline)]
        [string]
        $Message
    )
    
    $Message | ForEach-Object {
        if (-not $NoHostOutput) { Write-Host $_ }
    }
}

Set-Alias Log New-Log
#EndRegion './private/New-Log.ps1' 16
#Region './private/New-Package.ps1' -1

function New-Package {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [hashtable]
        $Package,

        [Parameter(Mandatory)]
        [ValidateSet('Driver', 'BIOS')]
        [string]
        $Type,

        [Parameter(Mandatory)]
        [io.directoryInfo]
        $ContentPath,

        [Parameter(Mandatory)]
        [string]
        $Make,

        [Parameter(Mandatory)]
        [string]
        $SiteCode
    )
    
    begin {
        Push-Location ('{0}:' -f $SiteCode)
    }
    
    process {
        $CMPackage = New-CMPackage @Package -Path $ContentPath
        $CMPackage | Move-CMObject -FolderPath ('{0}:\Package\{1} Packages\{2}' -f $SiteCode, $Type, $Make)
        Set-CMPackage -InputObject $CMPackage -EnableBinaryDeltaReplication $true

        $CMPackage
    }
    
    end {
        Pop-Location
    }
}
#EndRegion './private/New-Package.ps1' 42
#Region './private/Path-Creator.ps1' -1

function Path-Creator {
    [CmdletBinding()]
    param (
    
        [Parameter(Mandatory)]
        [io.directoryInfo]
        $Parent,

        [Parameter(Mandatory)]
        [string[]]
        $Child
    )

    $Path = Join-Path $Parent ($Child -join '\')

    if (-not (Test-Path $Path)) {
        New-Item $Path -ItemType Directory -ErrorAction SilentlyContinue
        return
    }

    [io.directoryinfo] $Path
}
#EndRegion './private/Path-Creator.ps1' 23
#Region './private/Start-ContentDistribution.ps1' -1

function Start-ContentDistribution {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [object]
        $CMPackage,

        [Parameter(Mandatory)]
        [string]
        $SiteCode,
        
        [Parameter(Mandatory, ParameterSetName = 'DistributionPoints')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPoints,

        [Parameter(Mandatory, ParameterSetName = 'DistributionPointGroups')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $DistributionPointGroups
    )
    
    begin {
        Push-Location ('{0}:' -f $SiteCode)
    }
    
    process {
        switch ($PSBoundParameters.Keys) {
            'DistributionPoints'      { Start-CMContentDistribution -InputObject $CMPackage -DistributionPointName $DistributionPoints }
            'DistributionPointGroups' { Start-CMContentDistribution -InputObject $CMPackage -DistributionPointGroupName $DistributionPointGroups }
        }
    }
    
    end {
        Pop-Location
    }
}
#EndRegion './private/Start-ContentDistribution.ps1' 38