Free tech learning for everyone, from basics to pro

Automation ProjectsProgramming and Application SecurityBeginner

Project: a network inventory report (models, serials, versions)

In short: Knowing exactly what hardware and software you run is the base of patching, support contracts and audits. This project collects facts such as model, serial number and OS version from every device with NAPALM and writes them to CSV and HTML. It is read-only, quick to build and immediately useful.

Goal and what you will build

Ask most teams for a list of their switches with serial numbers and software versions and you will get an out-of-date spreadsheet. Accurate inventory matters: support renewals need serial numbers, security advisories need software versions, and frameworks such as the CIS Controls start with knowing your assets. In this project you will build a script that logs in to each device, gathers the same set of facts and writes a clean report.

You need Python 3, a handful of lab devices you are allowed to access, and a read-only account on each.

Inventory report pipelineDevice listhosts.yamlCollect factsNAPALMget_factsNormaliseone recordeachEnrichend-of-lifeflagsExportCSV and HTML
Figure 1. The script gathers the same facts from every device and turns them into one consistent report.

Design

NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) provides the same function, get_facts(), across vendors such as Cisco IOS, IOS-XR, NX-OS, Juniper Junos and Arista EOS. It returns a dictionary with hostname, vendor, model, serial number, OS version and uptime, so you do not have to write a parser for each vendor’s show version.

What the report answersInventoryone row per deviceSupportserials forcontractsPatchingold OS versionsLifecyclemodels to replaceAuditis it all known?Capacitycounts by site
Figure 2. One accurate inventory serves support renewals, patching, lifecycle planning, audits and capacity planning.
FieldWhy it matters
hostnameMatches what engineers see in the CLI
vendor, modelLifecycle and spare-parts planning
serial_numberSupport contracts and warranty claims
os_versionVulnerability and patch tracking
uptimeLong uptimes often mean missed patches

Build it step by step

  1. Install the packages: pip install napalm pyyaml jinja2.
  2. Create hosts.yaml listing each device’s name, IP address and NAPALM driver (for example ios, eos, junos).
  3. Create approved_versions.yaml with the minimum software version you accept for each platform.
  4. Run the script, open the CSV in a spreadsheet and check one or two rows against the device CLI.
  5. Add the HTML output and schedule a weekly run.
#!/usr/bin/env python3
import csv, os, datetime
import yaml
from napalm import get_network_driver

FIELDS = ["name", "ip", "vendor", "model", "serial_number",
          "os_version", "uptime_days", "status", "note"]

def collect(dev, minimum):
    row = {"name": dev["name"], "ip": dev["host"]}
    driver = get_network_driver(dev["driver"])
    try:
        with driver(dev["host"], os.environ["NET_USER"], os.environ["NET_PASS"],
                    timeout=30) as conn:
            f = conn.get_facts()
        row.update({k: f[k] for k in ("vendor", "model", "serial_number", "os_version")})
        row["uptime_days"] = round(f["uptime"] / 86400, 1)
        floor = minimum.get(dev["driver"])
        row["status"] = "ok"
        if floor and floor not in f["os_version"]:
            row["note"] = f"check against approved {floor}"
    except Exception as e:
        row.update(status="unreachable", note=type(e).__name__)
    return row

def main():
    hosts = yaml.safe_load(open("hosts.yaml", encoding="utf-8"))
    minimum = yaml.safe_load(open("approved_versions.yaml", encoding="utf-8"))
    rows = [collect(d, minimum) for d in hosts]
    out = f"inventory-{datetime.date.today()}.csv"
    with open(out, "w", newline="", encoding="utf-8") as fh:
        w = csv.DictWriter(fh, fieldnames=FIELDS)
        w.writeheader()
        w.writerows(rows)
    print(f"Wrote {len(rows)} devices to {out}")

if __name__ == "__main__":
    main()

Tip: version strings do not sort reliably as text (for example "17.9" vs "17.12"). For a proper comparison, split them into numbers or use the packaging.version module when the format allows.

For the HTML report, pass the rows to a small Jinja2 template that builds a table and highlights unreachable devices and version notes. Keep the HTML file on an internal share; it contains serial numbers and IP addresses that should not be public.

How to extend it

  • Add stack members, modules and power supplies with get_environment() or platform-specific commands.
  • Compare each run with the previous CSV and report new, missing and changed devices.
  • Push the results into a source of truth such as NetBox through its REST API.
  • Add a lookup table of vendor end-of-sale and end-of-support dates that you maintain from official notices.
  • Speed it up with Nornir to run many devices in parallel.

Showing it in your portfolio

Publish the code with a sanitised sample report: replace serials with fake values such as LAB0001 and use documentation IP ranges. In the README, explain the business problem (contracts, patching, audits), why you chose NAPALM, and how the script handles unreachable devices. A before-and-after comparison, such as "manual spreadsheet updated twice a year" versus "accurate report every Monday", tells an employer you understand the value of automation.

Practice

Why use NAPALM get_facts() rather than parsing show version yourself?
It returns the same normalised fields for several vendors, so one script works across platforms without custom parsers for each.
Why might a very long uptime be a warning sign?
The device has not been rebooted for a long time, which often means software updates that need a reload have not been installed.
Why should the generated report not be published publicly?
It contains serial numbers, IP addresses and software versions that help an attacker find vulnerable devices and target support fraud.

Key takeaways

  • An accurate inventory is the base of patching, support and audits.
  • NAPALM get_facts() returns vendor, model, serial, OS version and uptime.
  • Handle unreachable devices and record them in the report.
  • Flag versions below your approved baseline for patching.
  • Sanitise serials and IP addresses before sharing samples.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.