Multi-Device Show Command
Multi-Device Show Command Collection¶
"From One to Many β Evolve Your Script for Production Scale"¶
In Tutorial #1, you built a script that connects to a single device and exports data to Excel. That's a great start, but real network automation needs to handle multiple devices.
In this tutorial, we'll build on your existing script and evolve it to:
- Read device inventory from a CSV file
- Loop through multiple devices
- Handle errors gracefully (one device failing doesn't stop the others)
- Export results to Excel with one sheet per device
This is how you transition from a proof-of-concept to a production-ready tool!
π― What You'll Learn¶
By the end of this tutorial, you'll understand:
- β How to manage device inventory using CSV files
- β How to loop through multiple devices efficiently
- β Why per-device error handling is critical
- β How to combine multi-device data into a single Excel file
- β How to provide user feedback during long operations
- β The difference between "fail-fast" and "continue-on-error" patterns
π Prerequisites¶
Required Knowledge¶
- β Completed Tutorial #1 β This builds directly on that script
- β Basic understanding of CSV files
- β Comfortable with Python loops and error handling
Required Software¶
Required Access¶
- Multiple Cisco devices (2 or more) with:
- SSH enabled
- Same credentials (or we'll show you how to handle different credentials)
- Reachable from your workstation
π Evolution from Tutorial #1¶
Here's what we're changing:
| Tutorial #1 (Single Device) | Tutorial #2 (Multi-Device) |
|---|---|
| Device details hardcoded in script | Device list in external CSV file |
| Connects to one device | Loops through multiple devices |
| Script stops if connection fails | Continues to next device on error |
| One Excel file, one device | One Excel file, multiple sheets (one per device) |
| Password entered once | Password entered once, used for all devices |
π§ The Complete Script¶
Here's the full multi-device script. We'll break down what changed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
π Create Your Inventory File¶
Before running the script, create a CSV file named devices.csv in the same directory:
devices.csv¶
Column Explanations:
- device_type: The Netmiko device type (
cisco_ios,cisco_nxos,cisco_xr, etc.) - host: IP address or hostname of the device
- username: SSH username
- secret: Enable password (leave blank if not needed)
Important Notes:
- The CSV must have a header row with these exact column names
- All devices should use the same password (you'll enter it once when the script runs)
- If devices have different passwords, see the "Advanced Variations" section below
π What Changed - Line by Line¶
Let's focus ONLY on what's different from Tutorial #1. I won't re-explain concepts you already learned.
New Import¶
What it does: Imports Python's built-in CSV library.
Why: We need to read device information from the CSV file. Python's csv module makes this easy and handles edge cases like quoted values and different delimiters.
Password Handling Change¶
Tutorial #1:
Tutorial #2:
What changed: We now capture the password in a variable BEFORE defining devices.
Why: We only want to prompt for the password once, then reuse it for all devices. In Tutorial #1, the password was part of the device dictionary. Now we store it separately and assign it to each device as we process the CSV.
New Function: read_inventory()¶
This function is completely new. Let's break it down:
What it does: Defines a function that reads our CSV file and returns a list of device dictionaries.
Why: Functions make code reusable and testable. By separating the "read CSV" logic from the "connect to devices" logic, we can easily swap to a different inventory source later (like a database or API).
The triple-quoted docstring documents what the function does, what parameters it expects, and what it returns. This is a Python best practice.
What it does: Creates an empty list to store device dictionaries.
Why: We'll loop through the CSV rows and append each device to this list.
What it does: Opens the CSV file for reading using a context manager (with).
Why:
- The
tryblock catches errors if the file doesn't exist - The
withstatement automatically closes the file when done, even if an error occurs 'r'means "read mode"
What it does: Creates a CSV reader that converts each row into a dictionary.
Why: DictReader automatically uses the first row as column headers. Each subsequent row becomes a dictionary where keys are column names. This is much easier to work with than positional indexes.
For example, if a CSV row is:
DictReader converts it to:
What it does: Loops through each row in the CSV (after the header).
Why: We need to process each device one at a time.
What it does: Creates a device dictionary in the format Netmiko expects.
Why: This dictionary structure is identical to Tutorial #1, but now we're building it from CSV data instead of hardcoding it.
Important detail:
row['device_type']gets the value from the CSVdevice_passworduses the password we captured at the startrow.get('secret', '')safely gets the secret, defaulting to empty string if the column is missing
What it does: Adds this device dictionary to our list.
Why: We're building a list of all devices to process.
What it does: Prints a success message and returns the list of devices.
Why: User feedback! It's important to confirm how many devices were loaded before starting connections.
What it does: Catches the error if the CSV file doesn't exist.
Why: If the file is missing, we want a friendly error message, not a Python traceback. Returning an empty list allows the script to exit gracefully.
What it does: Catches errors if required CSV columns are missing.
Why: If someone forgets the device_type column, this provides a clear error message instead of a confusing crash.
New Function: collect_from_device()¶
This function wraps the connection logic from Tutorial #1 but adds error handling.
What it does: Defines a function that handles ONE device.
Why: By putting the connection logic in a function, we can easily call it in a loop for multiple devices. The function returns either (hostname, DataFrame) on success or (hostname, None) on failure.
What it does: Stores the device IP/hostname for easier reference.
Why: We use hostname multiple times in print statements, so storing it in a variable makes code cleaner.
What it does: Attempts to connect to the device, wrapped in error handling.
Why: The try block is CRITICAL for multi-device operations. If this device fails, we want to:
- Log the error
- Continue to the next device
Without try/except, one failed device would crash the entire script!
Note the indentation in the print statement: The leading spaces make output more readable when processing multiple devices.
What it does: Same logic as Tutorial #1, but now returns a tuple.
Why: We return (hostname, df) so the main script knows which device this data came from. This is essential for creating separate Excel sheets later.
What it does: Handles the case where TextFSM parsing fails.
Why: Unlike Tutorial #1 where we printed raw output, here we just log a warning and return None. This keeps the script moving through other devices.
What it does: Catches ANY error during connection or command execution.
Why: This is the "continue-on-error" pattern. Instead of crashing, we:
- Log which device failed and why
- Return
Noneto indicate failure - Let the script continue to the next device
Common errors this catches:
- Authentication failures
- Timeouts
- Device unreachable
- SSH not enabled
Updated main() Function¶
The main function now orchestrates the entire multi-device operation.
What it does: Defines the CSV filename.
Why: Having this at the top of main() makes it easy to change if you want to use a different filename.
What it does: Prints a header banner.
Why: Visual feedback. The "=" * 60 creates a 60-character line of equals signs for a nice separator.
What it does: Reads the CSV and exits if no devices were loaded.
Why: If the CSV is missing or empty, there's no point continuing. This is defensive programmingβcheck preconditions before doing work.
What it does: Loops through all devices and stores successful results in a dictionary.
Why:
results = {}creates an empty dictionary- For each device, we call
collect_from_device()which returns(hostname, dataframe) - We use Python's tuple unpacking:
hostname, df = collect_from_device(device) if df is not Nonechecks if collection succeededresults[hostname] = dfstores the DataFrame with the hostname as the key
This builds a dictionary like:
Excel Export with Multiple Sheets¶
This is the biggest change from Tutorial #1!
What it does: Only exports if we have at least one successful result.
Why: If all devices failed, don't create an empty Excel file.
What it does: Creates an Excel writer object using a context manager.
Why:
ExcelWriterallows us to write multiple sheets to one Excel fileengine='openpyxl'specifies which library to use (same one Tutorial #1 uses)- The
withstatement ensures the file is properly saved when done
What it does: Loops through our results dictionary.
Why: results.items() gives us both the key (hostname) and value (DataFrame) for each successful device.
What it does: Truncates the hostname to 31 characters.
Why: Excel has a limitationβsheet names cannot exceed 31 characters. If your hostname is longer, this prevents an error by only taking the first 31 characters.
What it does: Writes this device's DataFrame to its own sheet.
Why:
writeris the Excel file we opened abovesheet_name=sheet_namenames the sheet after the deviceindex=Falseprevents pandas from adding row numbers
Key difference from Tutorial #1: We're calling to_excel() multiple times (once per device), all writing to the same writer object. This creates multiple sheets in one file!
What it does: Confirms each sheet was created.
Why: Real-time feedback during export. For 50 devices, this shows progress.
What it does: Prints final success summary.
Why: Confirms how many devices were exported and where to find the file.
π How to Run the Script¶
Step 1: Create the Inventory CSV¶
Create devices.csv with your device information:
Important: Save this file in the same directory as your Python script.
Step 2: Save the Script¶
Save the complete script as multi_device_show_version.py
Step 3: Run the Script¶
Step 4: Enter Your Password¶
When prompted:
Type your password (it won't be displayed) and press Enter.
Step 5: Watch the Progress¶
You'll see output like:
Notice that even though device 10.1.1.3 failed, the script continued and exported the two successful devices!
π Example Excel Output¶
Open multi_device_show_version.xlsx and you'll see:
- Multiple sheet tabs at the bottom (one per device)
- Each sheet contains that device's show version data
- Sheet names match the device IPs/hostnames
π Trying Different Commands¶
Just like Tutorial #1, you can change the command:
And update the filename:
π Key Concepts Learned¶
Congratulations! You've learned critical production automation patterns:
1. External Inventory Management¶
Instead of hardcoding devices, you now use CSV files. This means:
- Non-programmers can update the device list
- Easy to maintain as your network grows
- Can generate the CSV from other systems (CMDB, monitoring tools, etc.)
2. Continue-on-Error Pattern¶
One device failing doesn't stop the entire job. This is essential for production automation where you might have:
- Devices undergoing maintenance
- Occasional network blips
- Devices with different credential requirements
3. Per-Device Error Handling¶
Each device operation is isolated in a try/except block, providing:
- Clear logging of which device failed and why
- Ability to collect partial results
- Easier troubleshooting
4. Data Aggregation¶
Multiple device results combined into one Excel file with multiple sheets. This is much better than:
- Dozens of separate files
- Having to manually combine data
- Losing track of which device is which
5. User Feedback¶
Progress indicators during long operations keep users informed:
- CSV load confirmation
- Per-device connection status
- Export progress
- Final summary
π Troubleshooting¶
"Could not find file 'devices.csv'"¶
Cause: The CSV file isn't in the same directory as the script.
Solution:
- Check the CSV file exists
- Make sure it's in the same folder as your Python script
- Or use an absolute path:
inventory_file = 'C:/path/to/devices.csv'
Some Devices Fail with "Authentication failed"¶
Cause: Those devices have different credentials.
Solution: See "Advanced Variations" below for per-device passwords.
Excel Sheet Name is Cut Off¶
Cause: Hostname longer than 31 characters (Excel limit).
Solution: This is expected behavior. The script automatically truncates to 31 characters. If you need full hostnames, you could:
- Add a column in the sheet with the full hostname
- Create a mapping file
- Use shorter hostnames in your CSV
No Data Collected (All Devices Failed)¶
Troubleshooting steps:
- Verify you can manually SSH to at least one device
- Check the error messagesβcommon issues:
- Wrong password
- Wrong device_type in CSV
- Devices unreachable
- Test with just one device in the CSV first
π Advanced Variations¶
Different Passwords Per Device¶
If devices have different passwords, modify the CSV and script:
devices.csv with passwords:
Modified script (don't prompt for password):
Security Warning: Storing passwords in CSV is NOT recommended for production. Consider using a vault like HashiCorp Vault, CyberArk, or encrypted files.
Separate Excel Files Per Device¶
If you prefer individual files instead of multiple sheets:
Add Timestamp to Filename¶
To avoid overwriting previous runs:
This creates files like: multi_device_show_version_20260215_143022.xlsx
Filter Devices from CSV¶
Only process specific devices:
π― Next Steps¶
You've now mastered multi-device automation! Ready for the next challenge?
Continue Learning with These Tutorials:
- Configuration Backup (Complete the Beginner Path)
- Save device configurations to disk
- Build timestamped archives for version control
-
Understand data persistence patterns
-
Nornir Fundamentals (Intermediate)
- Learn a powerful framework for scaling automation
- Understand how industries run automation at scale
-
Multi-threaded device operations (10x speed improvement)
-
Enterprise Config Backup with Nornir (Intermediate)
- See the backup pattern scaled to production
- Integration with structured logging and error handling
-
Real-world patterns used in enterprise deployments
Study Production Code:
-
Deep Dives β Review complete production tools
- Access Switch Audit β Learn parallel device collection and PoE intelligence
-
CDP Network Audit β Study threading, configuration, and jump host support
Ready to Deploy?
-
Script Library β Deploy pre-built tools based on these patterns
- Credential vaulting with HashiCorp Vault
- Event-driven automation and webhooks
- GitOps workflows and CI/CD integration
-
Container deployment and orchestration
-
Deep Dives β Study production-grade tools:
- CDP Network Audit β Multi-threaded topology discovery
-
Access Switch Audit β Parallel port health collection
-
Enhance This Script β Practice by adding:
- Progress bars (using the
tqdmlibrary) - Logging to file with the
loggingmodule - Retry logic for failed devices
- Different commands for different device types
- Export to CSV in addition to Excel
π‘ Production Readiness Checklist¶
Want to use this script in production? Consider these enhancements:
π‘ Intermediate Level (Coming Soon in Tutorials)¶
- Threading & Concurrency: Use threading for parallel device connections (10x faster!)
- Advanced TextFSM: Create custom parsing templates for unsupported commands
- Configuration Templating: Use Jinja2 for dynamic configuration generation
- Structured Logging: Implement Python's
loggingmodule with rotating file handlers - Progress Indicators: Add
tqdmprogress bars for long-running operations - Command-Line Arguments: Use
argparseto specify CSV file, commands, output format - Configuration Files: Store settings in YAML/JSON instead of hardcoding
- Input Validation: Verify CSV format, IP addresses, and device types before processing
- Retry Logic: Implement exponential backoff for transient failures
- Data Validation: Sanitize and validate collected data before export
- Exception Handling: Granular error handling for different failure types
- Dry-Run Mode: Preview operations without executing changes
π΄ Expert Level (Coming Soon in Tutorials)¶
- Nornir Framework: Scale to hundreds of devices with Nornir's task-based architecture
- Async Operations: Use
asynciofor true concurrent I/O operations - Database Integration: Store results in PostgreSQL/SQLite for historical trending
- Credential Vaulting: Integrate HashiCorp Vault or AWS Secrets Manager
- API Integration: Trigger automation via REST API endpoints or webhooks
- Message Queuing: Use RabbitMQ or Kafka for distributed task processing
- Observability: Structured logging to ELK stack, metrics to Prometheus/Grafana
- CI/CD Integration: GitHub Actions, GitLab CI for automated testing and deployment
- GitOps Workflows: Store device configs in Git with version control and rollback
- Event-Driven Automation: React to network events (syslog, SNMP traps, streaming telemetry)
- Ansible Integration: Combine Python scripts with Ansible playbooks
- Tool Integration: Netbox for inventory, ServiceNow for CMDB, DNA Center APIs
- Container Deployment: Package as Docker containers with scheduled execution
- Testing & Validation: Unit tests, integration tests, mock device testing
- Multi-Vendor Support: Extend to Arista, Juniper, Palo Alto with NAPALM
These topics are covered in our Intermediate and Expert tutorials!
π¬ What You've Accomplished¶
Impressive! You've evolved from a single-device script to a multi-device automation tool. You now understand:
β
CSV inventory management
β
Looping through devices
β
Continue-on-error patterns
β
Multi-sheet Excel export
β
User feedback during operations
β
Defensive programming techniques
This foundation prepares you for enterprise automation scenarios where resilience and scale matter.
β Back to Beginner Tutorials | Continue to Tutorial #3 β