Home > Networking > Script to backup config for Cisco Catalyst 1300 with Python and Paramiko

Script to backup config for Cisco Catalyst 1300 with Python and Paramiko

Running standard IOS backup scripts on your shiny new Catalyst 1300 switches only to hit walls with truncated outputs or command mismatches? You’re not alone—these industrial Ethernet beasts (IE-1300 series) run a streamlined IOS-XE variant with tweaks that break old playbooks. Forget terminal length 0 for pagination; it demands terminal datadump to unleash full show running-config flows. Interface syntax? Version pulls? Clock syncs? All subtly shifted, turning generic scripts into frustration fests.

Enter this guide: a battle-tested Paramiko script dialed in for C1300 quirks, pulling show running-config, show interfaces status, show version, and show clock into bundled, timestamped files (e.g., 192_168_1_10_20251016.txt). No more manual SSH marathons—automate audits that actually work on your next-gen gear. If you’re migrating from classic IOS catalysts, this is your upgrade path to reliable auto-backups. Let’s script the future.

Why This Matters for Catalyst 1300 Owners

Traditional IOS automation shines on Catalyst 2960s or 9300s, but the 1300’s lightweight IOS-XE (like v4.1.6.54) introduces syntax variances: pagination killers like “More:” prompts ignore length tweaks, and outputs need datadump to flow freely. Result? Scripts grab 1% of configs, leaving you blind to port states or firmware details. This tailored approach fixes that—full captures for compliance, troubleshooting, or baseline logging. Scale it across your access/industrial edges, and reclaim hours from CLI drudgery.

Prerequisites

  • Python 3.x: Fresh install if you’re starting.
  • Paramiko: Hit pip install paramiko for SSH muscle.
  • SSH Access: Privileged logins (no enable mode—verify: show run spits full output on connect).
  • IP Inventory: access_switch.txt with IPs, one per line.
  • Output Folder: Script auto-makes D:\python\ for your audit dumps.

Security Callout: Hardcode creds for PoCs only—migrate to env vars or HashiCorp Vault for real deployments.

The Script: C1300-Optimized Audit Engine

Save as cisco_1300_audit_datadump.py. It’s built from the ground up for 1300 syntax, chaining commands with datadump to ensure complete pulls.

import paramiko
import sys
import time
import os
from datetime import datetime  # For timestamped filenames

# HARDCODED CREDENTIALS - REPLACE WITH YOURS (SECURE IN PROD)
username = 'your_username'  # e.g., 'admin'
password = 'your_password'  # e.g., 'cisco123'

# Path to TXT file with switch IPs (one per line)
ips_file_path = r'C:\path\to\your\access_switch.txt'  # Adjust for your OS

# Local backup directory - creates if missing
backup_dir = r'D:\python'
os.makedirs(backup_dir, exist_ok=True)

def send_and_capture(shell, command, timeout=5):
    """
    Helper: Send a command via shell, capture full output.
    """
    shell.send(command + '\n')
    time.sleep(timeout)  # Initial buffer

    output = ''
    max_wait = 30  # Safeguard loop
    wait_count = 0
    while wait_count < max_wait:
        if shell.recv_ready():
            output += shell.recv(4096).decode('utf-8')
            wait_count = 0
        else:
            time.sleep(0.1)
            wait_count += 1

    return output

def backup_config(ip, username, password):
    """
    SSH to Cisco C1300 switch, enable datadump, grab multiple show outputs (no enable needed), and save bundled to local file with IP+date.
    Returns filename on success or None on failure.
    """
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    timestamp = datetime.now().strftime('%Y%m%d')  # e.g., 20251016
    filename = f"{ip.replace('.', '_')}_{timestamp}.txt"  # e.g., 192_168_1_10_20251016.txt
    filepath = os.path.join(backup_dir, filename)

    try:
        # Connect
        client.connect(
            hostname=ip,
            username=username,
            password=password,
            timeout=10,
            look_for_keys=False,
            allow_agent=False
        )

        # Interactive shell
        shell = client.invoke_shell()
        time.sleep(2)

        # Disable pagination with C1300-specific command
        shell.send('terminal datadump\n')
        time.sleep(1)
        while not shell.recv_ready():
            time.sleep(0.1)
        shell.recv(4096).decode('utf-8')  # Drain echo

        # Capture outputs
        run_config = send_and_capture(shell, 'show running-config', timeout=10)  # Longer for config
        int_status = send_and_capture(shell, 'show interfaces status')
        version = send_and_capture(shell, 'show version')
        clock = send_and_capture(shell, 'show clock')

        # Exit
        shell.send('exit\n')
        time.sleep(1)
        client.close()

        # Bundle with separators
        audit_text = f"""=== RUNNING CONFIG ===
{run_config}

=== INTERFACES STATUS ===
{int_status}

=== VERSION ===
{version}

=== CLOCK ===
{clock}
"""

        # Trim to clean sections where possible
        audit_text = audit_text.replace('\x1b[0m', '')  # Strip ANSI codes if any

        with open(filepath, 'w') as f:
            f.write(audit_text)

        line_count = len(audit_text.splitlines())
        print(f"Audit saved: {filepath} ({line_count} lines)")
        return filepath

    except paramiko.AuthenticationException:
        print(f"Auth failed on {ip}")
        return None
    except paramiko.SSHException as e:
        print(f"SSH error on {ip}: {e}")
        return None
    except Exception as e:
        print(f"Unexpected error on {ip}: {e}")
        return None
    finally:
        try:
            client.close()
        except:
            pass

if __name__ == "__main__":
    # Validate file
    if not os.path.exists(ips_file_path):
        print(f"ERROR: IP file not found: {ips_file_path}")
        sys.exit(1)

    # Load IPs
    with open(ips_file_path, 'r') as f:
        switch_ips = [line.strip() for line in f if line.strip()]

    if not switch_ips:
        print("ERROR: No IPs in file.")
        sys.exit(1)

    # Cred check
    if username == 'your_username' or password == 'your_password':
        print("ERROR: Update credentials in script (lines 8-9).")
        sys.exit(1)

    print(f"Loaded {len(switch_ips)} switches from {ips_file_path}")
    print(f"Audits will save to {backup_dir}")
    print("\nStarting device audits...\n")

    success_count = 0
    for ip in switch_ips:
        result = backup_config(ip, username, password)
        if result:
            success_count += 1

    print(f"\nAudit complete: {success_count}/{len(switch_ips)} successful.")
    print("Check D:\\python for bundled files.")

Code Deep Dive

  1. Setup Basics: Grabs essentials, preps D:\python\—Windows-friendly paths with raw strings.
  2. Capture Helper: send_and_capture is your workhorse—sends, times out smartly, loops to nab every byte. Extra buffer for verbose show run.
  3. Main Action (backup_config):
  • SSH handshake, shell spin-up.
  • terminal datadump: The 1300 magic—bypasses pagination where length 0 flops.
  • Command Barrage: show running-config (tuned timeout), show interfaces status (port vibes), show version (firmware facts), show clock (time truth).
  • Bundle & Polish: Sections with === tags, ANSI scrub for clean reads.
  • File Drop: IP+date naming, line count for quick QA.
  1. Launcher: IP load, cred nag, loop with success tracking.

Execution Guide

  1. Swap in creds, point ips_file_path to your list.
  2. Sample access_switch.txt:
   192.168.1.10
   192.168.1.11
   10.0.0.5
  1. Run: python cisco_1300_audit_datadump.py.
  2. Console Tease:
   Loaded 3 switches from C:\path\to\your\access_switch.txt
   Audits will save to D:\python

   Starting device audits...

   Audit saved: D:\python\192_168_1_10_20251016.txt (823 lines)
   Audit saved: D:\python\192_168_1_11_20251016.txt (756 lines)
   Auth failed on 10.0.0.5

   Audit complete: 2/3 successful.
   Check D:\python for bundled files.

Inside a File (C1300-Style Output):

   === RUNNING CONFIG ===
   config-file-header
   KTI-sw01
   v4.1.6.54 / RLSB4.1.6_951_410_024
   ... [full config, no truncation] ...
   end

   === INTERFACES STATUS ===
   Port      Name               Status       Vlan       Duplex  Speed Type
   Gi1/0/1                      connected    1          a-full  a-1000 10/100/1000BaseTX
   ... [complete port roster] ...

   === VERSION ===
   Cisco IOS XE Software, C1300-8T2E (Industrial Ethernet)
   ... [hardware/software deets] ...

   === CLOCK ===
   *13:45:22.123 UTC Wed Oct 16 2025

Field-Tested Tweaks

  • Syntax Sensitivities: If your 1300 firmware varies (e.g., pre-4.1), test terminal datadump manually—fallback to space-sending loops if needed.
  • Expand the Arsenal: Add show vlan brief or show env temp? Just send_and_capture it in.
  • Bulk Mode: 100+ devices? Thread with concurrent.futures (cap at 10 concurrent to spare your TACACS).
  • Post-Process: awk '/down/{print $1}' for err-disable hunts, or pandas for CSV exports.
  • 1300 Prods: These run hot in industrial spots—pair audits with SNMP for env monitoring.
  • Debug Drill: Log len(output) per command to confirm fullness.

Leave a Comment