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.
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.
01
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.
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
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
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.
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
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.
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 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
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.
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
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.
# 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
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.
# 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
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
RouterOS scripting + scheduler + netwatch is EEM's counterpart; the mental model is the same.
| MikroTik / RouterOS | Cisco IOS EEM |
|---|---|
| /system script (named script) | event manager applet |
| /system scheduler (cron) | event timer cron / watchdog |
| /tool netwatch up/down script | event track (+ IP SLA) |
| Log rule triggering a script | event syslog pattern |
| :log info "..." in a script | action ... syslog msg |
| Global variables in scripts | EEM $_ built-in variables |
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
enable/configure terminal actions, and auto-answer prompts with pattern.$_ variables. The matched message, timestamp, and track state turn a fixed applet into one that reacts to what actually happened.maxrun, ratelimit, and non-triggering actions.event manager run, watch show event manager history, and keep no event manager applet ready. For fleet-wide change, reach for Ansible instead.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 →