Back to blog

Cisco / IOS  ·  Tutorial  ·  August 2026

Cisco IOS
EEM Automation

The router can watch its own logs and act. Embedded Event Manager runs little applets that trigger on a syslog message, a timer, or a tracked failure — and respond with CLI commands. Auto-recover a downed port, snapshot the config the instant it changes, email you on an event. IOS scripting, the RouterOS way.

Cisco IOS EEM Automation Applet Event Manager Ops

EVENT syslog · timer · track · none ACTIONS cli · syslog · mail · reload EEM applet "When THIS happens, run THESE commands." No external server, no NMS — it lives on the box.

Embedded Event Manager is a small automation engine built into IOS. Every applet has the same shape: one event that triggers it (a syslog message matching a pattern, a timer, a tracked object changing state, a manual run) and a list of actions that run when it fires — usually CLI commands, plus logging or email. No external orchestrator, no NMS, no agent: the logic lives on the device and keeps working even when the management network is down.

That makes EEM perfect for the small, local reflexes that would otherwise page a human: re-enable a port that a security feature shut, snapshot the config the moment someone changes it, clear stale NAT when a WAN fails over, or fire an alert on a specific event. It's the Cisco answer to MikroTik's scripting + scheduler — and it composes with everything earlier in this series, since the events it watches (err-disable, track state, config change) are exactly the ones those posts generate.

Prerequisites

01

Anatomy of an Applet

One event line, numbered action lines. The simplest useful applet: log a custom message whenever an interface goes down. Start here to see the shape.

IOS — a minimal syslog-triggered applet
R1(config)# event manager applet LINK-DOWN-ALERT
# EVENT: fire when a matching syslog message appears
R1(config-applet)# event syslog pattern "Interface GigabitEthernet0/1, changed state to down"
# ACTIONS: numbered so they run in order
R1(config-applet)# action 1.0 syslog msg "EEM: Gi0/1 went down — investigate"
R1(config-applet)# action 2.0 cli command "enable"
R1(config-applet)# action 3.0 cli command "show interface GigabitEthernet0/1" 
R1(config-applet)# action 4.0 syslog msg "EEM: captured interface state to buffer"
R1(config-applet)# end

# Confirm it's registered and watch its run count
R1# show event manager policy registered
R1# show event manager history events
⚠ Gotcha — Applets Run Non-Interactively; Start with "enable"

EEM CLI actions execute as if typed at a fresh session, so they begin in user EXEC — if an action needs privileged or config mode, the applet must walk itself there: action ... cli command "enable", then "configure terminal", then the real commands. And there's no human to answer prompts: any command that asks a question will hang unless you either avoid the interactive form or add action ... cli command "..." pattern "confirm" to auto-answer. Test every applet on lab gear — an applet that loops or mis-fires on production is a self-inflicted outage.

02

Use Case — Auto-Recover an err-disabled Port

The Switch Security post left ports going err-disabled on a violation, needing a manual bounce. EEM can watch for that log and recover the port after a delay — no help-desk call.

IOS — recover a psecure-violation err-disable
R1(config)# event manager applet PSECURE-RECOVER
R1(config-applet)# event syslog pattern "PSECURE_VIOLATION.*Gi0/5"
R1(config-applet)# action 1.0 syslog msg "EEM: Gi0/5 err-disabled — recovering in 60s"
R1(config-applet)# action 2.0 wait 60
R1(config-applet)# action 3.0 cli command "enable"
R1(config-applet)# action 4.0 cli command "configure terminal"
R1(config-applet)# action 5.0 cli command "interface Gi0/5"
R1(config-applet)# action 6.0 cli command "shutdown"
R1(config-applet)# action 7.0 cli command "no shutdown"
R1(config-applet)# action 8.0 syslog msg "EEM: Gi0/5 recovered"
R1(config-applet)# end
# (The built-in "errdisable recovery" does this too; EEM lets you scope it
# to ONE port, add a delay, log it, or notify — finer control than the global.)

03

Use Case — Snapshot Config on Every Change

An audit trail for free: whenever anyone saves or alters the config, EEM archives a copy off-box and logs who did it. Pairs with the archive feature from the backup post.

IOS — back up when the config is changed
R1(config)# event manager applet CONFIG-BACKUP
# Fires on the "configured from console/vty" syslog IOS emits on a change
R1(config-applet)# event syslog pattern "SYS-5-CONFIG_I"
R1(config-applet)# action 1.0 cli command "enable"
R1(config-applet)# action 2.0 cli command "copy running-config scp://backup@192.168.1.50/R1-$_event_pub_sec.cfg" pattern "assword"
R1(config-applet)# action 3.0 cli command "BackupPass123"
R1(config-applet)# action 4.0 syslog msg "EEM: config changed — off-box backup taken"
R1(config-applet)# end
# $_event_pub_sec is a built-in EEM variable (event timestamp) — handy for
# unique filenames. "pattern" auto-answers the password prompt.
💡 EEM Built-in Variables Make Applets Smart

EEM exposes context about the triggering event through $_ variables: $_syslog_msg (the full matched log line), $_event_pub_sec (when it fired), and for track events $_track_state (up/down). Use them to build unique filenames, include the offending message in an alert, or branch behaviour. Combined with action ... regexp to extract a value (like the interface name) from the matched message, applets go from "do a fixed thing" to "react intelligently to what actually happened" — genuinely small programs, running on the router.

04

Use Case — Clear NAT on WAN Failover

The exact loose end from the IP SLA failover post: stale NAT translations linger on the old WAN after a failover. A track-driven applet flushes them the instant the track flips.

IOS — flush NAT when track 1 (the WAN probe) goes down
R1(config)# event manager applet FLUSH-NAT-ON-FAILOVER
# EVENT: the same track object that drives the failover route + HSRP
R1(config-applet)# event track 1 state any
R1(config-applet)# action 1.0 syslog msg "EEM: WAN track changed to $_track_state — clearing NAT"
R1(config-applet)# action 2.0 cli command "enable"
R1(config-applet)# action 3.0 cli command "clear ip nat translation *"
R1(config-applet)# end
# Now failover is fully hands-off: probe fails → route switches (routing post)
# → gateway fails over (HSRP post) → NAT flushes (here). One track, three
# reactions, zero human involvement.

05

Use Case — Scheduled Tasks with a Timer

EEM timers replace kron for many jobs and are more flexible — cron-style schedules, countdown timers, or watchdog intervals that run something every N seconds.

IOS — a nightly and an interval applet
# Cron-style: every day at 02:30, save + back up
R1(config)# event manager applet NIGHTLY-SAVE
R1(config-applet)# event timer cron cron-entry "30 2 * * *"
R1(config-applet)# action 1.0 cli command "enable"
R1(config-applet)# action 2.0 cli command "write memory"
R1(config-applet)# action 3.0 syslog msg "EEM: nightly config save complete"
R1(config-applet)# exit

# Watchdog: every 300s, log the CPU if it's a concern (health heartbeat)
R1(config)# event manager applet CPU-HEARTBEAT
R1(config-applet)# event timer watchdog time 300
R1(config-applet)# action 1.0 cli command "enable"
R1(config-applet)# action 2.0 cli command "show processes cpu | include CPU utilization"
R1(config-applet)# end

06

Verify, Test & Safely Manage Safe to Run

Register, run manually to test, watch the history, and know how to disable one fast if it misbehaves. EEM runs real commands — treat applets like code.

IOS — the EEM control commands
# Test an applet on demand without waiting for its event (add "event none")
R1# event manager run MY-APPLET

# What's registered, and their run counts?
R1# show event manager policy registered

# Did applets fire, and did their actions succeed?
R1# show event manager history events
R1# show event manager history traps

# Kill a misbehaving applet immediately
R1(config)# no event manager applet PSECURE-RECOVER
⚠ Gotcha — Beware the Feedback Loop

The classic EEM footgun: an applet whose actions generate the event that triggers it. An applet that reacts to SYS-5-CONFIG_I (a config change) and then makes a config change will retrigger itself, potentially in a tight loop that pegs the CPU. Guard against it: use action ... cli commands that don't emit the watched pattern, add a maxrun limit (event manager applet X ... maxrun 30) so an applet can't run forever, and rate-limit with ratelimit. Always test with event manager run and watch show event manager history before trusting an applet on production.

07

MikroTik ↔ Cisco — On-Box Automation

RouterOS scripting + scheduler + netwatch is EEM's counterpart; the mental model is the same.

MikroTik / RouterOSCisco IOS EEM
/system script (named script)event manager applet
/system scheduler (cron)event timer cron / watchdog
/tool netwatch up/down scriptevent track (+ IP SLA)
Log rule triggering a scriptevent syslog pattern
:log info "..." in a scriptaction ... syslog msg
Global variables in scriptsEEM $_ built-in variables
💡 When to Reach for Tcl or Guest Shell Instead

Applets are great for "match an event, run some commands." When you need real logic — loops, math, parsing structured output, calling an API — IOS also supports EEM Tcl scripts, and modern IOS-XE adds a Linux Guest Shell (Python on the box). For fleet-wide automation, though, the better tool is off-box config management (Ansible), which is the next post. Rule of thumb: EEM for local, autonomous reflexes that must work even when the network to the device is down; Ansible for orchestrating change across many devices from a central point.

Takeaways

  1. Every applet is event → actions. A trigger (syslog / timer / track / none) and numbered CLI+log+mail actions. The logic lives on the box and runs even when the management network is down.
  2. Actions start in user EXEC and can't be prompted. Walk to privileged/config mode with enable/configure terminal actions, and auto-answer prompts with pattern.
  3. Best uses are small local reflexes: recover an err-disabled port, snapshot config on change, flush NAT on failover, alert on a specific event.
  4. It closes loops from earlier posts: the same track that drives IP SLA failover and HSRP can trigger an applet to clear NAT — fully hands-off failover.
  5. Use the $_ variables. The matched message, timestamp, and track state turn a fixed applet into one that reacts to what actually happened.
  6. Guard against feedback loops. An applet that causes its own trigger can run away — use maxrun, ratelimit, and non-triggering actions.
  7. Test like code. event manager run, watch show event manager history, and keep no event manager applet ready. For fleet-wide change, reach for Ansible instead.

Want your network to fix its own small problems in Crete?

NOCTIS builds self-healing automation — port recovery, auto-backup, failover cleanup, proactive alerts — into the Cisco and MikroTik gear we manage, so the little 3am problems resolve themselves and the big ones page us with context.

Book a Discovery Call →