Automatic RouterOS notifications for new versions

May 31, 2023
mikrotik scripting

Mikrotik routers are a good option for a power user on a budget. Dedicated switching hardware combined with the Linux-based RouterOS means everything is configurable via ssh, from VLANs to RADIUS to weird protocols like MPLS.

They also release (relatively) timely security updates, which is pretty high on my requirements list these days, as SOHO routers are being increasingly targeted by script kiddies and nation states alike.

RouterOS supports basic scripting of commands, and scheduling of scripts. This post will show how to combine these features to provide something that ROS doesn’t support natively - automatically notifying the admin via email when a firmware update is ready to be installed.

If you want to skip the explanation and just see the recipe, click here.


Configure outbound email server

This script notifies you with an email, which means it needs a configured email (SMTP) server, port and credentials.

/tool/email/set port=465 tls=yes vrf=main user=yourusername password=bG9sIG5pY2UgdHJ5Cg==

Scripting Basics


The interactive console does double-duty as a REPL. By prefixing commands with ‘:’ you can test fragments easily. Semicolons seem to be optional.

[admin@MikroTik] > :put "hello"


Declaration doesn’t use an explicit operator; a single equals is used for testing equality (see below section on if).

You can set a variable and reference it later, although you can’t combine declaration and assignment (C89 vibes). Variable scope can be local or global, however local can only be used within functions. In the repl only global is valid.

[admin@MikroTik] > :global myVal
[admin@MikroTik] > :set myVal "Hello"
[admin@MikroTik] > :put $myVal

Nested expansion

You can use square brackets for command expansion and nesting is supported.

[admin@MikroTik] > :global newIP [/ip address get [find interface="ether1"] address]
[admin@MikroTik] > :put $newIP

If statement

[admin@MikroTik] > :global a 1
[admin@MikroTik] > :global b 2
[admin@MikroTik] > :if ($a = $b) do={ :put "Equal" } else={ :put "not equal" }
not equal
[alex@MikroTik] >

There are more examples here

Putting it together

As far as I know there is no way to load a script from a file, so we just paste it into the console. There’s also a built-in editor that resembles GNU nano.

/system script
add dont-require-permissions=no name="my-update-notifier" owner=admin policy=read source= {
    local emailAddress;
    /system package update;
       set channel=stable;
       :local instVer [/system/package/update/get installed-version];
       :local latestVer [/system/package/update/get latest-version];
       :if ($instVer != $latestVer) do={
          :log info "Update check: current=$instVer available=$latestVer: sending email"
          /tool e-mail send to=$emailAddress subject="RouterOS $latestVer Released" body="Automated notification\nYou are running $instVer, the latest  available is $latestVer."

You can test it by invoking it manually. eg:

[alex@MikroTik] > /system/script/run my-update-notifier
            channel: stable
  installed-version: 7.9.2
     latest-version: 7.10.1
             status: New version is available

You should receive an email.

Schedule it

Add a scheduler action to fire every 3 hours and run your script.

/system scheduler
add interval=3h name="sched-update-notifier" on-event=my-update-notifier policy=read

Note that the scheduler has no way of knowing if it’s already fired for a given update. If you set it to check every hour, but you don’t install the update right away, it will send another email an hour later, and another, until you update.

Having the rule disarm itself might be a fun project for another time. For now it’s a good incentive to apply updates promptly so your inbox doesn’t get spammed :-)