Automate Dell BIOS Updates | PowerShell



INTRO

Microsoft Windows Logo Curious Blue Background

You can automate Dell BIOS updates with PowerShell and RMM. While it has been some time since my last IT related post. Whether you were crawling down the rabbit holes of missing people, Mandela Effects, and my personal life’s downfalls and challenges, whether self-inflicted or not, you’ve probably wondered if I was ever going to come back to binary world. Well, today I have a script to share and that’s automating the BIOS updates of Dell systems.

In my nearly a decade of IT experience, working with Lenovo, HP, and Dell mostly, Dell has been the best in terms of quality and management. In Dell’s BIOS updates, the Intel ME firmware updates are included thus reducing another thing to manage and update. Also, Dell’s firmware updates for their Server line are not behind a paywall.

WHAT THE SCRIPT WILL DO

This script will:

  • First uninstall any version of Dell Command Update currently installed using the proper uninstall string from the registry.
  • Install Dell Command Update v4.3.0.
  • Update the BIOS for “Compatible Systems”.

Each version of Dell Command Update supports different platforms and models so there is no 1-fits-all package. You will need to research which versions support the models of Dell you need to support, and you do that by expanding “Compatible Systems” under “Additional Details” for the download of Dell Command Update you’re going to use.

So, in this example, we’re using v4.3.0 located here.

In Datto RMM, create a new script component and upload the installer of Dell Command Update, “Dell-Command-Update-Application-for-Windows-10_GRVPK_WIN_4.3.0_A00_03.EXE”

Set your script type to PowerShell and place the following code in it. When running, the systems will reboot if there is an update, and after requesting device audits in Datto, you will see the BIOS revision has been updated for outdated models.

POWERSHELL SCRIPT

PowerShell
$remove = @('*Dell Command*')
 
function Get-InstalledApps {
param (
[Parameter(ValueFromPipeline=$true)]
[string[]]$ComputerName = $env:COMPUTERNAME,
[string]$NameRegex = ''
)
 
    foreach ($comp in $ComputerName) {
    $keys = '','\Wow6432Node'
        foreach ($key in $keys) {
        try {
            $apps = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$comp).OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall").GetSubKeyNames()
        } catch {
            continue
        }
 
            foreach ($app in $apps) {
            $program = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$comp).OpenSubKey("SOFTWARE$key\Microsoft\Windows\CurrentVersion\Uninstall\$app")
            $name = $program.GetValue('DisplayName')
                if ($name -and $name -match $NameRegex) {
                    [pscustomobject]@{
                    ComputerName = $comp
                    DisplayName = $name
                    DisplayVersion = $program.GetValue('DisplayVersion')
                    Publisher = $program.GetValue('Publisher')
                    InstallDate = $program.GetValue('InstallDate')
                    UninstallString = $program.GetValue('UninstallString')
                    Bits = $(if ($key -eq '\Wow6432Node') {'64'} else {'32'})
                    Path = $program.name
                    }
                }
            }
        }
    }
}
 
$array = Foreach ($r in $remove){
Get-InstalledApps | Where-Object {$_.DisplayName -like $r } | Select-Object -ExpandProperty UninstallString
}
 
ForEach ($a in $array) {
& "$env:ComSpec" /c $a /quiet
}
 
$ExecutingScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
 
Start-Process "$ExecutingScriptDirectory\Dell-Command-Update-Application-for-Windows-10_GRVPK_WIN_4.3.0_A00_03.EXE" -ArgumentList '/s' -Verbose -Wait
 
Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\DellCommandUpdate.exe" -ArgumentList "/s" -Verbose -Wait
Set-Service -Name 'DellClientManagementService' -StartupType Manual
 
Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/Scan -Report=C:\TEMP" -Wait
$XMLReport = Get-Content "C:\TEMP\DCUApplicableUpdates.xml"
 
#We now remove the item, because we don't need it anymore, and it sometimes fails to overwrite.
Remove-Item "C:\TEMP\DCUApplicableUpdates.xml" -Force
 
$AvailableUpdates = $XMLReport.updates.update
 
$BIOSUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "BIOS" }).name.Count
$ApplicationUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Application" }).name.Count
$DriverUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Driver" }).name.Count
$FirmwareUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Firmware" }).name.Count
$OtherUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Other" }).name.Count
$PatchUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Patch" }).name.Count
$UtilityUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Utility" }).name.Count
$UrgentUpdates = ($XMLReport.updates.update | Where-Object { $_.Urgency -eq "Urgent" }).name.Count
 
Start-Process -FilePath "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/applyUpdates -autoSuspendBitLocker=enable -reboot=enable -updateType=bios" -Wait

BIOS UPDATES ARE IMPORTANT

Taking a Dell OptiPlex 7040 for example, there are 24 revisions of BIOS updates, each with 1 or more enhancements or fixes. I have seen BIOS updates resolve issues that also aren’t listed in revision notes, like certain SSD drives not being detected.

Do you want to troubleshoot an issue you think is Windows, software, or hardware related for hours only to discover it a was a BIOS issue/bug on the OEM’s part? No. So just do the dang updates and don’t be so afraid. I think I have had only 2 bad BIOS flashes in my past and one of them I was able to recover so I myself never get worried doing them.

CONCLUSION

Well, there you go. Now if you run this and brick 50 systems remotely, I can’t help you there, but praying to Jesus Christ may be the next step, and we have plenty of posts here on how to connect with Him more if that happens.

I have run this multiple times without issues, and it has saved me a lot of time. Stay safe out there, and don’t take anything experimental that can cause heart problems, blood clots, and has a past of manufacturing and contamination issues.

2 replies
    • WinReflection
      WinReflection says:

      Hey Sal! You’re very welcome! I am glad you liked the Jesus part :). No calling list needed as I deploy it with an RMM solution (Datto RMM). I just select the computers I want in the web-based portal and the agents on each endpoint download the script and run with SYSTEM permissions. No bricks yet, attempted on like 12 endpoints at one time, worked well. I actually have a script for HP computers also, but still working out a bug. Have a great rest of your day/night, wherever you are.

      – Dex

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *