Managed IT • Knoxville, TN
Mass BIOS & Driver Updates
automation
dateDec 1, 2024
statusRESOLVED
machines127
Incident

Dell security bulletin: critical BIOS vulnerability affecting OptiPlex and Latitude models. CVE score 8.2. Client had 127 affected Dell machines across 4 locations. Manual updates would require physical presence at each machine. Needed to patch the entire fleet remotely before the 30-day compliance window closed.

Challenge

BIOS updates are traditionally a hands-on nightmare. Download, create bootable USB, visit each machine, pray it doesn't brick. For 127 machines across 4 locations, that's weeks of work.

assessment:
machines ······· 127 Dell OptiPlex/Latitude
vulnerability ·· CVE-2024-XXXXX (CVSS 8.2)
deadline ······ 30 days from bulletin
constraint ···· zero disruption, off-hours only
Solution

Dell Command Update via RMM. Script installs DCU via winget, configures for silent unattended operation, runs scan/apply cycle.

key config options:
autoSuspendBitLocker=enable (suspend/resume)
userConsent=disable (no popups)
reboot=disable (we control timing)
[+] dell_command_update.ps1GitHub
$ErrorActionPreference = 'Stop'

<#
██╗     ██╗███╗   ███╗███████╗██╗  ██╗ █████╗ ██╗    ██╗██╗  ██╗
██║     ██║████╗ ████║██╔════╝██║  ██║██╔══██╗██║    ██║██║ ██╔╝
██║     ██║██╔████╔██║█████╗  ███████║███████║██║ █╗ ██║█████╔╝
██║     ██║██║╚██╔╝██║██╔══╝  ██╔══██║██╔══██║██║███╗██║██╔═██╗
███████╗██║██║ ╚═╝ ██║███████╗██║  ██║██║  ██║╚███╔███╔╝██║  ██╗
╚══════╝╚═╝╚═╝     ╚═╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝ ╚══╝╚══╝ ╚═╝  ╚═╝
================================================================================
 SCRIPT   : Dell Command Update                                         v2.1.4
 AUTHOR   : Limehawk.io
 DATE     : January 2026
 USAGE    : .\dell_command_update.ps1
================================================================================
 FILE     : dell_command_update.ps1
 DESCRIPTION : Installs Dell Command Update and applies driver/firmware updates
--------------------------------------------------------------------------------
 README
--------------------------------------------------------------------------------
 PURPOSE

 Installs Dell Command Update via winget and runs it to scan and apply
 driver/firmware updates silently. Designed for automated Dell system maintenance
 in RMM environments.

 DATA SOURCES & PRIORITY

 1) Hardcoded values (defined within the script body)
 2) winget package manager
 3) Dell Command Update CLI

 REQUIRED INPUTS

 - DcuCliPath    : Path to Dell Command Update CLI executable
 - DcuLogPath    : Directory for DCU log files
 - WingetId      : winget package ID for Dell Command Update

 SETTINGS

 - Uses winget for package management
 - Configures DCU to auto-suspend BitLocker and disable user consent prompts
 - Applies updates without rebooting (reboot=disable)
 - Logs scan and apply operations to C:\dell\logs

 BEHAVIOR

 1. Verifies winget is available
 2. Installs Dell Command Update if not present
 3. Verifies DCU CLI exists
 4. Configures DCU for silent operation
 5. Scans for available updates and outputs log to console
 6. Applies updates without rebooting and outputs log to console

 PREREQUISITES

 - Windows 10 1809+ or Windows 11 with winget
 - Dell system (script will fail on non-Dell hardware)
 - Admin privileges for installation and updates

 SECURITY NOTES

 - No secrets in logs
 - Only affects Dell driver/firmware components

 EXIT CODES

 - 0: Success
 - 1: Failure (winget not found, DCU not installed, etc.)

 EXAMPLE RUN

 [INFO] INPUT VALIDATION
 ==============================================================
 DCU CLI Path : C:\Program Files\Dell\CommandUpdate\dcu-cli.exe
 DCU Log Path : C:\dell\logs
 Winget ID    : Dell.CommandUpdate

 [RUN] OPERATION
 ==============================================================
 Checking for winget...
 winget found
 Checking for Dell Command Update...
 Dell Command Update already installed
 Configuring Dell Command Update...
 Configuration complete
 Scanning for updates...
 Scan complete

 [INFO] SCAN LOG
 ==============================================================
 <Dell Command Update scan results displayed here>

 [RUN] APPLY UPDATES
 ==============================================================
 Applying updates...
 Updates applied

 [INFO] APPLY UPDATES LOG
 ==============================================================
 <Dell Command Update apply results displayed here>

 [OK] RESULT
 ==============================================================
 Status : Success

 [OK] SCRIPT COMPLETED
 ==============================================================

--------------------------------------------------------------------------------
 CHANGELOG
--------------------------------------------------------------------------------
 2026-01-19 v2.1.4 Fixed EXAMPLE RUN section formatting
 2026-01-19 v2.1.3 Updated to two-line ASCII console output style
 2026-01-14 v2.1.2 Fixed header formatting for framework compliance
 2025-12-23 v2.1.1 Updated to Limehawk Script Framework
 2025-12-01 v2.1.0 Output scan and apply log contents to console for RMM visibility
 2025-12-01 v2.0.0 Switched from Chocolatey to winget for package management
 2025-11-29 v1.0.0 Initial Style A implementation
================================================================================
#>

Set-StrictMode -Version Latest

# ==== STATE ====
$errorOccurred = $false
$errorText = ""

# ==== HARDCODED INPUTS ====
$DcuCliPath = "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe"
$DcuLogPath = "C:\dell\logs"
$WingetId = "Dell.CommandUpdate"

# ==== VALIDATION ====
if ([string]::IsNullOrWhiteSpace($DcuCliPath)) {
    $errorOccurred = $true
    if ($errorText.Length -gt 0) { $errorText += "`n" }
    $errorText += "- DcuCliPath is required."
}
if ([string]::IsNullOrWhiteSpace($DcuLogPath)) {
    $errorOccurred = $true
    if ($errorText.Length -gt 0) { $errorText += "`n" }
    $errorText += "- DcuLogPath is required."
}
if ([string]::IsNullOrWhiteSpace($WingetId)) {
    $errorOccurred = $true
    if ($errorText.Length -gt 0) { $errorText += "`n" }
    $errorText += "- WingetId is required."
}

if ($errorOccurred) {
    Write-Host ""
    Write-Host "[ERROR] VALIDATION FAILED"
    Write-Host "=============================================================="
    Write-Host $errorText
    exit 1
}

# ==== RUNTIME OUTPUT ====
Write-Host ""
Write-Host "[INFO] INPUT VALIDATION"
Write-Host "=============================================================="
Write-Host "DCU CLI Path : $DcuCliPath"
Write-Host "DCU Log Path : $DcuLogPath"
Write-Host "Winget ID    : $WingetId"

Write-Host ""
Write-Host "[RUN] OPERATION"
Write-Host "=============================================================="

try {
    # Check for winget
    Write-Host "Checking for winget..."
    $wingetPath = Get-Command "winget" -ErrorAction SilentlyContinue
    if (-not $wingetPath) {
        throw "winget is not available. Windows 10 1809+ or Windows 11 required."
    }
    Write-Host "winget found"

    # Check if Dell Command Update is already installed
    Write-Host "Checking for Dell Command Update..."
    $installed = winget list -e --id $WingetId --accept-source-agreements 2>$null | Select-String $WingetId

    if (-not $installed) {
        Write-Host "Installing $WingetId..."
        $installResult = winget install -e --id $WingetId --silent --accept-package-agreements --accept-source-agreements 2>&1
        if ($LASTEXITCODE -ne 0) {
            throw "Failed to install $WingetId. Exit code: $LASTEXITCODE"
        }
        Write-Host "Installation complete"
    } else {
        Write-Host "Dell Command Update already installed"

        # Check for updates
        Write-Host "Checking for DCU updates..."
        $upgradeResult = winget upgrade -e --id $WingetId --silent --accept-package-agreements --accept-source-agreements 2>&1
        if ($LASTEXITCODE -eq 0) {
            Write-Host "DCU upgraded to latest version"
        }
    }

    # Verify DCU CLI exists
    if (-not (Test-Path $DcuCliPath)) {
        throw "DCU CLI not found at $DcuCliPath. Installation may have failed."
    }

    # Ensure log directory exists
    if (-not (Test-Path $DcuLogPath)) {
        New-Item -Path $DcuLogPath -ItemType Directory -Force | Out-Null
        Write-Host "Created log directory: $DcuLogPath"
    }

    # Configure DCU for silent operation
    Write-Host "Configuring Dell Command Update..."
    & $DcuCliPath /configure -silent -autoSuspendBitLocker=enable -userConsent=disable
    Write-Host "Configuration complete"

    # Scan for updates
    Write-Host "Scanning for updates..."
    & $DcuCliPath /scan -outputLog="$DcuLogPath\scan.log"
    Write-Host "Scan complete"

    # Output scan log
    Write-Host ""
    Write-Host "[INFO] SCAN LOG"
    Write-Host "=============================================================="
    if (Test-Path "$DcuLogPath\scan.log") {
        Get-Content "$DcuLogPath\scan.log" | ForEach-Object { Write-Host $_ }
    } else {
        Write-Host "Scan log not found."
    }

    # Apply updates without rebooting
    Write-Host ""
    Write-Host "[RUN] APPLY UPDATES"
    Write-Host "=============================================================="
    Write-Host "Applying updates..."
    & $DcuCliPath /applyUpdates -reboot=disable -outputLog="$DcuLogPath\applyUpdates.log"
    Write-Host "Updates applied"

    # Output apply log
    Write-Host ""
    Write-Host "[INFO] APPLY UPDATES LOG"
    Write-Host "=============================================================="
    if (Test-Path "$DcuLogPath\applyUpdates.log") {
        Get-Content "$DcuLogPath\applyUpdates.log" | ForEach-Object { Write-Host $_ }
    } else {
        Write-Host "Apply updates log not found."
    }

} catch {
    $errorOccurred = $true
    $errorText = $_.Exception.Message
}

if ($errorOccurred) {
    Write-Host ""
    Write-Host "[ERROR] OPERATION FAILED"
    Write-Host "=============================================================="
    Write-Host $errorText

    Write-Host ""
    Write-Host "[ERROR] RESULT"
    Write-Host "=============================================================="
    Write-Host "Status : Failure"
} else {
    Write-Host ""
    Write-Host "[OK] RESULT"
    Write-Host "=============================================================="
    Write-Host "Status : Success"
}

Write-Host ""
if ($errorOccurred) {
    Write-Host "[ERROR] FINAL STATUS"
} else {
    Write-Host "[OK] FINAL STATUS"
}
Write-Host "=============================================================="
if ($errorOccurred) {
    Write-Host "Dell Command Update process failed. See error above."
} else {
    Write-Host "Dell Command Update completed successfully."
    Write-Host "Reboot may be required for some updates to take effect."
}

Write-Host ""
if ($errorOccurred) {
    Write-Host "[ERROR] SCRIPT COMPLETED"
} else {
    Write-Host "[OK] SCRIPT COMPLETED"
}
Write-Host "=============================================================="

if ($errorOccurred) {
    exit 1
} else {
    exit 0
}
Deployment

Phased rollout - firmware updates are high-risk. Bad update or power loss mid-flash can brick a machine.

rollout plan:
1. pilot (5) ······· one of each model, users notified
2. wave 1 (30) ···· IT dept, overnight deployment
3. wave 2 (50) ···· non-critical, weekend deployment
4. wave 3 (42) ···· remaining, scheduled maintenance

After each wave, verified BIOS versions via RMM inventory scan. Any machine that didn't update got flagged for manual review before proceeding.

Outcome
machines patched127 across 4 locations
time to complete2 weeks (phased rollout)
hours saved196+ vs manual updates
bricked machineszero

Key takeaways:

DCU CLI makes BIOS updates remotely deployable
autoSuspendBitLocker prevents lockouts
phased rollout essential for firmware
now run DCU monthly as proactive maintenance
Get Help

Need to patch your Dell fleet? We automate firmware and driver updates - no site visits required.

Contact Us