Python for Network Automation with Netmiko

A practical guide to automating Cisco CLI commands using Python and the Netmiko library.

← Back to all articles

Network automation is no longer optional—it's an operational necessity. The netmiko library simplifies SSH connections to network devices, making it the perfect starting point for network engineers learning Python.

This guide covers the core concepts and a practical script to automate Cisco device management.

1. Installing Netmiko

pip install netmiko

Netmiko supports a wide range of devices including Cisco (IOS, IOS-XE, NX-OS), Arista, Juniper, and many others.

2. Basic Connection

Here is a simple script to connect to a Cisco device and run a show command:

from netmiko import ConnectHandler

device = {
    "device_type": "cisco_ios",
    "ip": "192.168.1.1",
    "username": "admin",
    "password": "secret"
}

connection = ConnectHandler(**device)
output = connection.send_command("show ip interface brief")
print(output)
connection.disconnect()

This connects to the device, runs show ip interface brief, and prints the output.

3. Handling Different Prompts

Some devices require an enable password to access privileged EXEC mode:

device = {
    "device_type": "cisco_ios",
    "ip": "192.168.1.1",
    "username": "admin",
    "password": "secret",
    "secret": "enable_password"   # Enable mode password
}

connection = ConnectHandler(**device)
connection.enable()   # Enter enable mode
output = connection.send_command("show running-config")
print(output)

4. Sending Configuration Commands

To send configuration commands, use send_config_set():

config_commands = [
    "interface GigabitEthernet0/1",
    "description Connected to Uplink",
    "no shutdown"
]

output = connection.send_config_set(config_commands)
print(output)

This enters configuration mode, applies the commands, and exits.

5. Saving the Configuration

After making changes, it's crucial to save the configuration:

connection.send_command("write memory")

Alternatively:

connection.send_command("copy running-config startup-config")

6. Handling Multiple Devices (List Iteration)

To manage multiple devices simultaneously:

devices = [
    {"ip": "192.168.1.1", "username": "admin", "password": "secret1"},
    {"ip": "192.168.1.2", "username": "admin", "password": "secret2"},
]

for device in devices:
    device["device_type"] = "cisco_ios"
    connection = ConnectHandler(**device)
    output = connection.send_command("show version")
    print(f"Device: {device['ip']}")
    print(output[:200])   # Print first 200 characters
    connection.disconnect()

7. Error Handling

Network devices can be unreachable, authentication can fail, or commands can time out. Add exception handling:

from netmiko import ConnectHandler, NetMikoTimeoutException, NetMikoAuthenticationException

try:
    connection = ConnectHandler(**device)
    output = connection.send_command("show interfaces status")
    print(output)
except NetMikoTimeoutException:
    print("Connection timed out. Check IP or firewall.")
except NetMikoAuthenticationException:
    print("Authentication failed. Check username/password.")
finally:
    try:
        connection.disconnect()
    except:
        pass
Pro Tip: Use the send_command_timing() method if your device requires you to handle interactive prompts that are not part of the standard command set (e.g., confirmation messages).

8. Backing Up Configurations to a File

This script retrieves the running configuration from a device and saves it to a text file:

from datetime import datetime

connection = ConnectHandler(**device)
config = connection.send_command("show running-config")

filename = f"backup_{device['ip']}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
with open(filename, "w") as f:
    f.write(config)

print(f"Backup saved to {filename}")
connection.disconnect()

9. Parsing Output with TextFSM

Netmiko can parse structured data using TextFSM templates:

output = connection.send_command("show version", use_textfsm=True)
print(output)  # This returns a list of dictionaries

For older devices, you may need to explicitly set the template path. See the official Netmiko documentation for the latest guidance on TextFSM templates.

10. Full Practical Script: Checking Interface Status

from netmiko import ConnectHandler

def check_interface_status(device, interface):
    try:
        conn = ConnectHandler(**device)
        output = conn.send_command(f"show interfaces {interface}")
        if "administratively down" in output:
            status = "Administratively Down"
        elif "down" in output:
            status = "Down"
        else:
            status = "Up"
        print(f"Interface {interface} is {status}")
        conn.disconnect()
        return status
    except Exception as e:
        print(f"Error: {e}")
        return None

# Example usage
device = {
    "device_type": "cisco_ios",
    "ip": "192.168.1.1",
    "username": "admin",
    "password": "secret"
}

check_interface_status(device, "GigabitEthernet0/1")

11. Additional Notes on SSH

SSH can be a performance bottleneck when executing multiple commands. For batch operations, using send_command with delay_factor can help mitigate inconsistencies in slower environments:

output = conn.send_command("show version", delay_factor=2)