Back to Blog
Tutorial6 min

Python Network Automation Lab for Beginners

Get started with network automation using Python and Netmiko. Connect to routers via SSH, pull configs, push changes, and build your first automation script.

S
Sarah Chen
Network Engineer

Network automation is no longer optional. It's on the CCNA exam, it's a dedicated Cisco certification track, and it's what separates senior engineers from junior ones in job interviews.

The good news: you don't need to be a software developer. If you can configure a router via CLI, you can automate it with Python. This lab gets you from zero to your first working automation script.

What You Need

  • A network lab with SSH-enabled devices (routers or switches)
  • Python 3 installed
  • The Netmiko library (pip install netmiko)

To generate a lab with SSH-ready devices:

Build a network automation lab with 3 Cisco routers running OSPF.
All devices must be accessible via SSH with username admin and password cisco123.

Step 1: Connect to a Router

The most basic automation task — connect to a device and run a show command:

from netmiko import ConnectHandler
 
device = {
    "device_type": "cisco_ios",
    "host": "10.0.1.1",
    "username": "admin",
    "password": "cisco123",
}
 
connection = ConnectHandler(**device)
output = connection.send_command("show ip interface brief")
print(output)
connection.disconnect()

Run this script and you'll see the same output as if you typed the command manually:

Interface                  IP-Address      OK? Method Status                Protocol
GigabitEthernet0/0         10.0.1.1        YES manual up                    up
GigabitEthernet0/1         192.168.1.1     YES manual up                    up

That's it — you just automated your first network task. The script connects via SSH, runs the command, captures the output, and disconnects.

Step 2: Connect to Multiple Devices

The real power of automation is doing the same thing across many devices at once:

from netmiko import ConnectHandler
 
devices = [
    {
        "device_type": "cisco_ios",
        "host": "10.0.1.1",
        "username": "admin",
        "password": "cisco123",
    },
    {
        "device_type": "cisco_ios",
        "host": "10.0.1.2",
        "username": "admin",
        "password": "cisco123",
    },
    {
        "device_type": "cisco_ios",
        "host": "10.0.1.3",
        "username": "admin",
        "password": "cisco123",
    },
]
 
for device in devices:
    connection = ConnectHandler(**device)
    hostname = connection.send_command("show run | include hostname")
    version = connection.send_command("show version | include uptime")
    print(f"{hostname}")
    print(f"  {version}")
    print()
    connection.disconnect()

Output:

hostname R1
  R1 uptime is 2 hours, 15 minutes

hostname R2
  R2 uptime is 2 hours, 14 minutes

hostname R3
  R3 uptime is 2 hours, 13 minutes

Three devices checked in seconds. Manually, that's three SSH sessions, three show commands, three disconnects. With automation, it's one script run.

Step 3: Push Configuration Changes

Reading is useful. Writing configs is where automation saves serious time:

from netmiko import ConnectHandler
 
device = {
    "device_type": "cisco_ios",
    "host": "10.0.1.1",
    "username": "admin",
    "password": "cisco123",
}
 
config_commands = [
    "interface Loopback99",
    "ip address 99.99.99.1 255.255.255.255",
    "description Created by automation",
    "no shutdown",
]
 
connection = ConnectHandler(**device)
output = connection.send_config_set(config_commands)
print(output)
 
# Verify the change
result = connection.send_command("show ip interface brief | include Loopback99")
print(f"\nVerification: {result}")
 
connection.disconnect()

send_config_set() enters config mode, pushes each command, and exits config mode automatically. No need to type configure terminal or end.

Step 4: Backup Configs Across All Devices

A practical script every network team needs — back up running configs to files:

from netmiko import ConnectHandler
from datetime import datetime
 
devices = [
    {"device_type": "cisco_ios", "host": "10.0.1.1", "username": "admin", "password": "cisco123"},
    {"device_type": "cisco_ios", "host": "10.0.1.2", "username": "admin", "password": "cisco123"},
    {"device_type": "cisco_ios", "host": "10.0.1.3", "username": "admin", "password": "cisco123"},
]
 
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
 
for device in devices:
    connection = ConnectHandler(**device)
    hostname = connection.send_command("show run | include hostname").split()[-1]
    config = connection.send_command("show running-config")
 
    filename = f"{hostname}_{timestamp}.txt"
    with open(filename, "w") as f:
        f.write(config)
 
    print(f"Saved {filename}")
    connection.disconnect()

Output:

Saved R1_20260316_1430.txt
Saved R2_20260316_1430.txt
Saved R3_20260316_1430.txt

Three routers backed up in seconds. Schedule this to run daily and you have automated config backups.

Step 5: OSPF Neighbor Check Script

A more practical example — verify OSPF neighbors across all routers and flag any issues:

from netmiko import ConnectHandler
 
devices = [
    {"device_type": "cisco_ios", "host": "10.0.1.1", "username": "admin", "password": "cisco123"},
    {"device_type": "cisco_ios", "host": "10.0.1.2", "username": "admin", "password": "cisco123"},
    {"device_type": "cisco_ios", "host": "10.0.1.3", "username": "admin", "password": "cisco123"},
]
 
for device in devices:
    connection = ConnectHandler(**device)
    hostname = connection.send_command("show run | include hostname").split()[-1]
    neighbors = connection.send_command("show ip ospf neighbor")
 
    if "FULL" in neighbors:
        full_count = neighbors.count("FULL")
        print(f"✅ {hostname}: {full_count} OSPF neighbors FULL")
    else:
        print(f"❌ {hostname}: No FULL OSPF neighbors - CHECK THIS")
 
    connection.disconnect()

Output:

✅ R1: 2 OSPF neighbors FULL
✅ R2: 2 OSPF neighbors FULL
✅ R3: 2 OSPF neighbors FULL

This is the kind of script that runs as a health check after maintenance windows.

Multi-Vendor: Juniper Example

Netmiko supports multiple vendors. Here's the same pattern for a Juniper device:

from netmiko import ConnectHandler
 
juniper_device = {
    "device_type": "juniper_junos",
    "host": "10.0.2.1",
    "username": "admin",
    "password": "juniper123",
}
 
connection = ConnectHandler(**juniper_device)
output = connection.send_command("show interfaces terse")
print(output)
connection.disconnect()

Change device_type and the commands — the connection logic stays the same. Netmiko handles the SSH differences between vendors.

Common Mistakes

1. SSH not enabled on the device

Netmiko connects via SSH. If your router only has telnet or console access, the connection will fail. Make sure SSH is configured:

R1(config)# hostname R1
R1(config)# ip domain-name lab.local
R1(config)# crypto key generate rsa modulus 2048
R1(config)# line vty 0 4
R1(config-line)# transport input ssh
R1(config-line)# login local
R1(config)# username admin privilege 15 secret cisco123

2. Wrong device_type

cisco_ios is for IOS. If your device runs IOS-XE, IOS-XR, or NX-OS, you need a different device type. Check Netmiko's documentation for the full list.

3. Not handling exceptions

In production, devices might be unreachable. Wrap connections in try/except:

from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoTimeoutException
 
try:
    connection = ConnectHandler(**device)
    output = connection.send_command("show version")
except NetmikoTimeoutException:
    print(f"Could not connect to {device['host']}")

What's Next

Once you're comfortable with Netmiko basics:

  • TextFSM / Genie parsing — parse CLI output into structured data instead of raw text
  • Ansible — declarative automation (describe the desired state, let Ansible figure out the commands)
  • NAPALM — vendor-neutral library for config management and operational data
  • REST APIs — interact with modern network controllers programmatically

For more on how automation fits into the CCNA, see CCNA Automation: What Changed in 2026. Or practice routing fundamentals in CCNP labs.


Ready to automate? Get started with NetPilot — build a lab with SSH-ready devices and start writing automation scripts in minutes.

Try NetPilot Free

Build enterprise-grade network labs in seconds with AI assistance

Get Started Free