Public/Dell.DCU/Public/Get-DellBIOSUpdates.ps1

Function Get-DellBIOSUpdates {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$False)]
        [ValidateLength(4,4)]    
        [string]$SystemSKUNumber,
        [switch]$Latest,
        [switch]$Check, #This will find the latest BIOS update and compare it to the current BIOS version
        [switch]$Details,
        [switch]$Flash,
        [string]$Password,
        [string]$DownloadPath

    )
    $Manufacturer = (Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer
    if (!($SystemSKUNumber)) {
        if ($Manufacturer -notmatch "Dell"){return "This Function is only for Dell Systems, or please provide a SKU"}
        $SystemSKUNumber = (Get-CimInstance -ClassName Win32_ComputerSystem).SystemSKUNumber
    }

    if ($Details){
        if ($Manufacturer -notmatch "Dell"){return "This Function is only for Dell Systems"}

        $BiosInfo = Get-CimInstance -ClassName Win32_BIOS
        [version]$CurrentBIOSVersion = $BiosInfo.SMBIOSBIOSVersion
        $CurrentBIOSReleaseDate = $null
        if ($BiosInfo.ReleaseDate){
            try {
                $CurrentBIOSReleaseDate = [System.Management.ManagementDateTimeConverter]::ToDateTime($BiosInfo.ReleaseDate)
            }
            catch {
                $CurrentBIOSReleaseDate = $BiosInfo.ReleaseDate
            }
        }

        $AllBIOSUpdates = @(Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS)
        $LatestBIOS = $AllBIOSUpdates | Sort-Object -Property ReleaseDate -Descending | Select-Object -First 1
        if ($LatestBIOS){
            [version]$LatestBIOSVersion = $LatestBIOS.DellVersion
            $LatestBIOSReleaseDate = $LatestBIOS.ReleaseDate
            $UpdateAvailable = $CurrentBIOSVersion -lt $LatestBIOSVersion
            $BIOSIsCurrent = $CurrentBIOSVersion -ge $LatestBIOSVersion
            $ReleasesSinceCurrent = @(
                $AllBIOSUpdates |
                    Where-Object {
                        try {
                            $CandidateVersion = [version]$_.DellVersion
                            $CandidateVersion -gt $CurrentBIOSVersion
                        }
                        catch {
                            $false
                        }
                    } |
                    Select-Object -ExpandProperty DellVersion -Unique
            ).Count
        }
        else {
            $LatestBIOSVersion = $null
            $LatestBIOSReleaseDate = $null
            $UpdateAvailable = $false
            $BIOSIsCurrent = $true
            $ReleasesSinceCurrent = 0
        }

        return [PSCustomObject]@{
            CurrentBIOSVersion = $CurrentBIOSVersion
            CurrentBIOSReleaseDate = $CurrentBIOSReleaseDate
            LatestBIOSVersion = $LatestBIOSVersion
            LatestBIOSReleaseDate = $LatestBIOSReleaseDate
            UpdateAvailable = $UpdateAvailable
            BIOSIsCurrent = $BIOSIsCurrent
            ReleasesSinceCurrent = $ReleasesSinceCurrent
        }
    }
    
    if ($Check){
        if ($Manufacturer -notmatch "Dell"){return "This Function is only for Dell Systems"}
        else{
            [Version]$CurrentBIOSVersion = (Get-CimInstance -ClassName Win32_BIOS).SMBIOSBIOSVersion
            $LatestBIOS = Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS -Latest | Sort-Object -Property ReleaseDate -Descending
            if ($LatestBIOS.count -gt 1){
                $LatestBIOS = $LatestBIOS | Select-Object -First 1
            }
            [version]$LatestVersion = ($LatestBIOS).DellVersion

            if ($CurrentBIOSVersion -lt $LatestVersion){
                Write-Verbose "Current BIOS Version: $CurrentBIOSVersion"
                Write-Verbose "Latest BIOS Version: $LatestVersion"
                Write-Verbose "New BIOS Update Available"
                return $false
            }
            else {
                Write-Verbose "Current BIOS Version: $CurrentBIOSVersion"
                Write-Verbose "Latest BIOS Version: $LatestVersion"
                Write-Verbose "No New BIOS Update Available"
                return $true
            }
        }
    }
    if ($Flash){
        #Test for BitLocker state before downloading or flashing the BIOS update.
        try {
            $BitlockerStatus = Get-BitLockerVolume -MountPoint $env:SystemDrive
        }
        catch {
            $BitlockerStatus = $null
            Write-Host "Unable to query BitLocker status. Continuing without preflight check: $($_.Exception.Message)"
        }

        if ($BitlockerStatus -ne $null){
            Write-Host "BitLocker status: Protection=$($BitlockerStatus.ProtectionStatus) | Volume=$($BitlockerStatus.VolumeStatus) | Encryption=$($BitlockerStatus.EncryptionPercentage)%"

            if ($BitlockerStatus.VolumeStatus -in @('EncryptionInProgress','DecryptionInProgress')){
                Write-Host "BitLocker is currently encrypting or decrypting this volume. BIOS flashing is blocked until that process finishes."
                return
            }

            if ($BitlockerStatus.ProtectionStatus -eq "On"){
                if ($BitlockerStatus.VolumeStatus -eq 'FullyEncrypted'){
                    Write-Host "BitLocker protection is On and the volume is fully encrypted. Suspending BitLocker before flashing BIOS..."
                    Suspend-BitLocker -MountPoint $env:SystemDrive -RebootCount 1
                }
                else {
                    Write-Host "BitLocker protection is On, but the volume is not in a ready state for BIOS flashing. BIOS flashing will not be attempted."
                    return
                }
            }
        }
        #https://www.dell.com/support/kbdoc/en-us/000136752/command-line-switches-for-dell-bios-updates
        $Updates = Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS -Latest
        $Update = $Updates | Select-Object -First 1
        $UpdatePath = $Update.Path
        $UpdateFileName = $UpdatePath -split "/" | Select-Object -Last 1
        $UpdateDownloadFolder = "$env:ProgramData\OEMWrapPS\DellBIOSUpdates"
        if (!(Test-Path $UpdateDownloadFolder)){$null = New-Item -Path $UpdateDownloadFolder -ItemType Directory -Force}
        $UpdateLocalPath = "$UpdateDownloadFolder\$UpdateFileName"
        Start-BitsTransfer -DisplayName $UpdateFileName -Source $UpdatePath -Destination $UpdateLocalPath -Description "Downloading $UpdateFileName" -RetryInterval 60 #-CustomHeaders "User-Agent:Bob"
        if (Test-Path -Path $UpdateLocalPath){
            Write-Host "Installing $UpdateFileName, logfile: $($UpdateLocalPath).log"
            if ($Password){
                $BIOSArgs = "/s /l=$UpdateLocalPath.log /p=$Password"
            }
            else {
                $BIOSArgs = "/s /l=$UpdateLocalPath.log"
            }
            $InstallUpdate = Start-Process -FilePath $UpdateLocalPath -ArgumentList $BIOSArgs -Wait -PassThru
            $LogPath = "$UpdateLocalPath.log"
            $ExitInfo = Get-DUPExitInfo -DUPExit $InstallUpdate.ExitCode | Select-Object -First 1
            if (-not $ExitInfo) {
                $ExitInfo = [PSCustomObject]@{
                    ExitCode = $InstallUpdate.ExitCode
                    DisplayName = 'Unknown'
                    Description = 'No matching Dell DUP BIOS exit-code documentation was found.'
                }
            }

            if (Test-Path -Path $LogPath) {
                $LogContent = Get-Content -Path $LogPath -Raw -ErrorAction SilentlyContinue
                $LoggedExitCode = [regex]::Match($LogContent, '(?im)^\s*Exit Code\s*=\s*(?<Value>.+?)\s*$')
                $LoggedError = [regex]::Match($LogContent, '(?im)^\s*Error:\s*(?<Value>.+?)\s*$')

                if ($LoggedExitCode.Success) {
                    $ExitInfo.DisplayName = $LoggedExitCode.Groups['Value'].Value.Trim()
                }
                if ($LoggedError.Success) {
                    $ExitInfo.Description = $LoggedError.Groups['Value'].Value.Trim()
                }
            }
            Write-Host "Exit Code: $($ExitInfo.ExitCode)"
            Write-Host "Code Name: $($ExitInfo.DisplayName)"
            Write-Host "Description: $($ExitInfo.Description)"
            return [PSCustomObject]@{
                Update = $UpdateFileName
                ExitCode = $ExitInfo.ExitCode
                CodeName = $ExitInfo.DisplayName
                Description = $ExitInfo.Description
                LogPath = $LogPath
                Success = $ExitInfo.ExitCode -in @(0, 2)
                RebootRequired = $ExitInfo.ExitCode -eq 2
            }
        }
        else {
            Write-Host "File Not Found: $UpdateFileName"
            return
        }
    }
    if ($DownloadPath){
        [void][System.IO.Directory]::CreateDirectory($DownloadPath)
        $Updates = Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS -Latest
        $Update = $Updates | Select-Object -First 1
        $UpdatePath = $Update.Path
        $UpdateFileName = $UpdatePath -split "/" | Select-Object -Last 1
        $UpdateLocalPath = "$DownloadPath\$UpdateFileName"
        Start-BitsTransfer -DisplayName $UpdateFileName -Source $UpdatePath -Destination $UpdateLocalPath -Description "Downloading $UpdateFileName" -RetryInterval 60 #-CustomHeaders "User-Agent:Bob"
        return $UpdateLocalPath
    }
    if ($Latest){
        $Updates = Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS -Latest
    }
    else {
        $Updates = Get-DCUUpdateList -SystemSKUNumber $SystemSKUNumber -updateType BIOS
    }
    return $Updates |Select-Object -Property "PackageID","Name","ReleaseDate","DellVersion" | Sort-Object -Property ReleaseDate -Descending
}