Unsolved

1 Rookie

 • 

1 Message

43

March 15th, 2026 10:39

How to bulk detect and download new Bios to a laptop

I have 11 different Dell devices and I need to automate downloading new Bios versions to one place (we can't use the DCU app). Is there a way to automatically check and download them to my PC?

Thank you

Mirka

10 Elder

 • 

30.8K Posts

March 15th, 2026 10:53

Not without using a third party (paid) administrative application, no.

2 Intern

 • 

258 Posts

March 18th, 2026 12:33

@Mirka 

1) create a txt file with this content: (use your 11 different machines)

Latitude 5420
Latitude 7430
OptiPlex 7090
Precision 3581

2) create a bash-script: dell_bios_from_list.sh

#!/usr/bin/env bash
set -euo pipefail

# usecase:
#   ./dell_bios_from_list.sh models.txt
#
# prerequest:
#   - curl
#   - cabextract
#   - python3
#
# Output:
#   CSV to STDOUT:
#   Model,BIOS_Version,ReleaseDate,DownloadURL,FileName

MODEL_LIST="${1:-models.txt}"
WORKDIR="$(mktemp -d)"
CATALOG_URL="https://downloads.dell.com/catalog/CatalogPC.cab"

cleanup() {
  rm -rf "$WORKDIR"
}
trap cleanup EXIT

if [[ ! -f "$MODEL_LIST" ]]; then
  echo "Error: Modell-List '$MODEL_LIST' not found." >&2
  exit 1
fi

echo "Download Dell Catalog ..." >&2
curl -fsSL -o "$WORKDIR/CatalogPC.cab" "$CATALOG_URL"

echo "Unpack Catalog..." >&2
cabextract -q -d "$WORKDIR" "$WORKDIR/CatalogPC.cab" >/dev/null

XML_FILE="$(find "$WORKDIR" -maxdepth 1 -type f -iname '*.xml' | head -n1)"
if [[ -z "${XML_FILE:-}" ]]; then
  echo "Error: No XML-File found in Catalog" >&2
  exit 1
fi

python3 - "$MODEL_LIST" "$XML_FILE" <<'PY'
import sys
import csv
import xml.etree.ElementTree as ET
from pathlib import Path

model_file = Path(sys.argv[1])
xml_file = Path(sys.argv[2])

wanted_models = [
    line.strip() for line in model_file.read_text(encoding="utf-8").splitlines()
    if line.strip() and not line.strip().startswith("#")
]

tree = ET.parse(xml_file)
root = tree.getroot()

def local_name(tag):
    if "}" in tag:
        return tag.split("}", 1)[1]
    return tag

def child_text(elem, name, default=""):
    for c in elem:
        if local_name(c.tag) == name:
            return (c.text or "").strip()
    return default

def find_first_text(elem, names):
    for e in elem.iter():
        if local_name(e.tag) in names and (e.text and e.text.strip()):
            return e.text.strip()
    return ""

def get_supported_models(component):
    models = []
    for e in component.iter():
        if local_name(e.tag) == "Display" and e.text and e.text.strip():
            # Meist gibt es viele Display-Knoten; wir sammeln nur plausible Modellnamen
            text = e.text.strip()
            # Grobe Filterung gegen irrelevante Display-Texte
            if any(prefix in text.lower() for prefix in [
                "bios", "firmware", "driver", "application"
            ]):
                continue
            models.append(text)
    # Reihenfolge beibehalten, Dubletten raus
    seen = set()
    result = []
    for m in models:
        if m not in seen:
            seen.add(m)
            result.append(m)
    return result

def is_bios_component(component):
    # Dell-Kataloge enthalten BIOS-Komponenten; je nach XML-Struktur sitzt das
    # in ComponentType oder als Value darunter.
    ctype = child_text(component, "ComponentType", "").strip().lower()
    if ctype == "bios":
        return True
    for e in component.iter():
        if local_name(e.tag) == "ComponentType":
            txt = (e.text or "").strip().lower()
            if txt == "bios":
                return True
        if local_name(e.tag) == "Value":
            txt = (e.text or "").strip().lower()
            if txt == "bios":
                return True
    return False

rows = []
for comp in root.iter():
    if local_name(comp.tag) != "SoftwareComponent":
        continue
    if not is_bios_component(comp):
        continue

    version = find_first_text(comp, {"dellVersion", "vendorVersion", "DisplayVersion"})
    release_date = find_first_text(comp, {"ReleaseDate", "releaseDate", "DateTime"})
    path = find_first_text(comp, {"Path", "path"})
    filename = find_first_text(comp, {"FileName", "fileName"})
    download_url = f"https://downloads.dell.com/{path.lstrip('/')}" if path else ""

    supported_models = get_supported_models(comp)

    for wanted in wanted_models:
        wanted_l = wanted.lower()
        for supported in supported_models:
            if wanted_l == supported.lower():
                rows.append([wanted, version, release_date, download_url, filename])
                break

# Pro Modell nur den "besten" Treffer behalten:
# bevorzugt Einträge mit Version/Datum/URL
best = {}
for row in rows:
    model = row[0]
    score = sum(1 for x in row[1:] if x)
    if model not in best or score > best[model][0]:
        best[model] = (score, row)

writer = csv.writer(sys.stdout)
writer.writerow(["Model", "BIOS_Version", "ReleaseDate", "DownloadURL", "FileName"])

for wanted in wanted_models:
    if wanted in best:
        writer.writerow(best[wanted][1])
    else:
        writer.writerow([wanted, "NICHT_GEFUNDEN", "", "", ""])
PY


3)
use this command to run the complete script

chmod +x dell_bios_from_list.sh
./dell_bios_from_list.sh models.txt > dell_bios.csv

4)
the csv file will look like this:

Model,BIOS_Version,ReleaseDate,DownloadURL,FileName
Latitude 5420,1.30.0,2026-02-14T00:00:00,https://downloads.dell.com/.../Latitude_5420_1.30.0.exe,Latitude_5420_1.30.0.exe
OptiPlex 7090,1.25.1,2026-01-22T00:00:00,https://downloads.dell.com/.../OptiPlex_7090_1.25.1.exe,OptiPlex_7090_1.25.1.exe

HTH

Peter


Top