Compare commits

...

162 commits

Author SHA1 Message Date
Christian Hesse
c0678f0501 INITIAL-COMMANDS: add missing space 2025-12-01 11:25:28 +01:00
Christian Hesse
73350ff3f4 README: add missing space 2025-12-01 11:25:00 +01:00
Christian Hesse
7caaa62321 check-perpetual-license: add scroll symbol in notification
doc/check-perpetual-license.d/notification-01-warn.avif
----- >8 -----
[rsc] 📜⚠️ License about to expire!

Your license failed to renew and is about to expire on 2025-09-13 12:12:23 on rsc...
----- >8 -----

doc/check-perpetual-license.d/notification-02-renew.avif
----- >8 -----
[rsc] 📜️ License renewed

Your license was successfully renewed on rsc. It is now valid until 2025-10-25 08:42:46.
----- >8 -----
2025-11-27 11:26:04 +01:00
Christian Hesse
1f11f72d18 global-functions: $SymbolByUnicodeName: add special with magic 2025-11-27 08:49:56 +01:00
Christian Hesse
daeb173dbc doc/check-routeros-update: add screenshot from terminal 2025-11-25 18:44:52 +01:00
Christian Hesse
4acbd6449e Merge branch 'notifications' into next 2025-11-25 17:37:00 +01:00
Christian Hesse
9db7f4494c doc/sms-forward: update notifications
doc/sms-forward.d/notification.avif
----- >8 -----
[rsc] 📨️ SMS Forwarding from 7277

Received this message by rsc from 7277:

📨️ On 2025-08-20 01:01:15+02:00 type class-0:
Welcome to our network!
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
2d0c79160d doc/netwatch-notify: update notifications
doc/netwatch-notify.d/notification-01-down.avif
----- >8 -----
[rsc] ️ Netwatch Notify: ipv6.eworm.de down

The host 'ipv6.eworm.de' (2a01:4f8:222:1e83::80, ipv6.eworm.de) is down since 2025-11-18 11:33:18.
----- >8 -----

doc/netwatch-notify.d/notification-02-up.avif
----- >8 -----
[rsc] ️ Netwatch Notify: ipv6.eworm.de up

The host 'ipv6.eworm.de' (2a01:4f8:222:1e83::80, ipv6.eworm.de) is up since 2025-11-18 11:43:15.
It was down for 10 checks since 2025-11-18 11:33:18.
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
b6e72f9a9f doc/log-forward: update notifications
doc/log-forward.d/notification-01-info.avif
----- >8 -----
[rsc] 📝️ Log Forwarding

The log on rsc contains these 2 messages after 00:01:19 uptime.

ℹ️ 2025-11-20 16:40:25 system;info router rebooted by ssh:eworm@10.10.0.37
ℹ️ 2025-11-20 16:40:27 script;info global-functions: Loaded on hAP ax^2 with RouterOS 7.20.4 (stable).
----- >8 -----

doc/log-forward.d/notification-02-warn.avif
----- >8 -----
[rsc] 📝⚠️ Log Forwarding

The log on rsc contains these 3 messages after 01:23:19 uptime.

🟠️ 2025-11-20 17:35:48 dhcp;warning dhcp offering lease 192.168.2.254 for 02:00:BA:DC:AB:1E without success
🔴️ 2025-11-20 17:35:57 dhcp;error pool6 refused acquire: bad preferred prefix! (1)
ℹ️ 2025-11-20 17:36:25 system;info;account user eworm logged in from 10.10.0.37 via ssh
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
1b53b52ac6 doc/daily-psk: update notifications
doc/daily-psk.d/notification.avif
----- >8 -----
[rsc] 📅️ daily PSK Guest-Wifi

This is the daily PSK on rsc:

SSID:   Guest-Wifi
PSK:    53cr3t5tr1ng
Date:   2025-11-24

A client device specific rule must not exist!

🔗https://www.eworm.de/cgi-bin/cqrlogo-wifi.cgi?scale=8&ssid=Guest-Wifi&pass=53cr3t5tr1ng
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
f77cc07338 doc/collect-wireless-mac: update notifications
doc/collect-wireless-mac.d/notification.avif
----- >8 -----
[rsc] 📱️ 02:00:C0:FF:EE:00 connected to Guest-Wifi

A device with unknown MAC address connected to Guest-Wifi on rsc.

Controller:     rsc
Interface:      wifi1-guest
SSID:           Guest-Wifi
MAC:            02:00:C0:FF:EE:00
Vendor:         locally administered
Hostname:       Wifi-Client
Address:        192.168.1.244
DNS name:       02-00-C0-FF-EE-00.dhcp-guest.rsc.eworm.de
                Wifi-Client.dhcp-guest.rsc.eworm.de
Date:           2025-11-23 15:30:27
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
094215aec7 doc/check-routeros-update: update notifications
doc/check-routeros-update.d/notification-01-found.avif
----- >8 -----
[rsc] ️ RouterOS update: 7.20.4

A new RouterOS version 7.20.4 is available for rsc.

Hostname:       rsc
Hardware:
    Board:      hAP ax^2
    Arch:       arm64
    Model:      C52iG-5HaxD2HaxD
    Serial:     HEG08Q4FT32
    License:    level 4
RouterOS:
    Channel:    stable
    Installed:  7.20.2
    Available:  7.20.4
RouterOS-Scripts:
    Commit:     main/3287/699be25b
    Version:    138

🔗https://mikrotik.com/download/changelogs/stable-release-tree
----- >8 -----

doc/check-routeros-update.d/notification-02-neighbor.avif
----- >8 -----
[rsc] ️ RouterOS update: 7.20.4

Seen a neighbor (MikroTik) running version 7.20.4 from stable, updating on rsc...

🔗https://mikrotik.com/download/changelogs/stable-release-tree
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
d60ee59e77 doc/check-perpetual-license: update notifications
doc/check-perpetual-license.d/notification-01-warn.avif
----- >8 -----
[rsc] ⚠️ License about to expire!

Your license failed to renew and is about to expire on 2025-09-13 12:12:23 on rsc...
----- >8 -----

doc/check-perpetual-license.d/notification-02-renew.avif
----- >8 -----
[rsc] ️ License renewed

Your license was successfully renewed on rsc. It is now valid until 2025-10-25 08:42:46.
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
3926d12070 doc/check-lte-firmware-upgrade: update notifications
doc/check-lte-firmware-upgrade.d/notification.avif
----- >8 -----
[rsc] ️ LTE firmware upgrade

A new firmware version 16121.1034.00.01.01.10 is available for LTE interface lte on rsc.

Model:          FG621-EA
Revision:       16121.1034.00.01.01.09
Firmware version:
    Installed:  16121.1034.00.01.01.09
    Available:  16121.1034.00.01.01.10
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
5dbd419d1a doc/check-health: update notifications
doc/check-health.d/notification-01-cpu-utilization-high.avif
----- >8 -----
[rsc] 🧮📈️ Health warning: CPU utilization

The average CPU utilization on rsc is at 79%!
----- >8 -----

doc/check-health.d/notification-02-cpu-utilization-ok.avif
----- >8 -----
[rsc] 🧮📉️ Health recovery: CPU utilization

The average CPU utilization on rsc decreased to 64%.
----- >8 -----

doc/check-health.d/notification-03-ram-utilization-high.avif
----- >8 -----
[rsc] 🗃️📈️ Health warning: RAM utilization

The RAM utilization on rsc is at 88%!

total:  64.0MiB
used:   56.7MiB
free:   7.25MiB
----- >8 -----

doc/check-health.d/notification-04-ram-utilization-ok.avif
----- >8 -----
[rsc] 🗃️📉️ Health recovery: RAM utilization

The RAM utilization on rsc decreased to 75%.
----- >8 -----

doc/check-health.d/notification-05-voltage.avif
----- >8 -----
[rsc] 📉️ Health warning: voltage

The voltage on rsc jumped more than 10%.

old value:  23.8V
new value:  16.2V
----- >8 -----

doc/check-health.d/notification-06-temperature-high.avif
----- >8 -----
[rsc] 🔥️ Health warning: cpu-temperature

The cpu-temperature on rsc is above threshold: 74°C
----- >8 -----

doc/check-health.d/notification-07-temperature-ok.avif
----- >8 -----
[rsc] ️ Health recovery: cpu-temperature

The cpu-temperature on rsc dropped below threshold: 64°C
----- >8 -----

doc/check-health.d/notification-08-state-fail.avif
----- >8 -----
[rsc] ️ Health warning: psu2-state

The device 'psu2-state' on rsc failed!
----- >8 -----

doc/check-health.d/notification-09-state-ok.avif
----- >8 -----
[rsc] ️ Health recovery: psu2-state

The device 'psu2-state' on rsc recovered!
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
ac6aefd34c doc/check-certificates: update notifications
doc/check-certificates.d/notification-01-warn.avif
----- >8 -----
[rsc] 🔏⚠️ Certificate warning: rsc.eworm.de

A certificate on rsc is about to expire.

Name:           rsc.eworm.de
CommonName:     rsc.eworm.de
SubjectAltNames:
                DNS:rsc.eworm.de
Private key:    available
Fingerprint:    f21bd7e64eef82b963938fecd07ab0210194129d7829ba08c2d212d063f3b07c
Issuer chain:   E7 -> ISRG Root X2
Validity:
    from:       2025-09-09 13:30:10
    to:         2025-12-07 13:30:09
Expires in:     1w 3d 11:37:06
----- >8 -----

doc/check-certificates.d/notification-02-renew.avif
----- >8 -----
[rsc] 🔏️ Certificate renewed: rsc.eworm.de

A certificate on rsc has been renewed.

Name:           rsc.eworm.de
CommonName:     rsc.eworm.de
SubjectAltNames:
                DNS:rsc.eworm.de
Private key:    available
Fingerprint:    f21bd7e64eef82b963938fecd07ab0210194129d7829ba08c2d212d063f3b07c
Issuer chain:   E7 -> ISRG Root X2
Validity:
    from:       2025-11-07 13:30:09
    to:         2026-02-05 13:30:08
Expires in:     11w 3d 02:25:23
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
518a4c329f doc/backup-upload: update notifications
doc/backup-upload.d/notification.avif
----- >8 -----
[rsc] 💾⬆️ Backup & Config upload

Backup and config export upload for rsc.

Hostname:       rsc
Hardware:
    Board:      hAP ax^2
    Arch:       arm64
    Model:      C52iG-5HaxD2HaxD
    Serial:     HEG08Q4FT32
    License:    level 4
RouterOS:
    Channel:    stable
    Installed:  7.20.4
RouterOS-Scripts:
    Commit:     main/3287/699be25b
    Version:    138

Backup file:
    name:       rsc-eworm-de.backup
    size:       372kiB
Export file:
    name:       rsc-eworm-de.rsc
    size:       377kiB
Config file:
    name:       rsc-eworm-de.conf
    size:       3.26kiB
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
9ef3ba5479 doc/backup-cloud: update notifications
doc/backup-cloud.d/notification.avif
----- >8 -----
[rsc] 💾☁️ Cloud backup

Uploaded backup for rsc to cloud.

Hostname:       rsc
Hardware:
    Board:      hAP ax^2
    Arch:       arm64
    Model:      C52iG-5HaxD2HaxD
    Serial:     HEG08Q4FT32
    License:    level 4
RouterOS:
    Channel:    stable
    Installed:  7.20.4
RouterOS-Scripts:
    Commit:     main/3287/699be25b
    Version:    138

Name:           cloud-20251124-092255
Size:           180kiB
Download key:   lteX51vlEnrV4OSXfUngu8d
----- >8 -----
2025-11-25 17:37:00 +01:00
Christian Hesse
84c49c0f7e README: update notifications
README.d/notification-news-and-changes.avif
----- >8 -----
[rsc] 📌️ News and configuration changes

The configuration version on thyone increased to 138, current configuration may need modification. Please review and update global-config-overlay, then re-run global-config.

Changes:
 📌️ Added support to send notifications via Gotify (gotify.net).
 📌️ RouterOS 7.19 is suffering an issue with certificate store. Fixing trust state for all certificates...
----- >8 -----
2025-11-25 17:28:26 +01:00
Christian Hesse
bc174d7f1f general/style: add a margin to notification when floating 2025-11-25 17:23:01 +01:00
Christian Hesse
678fc3307e general/style: clear floating on hr 2025-11-25 17:23:01 +01:00
Christian Hesse
1ac0147fce sms-forward: mark every message with an envelope 2025-11-25 17:23:01 +01:00
Christian Hesse
1f6c43d5ce check-certificates: show lock-with-ink-pen symbol in notification...
... also for warning, but of course keep the warning sign.
2025-11-25 17:23:01 +01:00
Christian Hesse
544e8094de contrib/notification: increase font size for heading 2025-11-25 17:23:01 +01:00
Christian Hesse
d4979146f9 contrib/notification: disable the border-radius for logo 2025-11-25 17:23:01 +01:00
Christian Hesse
ca487376d6 contrib/notification: use rsc.eworm.de for default link 2025-11-25 17:23:01 +01:00
Christian Hesse
ea9e843ae9 contrib/html: add a class for code...
... and make sure the notification generator does not suffer
strange styles.
2025-11-25 17:23:01 +01:00
Christian Hesse
94514a7c75 doc/check-routeros-update: update the forum link 2025-11-25 17:23:01 +01:00
Christian Hesse
699be25b64 general/clipboard: use textContent...
... and avoid having html entity encoded characters in clipboard.
2025-11-20 20:44:56 +01:00
Christian Hesse
79c98a4b3a Merge branch 'screenshots' into next 2025-11-20 15:36:23 +01:00
Christian Hesse
e49f68c1f2 doc/mod/notification-matrix: update screenshots, with terminal window 2025-11-20 15:33:53 +01:00
Christian Hesse
2f4e83990a doc/mod/scriptrunonce: update screenshot, with terminal window 2025-11-20 15:33:53 +01:00
Christian Hesse
77dc0565a9 doc/mod/inspectvar: update screenshot, with terminal window 2025-11-20 15:32:56 +01:00
Christian Hesse
564c7f6bbc doc/mod/ipcalc: update screenshots, with terminal window 2025-11-20 15:31:40 +01:00
Christian Hesse
6718b90780 doc/mod/notification-telegram: update screenshot, with terminal window 2025-11-20 15:31:40 +01:00
Christian Hesse
e6faf346c2 doc/accesslist-duplicates: update screenshot, with terminal window 2025-11-20 14:58:39 +01:00
Christian Hesse
295fa3144a README: update screenshots, with terminal window
Started xterm with:

    xterm -xrm 'XTerm.vt100.allowTitleOps: false' -T 'Terminal: rsc.eworm.de'
2025-11-20 14:07:21 +01:00
Christian Hesse
b65f3512d0 README: add scheduler with start-time=startup 2025-11-20 14:03:00 +01:00
Christian Hesse
8a904dadf4 contrib/notification: add the copyright notice in footer 2025-11-20 11:53:55 +01:00
Christian Hesse
fa64e8906b contrib/logo-color: add the copyright notice in footer 2025-11-20 11:53:27 +01:00
Christian Hesse
2feaaf36b2 README: highlight the long way for first time users with hint 2025-11-20 11:26:59 +01:00
Christian Hesse
30743c0e87 README: mention broken installation for initial commands 2025-11-20 11:26:59 +01:00
Christian Hesse
725eb834f4 README: link the long way in detail 2025-11-20 11:26:59 +01:00
Christian Hesse
b97a434a9c Makefile: also clean contrib 2025-11-20 11:26:59 +01:00
Christian Hesse
70675a9fee contrib/Makefile: add target clean 2025-11-20 11:26:59 +01:00
Christian Hesse
e0b12a9050 contrib/static-html: add badges 2025-11-20 11:26:59 +01:00
Christian Hesse
a64e9bed80 contrib/static-html: find static html files by comment 2025-11-20 11:26:59 +01:00
Christian Hesse
e10455fb18 contrib/static-html: split off from Makefile 2025-11-20 11:26:59 +01:00
Christian Hesse
ed9dee3c5f contrib/html: simplify handling of relative paths 2025-11-20 11:26:59 +01:00
Christian Hesse
4f778cb1c6 general/clipboard: add a visual feedback 2025-11-20 11:26:59 +01:00
Christian Hesse
a61fbfb75c general/style: add a "📋 Copy!" hint to code blocks 2025-11-20 11:26:59 +01:00
Christian Hesse
903a3f44a0 contrib/html: support click on code block to copy to clipboard 2025-11-20 11:26:59 +01:00
Christian Hesse
638258000b contrib/commitinfo: support updating the commit info 2025-11-20 11:26:59 +01:00
Christian Hesse
b285f2c5d2 global-functions: add and fix global scheduler automatically...
... and also adjust README and INITIAL-COMMANDS.
2025-11-20 11:26:59 +01:00
Christian Hesse
93eb218589 global-functions: $FetchUserAgentStr: add commit info in user agent string 2025-11-20 11:26:59 +01:00
Christian Hesse
45e2f7b0a8 Merge branch 'rsc-eworm-de' into next 2025-11-20 11:26:59 +01:00
Christian Hesse
b29f3535b6 Merge branch 'contrib-template' into next 2025-11-20 11:26:59 +01:00
Christian Hesse
fa9c4be576 doc/mod/scriptrunonce: get script from rsc.eworm.de 2025-11-20 11:26:59 +01:00
Christian Hesse
ce37544bae contrib/logo-color: drop width & height properties for images 2025-11-20 11:26:59 +01:00
Christian Hesse
aeca778284 contrib/template-wifi: split off from Makefile 2025-11-20 11:26:59 +01:00
Christian Hesse
af5f01a973 INITIAL-COMMANDS: install from rsc.eworm.de 2025-11-20 11:26:59 +01:00
Christian Hesse
0b7528db99 contrib/logo-color: place screenshots below each other...
... not side by side.
2025-11-20 11:26:59 +01:00
Christian Hesse
54612e333f contrib/template-local: split off from Makefile 2025-11-20 11:26:59 +01:00
Christian Hesse
05f0838119 README: install from rsc.eworm.de 2025-11-20 11:26:59 +01:00
Christian Hesse
c6451c87f1 general/style: make the blockquote darker 2025-11-20 11:26:59 +01:00
Christian Hesse
4935c81bd9 contrib/template-capsman: split off from Makefile 2025-11-20 11:26:59 +01:00
Christian Hesse
d12be8f1ac fw-addr-lists.d/allow: use rsc.eworm.de in the list 2025-11-20 11:26:59 +01:00
Christian Hesse
c4a060c3d4 Merge branch 'contrib-html-head-foot' into next 2025-11-20 11:26:59 +01:00
Christian Hesse
f3afee3e4b fw-addr-lists.d/{allow,block}: use short url rsc.eworm.de 2025-11-20 11:26:59 +01:00
Christian Hesse
82587ec589 contrib/html: add copyright notice in footer 2025-11-20 11:26:59 +01:00
Christian Hesse
edd51ca719 contrib/html: add a footer with date and version info 2025-11-20 11:23:45 +01:00
Christian Hesse
d1fa3facfd Makefile: clean up and add phony targets 2025-11-20 10:57:20 +01:00
Christian Hesse
b4e6cc5b59 contrib/notification: add a head with eworm, QR code and caption 2025-11-20 10:57:20 +01:00
Christian Hesse
9287996b74 Merge branch 'contrib-html' into next 2025-11-20 10:57:20 +01:00
Christian Hesse
75692abf47 contrib/logo-color: add a head with eworm, QR code and caption 2025-11-20 10:57:20 +01:00
Christian Hesse
7b45bb5b46 contrib/Makefile: hide the hint on broken site 2025-11-20 10:57:20 +01:00
Christian Hesse
165d7c60d4 contrib/html: add a head with eworm, QR code and caption 2025-11-20 10:57:20 +01:00
Christian Hesse
b16c2f5b90 contrib/notification: hint on possibly broken site 2025-11-20 10:57:20 +01:00
Christian Hesse
cbb0aba1b1 contrib/logo-color: hint on possibly broken site 2025-11-20 10:57:20 +01:00
Christian Hesse
1ce3160933 contrib/html: hide the hint on broken link 2025-11-20 10:57:20 +01:00
Christian Hesse
607a608502 doc/mod/notification-telegram: hint on possibly broken link 2025-11-20 10:57:20 +01:00
Christian Hesse
148d40e18d contrib: introduce Makefile...
... and update references in links.
2025-11-20 10:57:20 +01:00
Christian Hesse
036c6ef682 contrib/logo-color: use relative reference in link
... without extra path elements.

This may break, depending on site.
2025-11-20 10:57:20 +01:00
Christian Hesse
5986894749 doc/mod/notification-telegram: use relative reference in link
This may break, depending on site.
2025-11-20 10:57:20 +01:00
Christian Hesse
8d68f24095 contrib/notification: format the values italic 2025-11-20 10:57:20 +01:00
Christian Hesse
eb89f8359b contrib/notification: update date format 2025-11-20 10:57:20 +01:00
Christian Hesse
8faf4ab7cf contrib/{logo-color,notification}: add navigation structure 2025-11-20 10:57:20 +01:00
Christian Hesse
ceb6f2353e contrib/*: unify html code 2025-11-20 10:57:20 +01:00
Christian Hesse
719b662b76 contrib/html: drop ampersand, comma, dash, exclamation mark, ...
... parentesis & tick mark from id/anchor
2025-11-20 10:57:20 +01:00
Christian Hesse
cbb282746f README: add a sub-section for code hosting 2025-11-20 09:48:35 +01:00
Christian Hesse
2e0787afd1 contrib/html: properly handle anchors 2025-11-20 09:48:35 +01:00
Christian Hesse
a0399216fc contrib/html: link the logo with relative path 2025-11-20 09:48:35 +01:00
Christian Hesse
2d6fdc355e contrib/html: increase default line height 2025-11-20 09:48:35 +01:00
Christian Hesse
fae8dbd8ea contrib/html: add a margin on left and right...
... for windows in landscape (wider than high). Also make the
notification float right for landscape only.
2025-11-20 09:48:35 +01:00
Christian Hesse
a2d6671cf0 contrib/html: include stylesheet via link 2025-11-20 09:48:35 +01:00
Christian Hesse
d610bf3582 contrib/{logo-color,notification}: use a single style 2025-11-20 09:48:35 +01:00
Christian Hesse
97b4a41f23 contrib/html: add empty lines...
... for easier rebasing.
2025-11-20 09:48:35 +01:00
Christian Hesse
a2250a00e6 README: add the upstream url verbatim 2025-11-19 16:19:59 +01:00
Christian Hesse
c6cc8b9a51 README: move the QR code 2025-11-19 16:19:59 +01:00
Christian Hesse
5075701958 Merge branch 'builtin-trust-store' into next 2025-11-19 16:19:59 +01:00
Christian Hesse
8f6a38f299 mod/notification-email: remove schedule with find...
... as a race condition could occur and the scheduler is already gone.
2025-11-19 16:19:59 +01:00
Christian Hesse
cc5aea22b3 doc/mod/notification-matrix: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
d002d1c0c0 global-functions: $ScriptInstallUpdate: extra actions on 'not found' only 2025-11-19 16:19:59 +01:00
Christian Hesse
737a872a5f CERTIFICATES: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
298a43a871 global-functions: $ScriptInstallUpdate: either or...
... but not both.
2025-11-19 16:19:59 +01:00
Christian Hesse
335bfc0a88 update-tunnelbroker: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
20885c4620 global-functions: $ScriptInstallUpdate: give hint on ignore
Fixes: https://github.com/eworm-de/routeros-scripts/issues/112
2025-11-19 16:19:59 +01:00
Christian Hesse
5ccb0d07b1 telegram-chat: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
7d701483d3 contrib/checksums: output to stdout...
... and let the Makefile redirect.
2025-11-19 16:19:59 +01:00
Christian Hesse
7772fbb22d netwatch-dns: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
83b164d511 global-functions: $CertificateDownload: drop unused function 2025-11-19 16:19:59 +01:00
Christian Hesse
f0910a4472 mod/notification-telegram: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
090f25a82d check-certificates: add missing semicolon 2025-11-19 16:19:59 +01:00
Christian Hesse
8ff34a2408 mod/notification-ntfy: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
affb9b3baf doc/mode-button: create code block with indention 2025-11-19 16:19:59 +01:00
Christian Hesse
87787eefe3 fw-addr-lists: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
677b5b8069 doc/mod/ssh-keys-import: create code block with indention 2025-11-19 16:19:59 +01:00
Christian Hesse
876505c36d check-certificates: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
b5a0269667 global-functions: $ScriptInstallUpdate: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
f3e6e152bc global-functions: $GetMacVendor: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
8eb397f79f global-functions: $DownloadPackage: define certificate use 2025-11-19 16:19:59 +01:00
Christian Hesse
db0a5bf33c global-functions: $CertificateAvailable: support new builtin-trust-store...
... which was introduced with RouterOS 7.21beta7.
2025-11-19 16:19:59 +01:00
Christian Hesse
fbfeea3042 INITIAL-COMMANDS: support new builtin-trust-store...
... which was introduced with RouterOS 7.21beta7.
2025-11-19 16:19:59 +01:00
Christian Hesse
1a1399d302 README: support new builtin-trust-store...
... which was introduced with RouterOS 7.21beta7.
2025-11-19 16:19:59 +01:00
Christian Hesse
335266f247 README: update the screenshot for script update...
... to match commit 2c92c78b46.
2025-11-19 16:19:47 +01:00
Christian Hesse
d100cac9ed README: add a line break before command 2025-11-13 12:03:37 +01:00
Christian Hesse
c88953e44d README: fix typo
We had it there since 39d1027d697c09ec709a1b847a185ccff3b00540... 😜
2025-11-07 22:11:25 +01:00
Christian Hesse
20987221d9 mod/notification-email: ignore errors (for now...)
Errors are returned since RouterOS 7.21beta2.

We keep the current logic for now, as we want to support older
RouterOS versions. This is something to be reworked later...
2025-10-26 19:19:13 +01:00
Christian Hesse
ea4b5553c2 Merge branch 'netmask6' into next
This branch is a follow-up on 9ceed0926a
with clean solution. Read on for details...

The data type `ip6-prefix` used to hold what it was named for - an IPv6
prefix:

    [user@mikrotik] > :put 2001:db8::dead:beef/32
    2001:db8::/32

This changed with RouterOS 6.21beta2, which now allows that exact same
data type to hold something like "address with prefix length attached":

    [user@mikrotik] > :put 2001:db8::dead:beef/32
    2001:db8::dead:beef/32

My scripts (namely `fw-addr-lists`) relied on the old behaviour and broke.
The commit mentioned above was just a quick workaround, with rough edges,
and it could still fail.

Sadly RouterOS does not support bit shifting on IPv6 data types, so a
(completely) mathematical solution is out of scope.

This branch implements a new and better workaround, see the first commit
of branch (6ad6f9aa08) for details.

I opened a support ticket / feature request on this topic, let's see
what results it brings...

https://help.mikrotik.com/servicedesk/servicedesk/customer/portal/1/SUP-201881
2025-10-22 19:05:38 +02:00
Christian Hesse
b80b872e55 mod/ipcalc: support IPv6
Well, some of these values do not make a lot of sense for IPv6...
Something to be cleaned up later.
2025-10-19 19:55:12 +02:00
Christian Hesse
ea05b69f7c fw-addr-lists: use $NetMask6 2025-10-19 19:55:12 +02:00
Christian Hesse
d7a6eb1d00 global-functions: $NetMask6: implement simple caching
The calculation is quite complex for something that needs to be done
frequently, for example by `fw-addr-lists`. The number of possible
netmasks is limited, so let's cache the results that were calculated
already.
2025-10-19 19:52:42 +02:00
Christian Hesse
6ad6f9aa08 global-functions: introduce $NetMask6
RouterOS does not support bit shifting on IPv6 data types, so we have to
split the problem:

 * each 16 bit block is calculated separately, as number
 * the complete netmask is assembled in a loop, as string
 * the final string is casted to correct data type
2025-10-19 19:48:14 +02:00
Christian Hesse
c62f236251 Merge branch 'netmask4' into next 2025-10-19 19:26:51 +02:00
Christian Hesse
47309e5c03 fw-addr-lists: normalize IPv4 addresses 2025-10-16 15:43:43 +02:00
Christian Hesse
9fa11cb79a mod/ipcalc: use $NetMask4 2025-10-16 13:03:54 +02:00
Christian Hesse
def540c965 global-functions: introduce $NetMask4 2025-10-16 10:47:19 +02:00
Christian Hesse
025b492783 global-functions: remove trailing space 2025-10-16 10:34:09 +02:00
Christian Hesse
6630d35eea mod/notification-telegram: $FlushTelegramQueue: check for cert, again
Chances are that messages have been queued before system was fully up or
connected. Thus the certificate may be missing, and it should be checked
again for on flush.
2025-10-13 12:06:01 +02:00
Christian Hesse
c81618b571 log-forward: always use memo symbol...
... and add warning sign on top.
2025-10-09 09:22:39 +02:00
Christian Hesse
35b556f0b2 fw-addr-lists: calculate branch after post-processing...
... as branch will likely change, and we want to avoid duplicates. 😉
2025-10-08 18:43:06 +02:00
Christian Hesse
9ceed0926a fw-addr-lists: do not use IPv6 net addresses smaller /64
This should reduce the number of addresses in list by aggregating them,
and also fix addresses with host part set (like 2001:470:1:fb5::2a0/64,
which should be 2001:470:1:fb5::/64 really).

The latter caused new warnings with RouterOS 7.21beta2.
2025-10-08 18:43:06 +02:00
Christian Hesse
5ffa85f8bf mod/ssh-keys-import: handle new parameter
With RouterOS 7.21beta2 the user SSH keys "key-owner" field was
renamed to "info".

Either of both is displayed in red by syntax highlighting, but it
works anyway.
2025-10-08 18:42:26 +02:00
Christian Hesse
48d0f1f0b9 fw-addr-lists: check last character of line for JSON
This is not a proof, but a line also ending with a curly bracket
has higher probability of being valid JSON.

Better safe than sorry... We are suffering a CVE in RouterOS:
https://www.cve.org/CVERecord?id=CVE-2025-10948
2025-10-02 11:51:08 +02:00
Christian Hesse
a931cb61a0 packages-update: fix condition when checking for scheduler
This broke with commit 6b0c9ab17d2e7e3693cebf281e5300d1e4de3446...
2025-09-30 10:02:20 +02:00
Christian Hesse
14b51d96b0 generate valid HTML, including head & style 2025-09-25 10:25:20 +02:00
Miquel Bonastre
2c715096b9 mod/ssh-keys-import: $SSHKeysImportFile: fix file exists condition...
... which broke in commit 80aed200fd.
2025-09-25 10:24:07 +02:00
Christian Hesse
2773fef9d8 global-functions: $WaitForFile: try less expensive operation
Checking a specific file is less expensive operation than finding one,
especially when on hardware with huge storage and lots of files (like
RDS). We have to keep the find command in the latter loop, though.
2025-09-25 10:24:07 +02:00
Christian Hesse
6b0c9ab17d packages-update: exit early if scheduler exists 2025-09-15 13:18:30 +02:00
Christian Hesse
59dc7e6d0c Merge branch 'check-health' into next 2025-08-26 09:25:01 +02:00
Christian Hesse
22e6383e86 check-health.d/voltage: use script name for origin in notification 2025-08-25 11:11:07 +02:00
Christian Hesse
62ca30b5d3 check-health.d/temperature: use script name for origin in notification 2025-08-25 11:11:07 +02:00
Christian Hesse
907358cb85 check-health.d/state: use script name for origin in notification 2025-08-25 11:11:07 +02:00
Christian Hesse
2fed8f967b check-health: pass script name to plugin 2025-08-25 11:11:07 +02:00
Christian Hesse
386ea2419f check-health: fix variable name 2025-08-25 11:04:07 +02:00
Christian Hesse
fe080c0d3d global-functions: $CertificateAvailable: properly handle duplicate CN
There are CA certificates with identical CommonName out there... 🤪
Let's handle these.

    [admin@MikroTik] > /certificate/print proplist=common-name,skid where common-name="GlobalSign";
    Flags: T - TRUSTED
    Columns: COMMON-NAME, SKID
    #   COMMON-NAME  SKID
    0 T GlobalSign   8FF04B7FA82E4524AE4D50FA639A8BDEE2DD1BBC
    1 T GlobalSign   3DE629489BEA07CA21444A26DE6EDED283D09F59
    2 T GlobalSign   AE6C05A39313E2A2E7E2D71CD6C7F07FC86753A0
    3 T GlobalSign   54B07BAD45B8E2407FFB0A6EFBBE33C93CA384D5
2025-08-16 23:14:31 +02:00
Christian Hesse
a856d309df global-functions: $SymbolByUnicodeName: allow to add more symbols...
... for example from a module. Add a script `mod/symbols-extra` with
something like:

    :global SymbolsExtra;

    :set ($SymbolsExtra->"rocket") "\F0\9F\9A\80";
2025-07-28 16:47:27 +02:00
Christian Hesse
721e786f68 netwatch-notify: increase the address-list timeout even further 2025-07-21 10:52:22 +02:00
Christian Hesse
4c2c7e817a netwatch-notify: give the number of failures...
... to indicated this happened several times.
2025-07-21 10:47:19 +02:00
Christian Hesse
89175e511f accesslist-duplicates: print without paging 2025-07-07 18:38:21 +02:00
Christian Hesse
b068f86995 netwatch-dns: fix indention 2025-06-25 10:47:12 +02:00
Christian Hesse
d46574b4fe netwatch-dns: retry doh server...
... for more resilience on bad connectivity or saturated link.
2025-06-25 10:30:26 +02:00
122 changed files with 636 additions and 248 deletions

View file

@ -61,7 +61,7 @@ Import a certificate by CommonName
Running the function `$CertificateAvailable` with that name as parameter Running the function `$CertificateAvailable` with that name as parameter
makes sure the certificate is available in the device's store: makes sure the certificate is available in the device's store:
$CertificateAvailable "ISRG Root X2"; $CertificateAvailable "ISRG Root X2" "fetch";
If the certificate is actually available already nothing happens, and there If the certificate is actually available already nothing happens, and there
is no output. Otherwise the certificate is downloaded and imported. is no output. Otherwise the certificate is downloaded and imported.

View file

@ -17,12 +17,15 @@ Initial commands
Run the complete base installation: Run the complete base installation:
{ {
:local BaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; :local BaseUrl "https://rsc.eworm.de/main/";
:local CertCommonName "ISRG Root X2"; :local CertCommonName "ISRG Root X2";
:local CertFileName "ISRG-Root-X2.pem"; :local CertFileName "ISRG-Root-X2.pem";
:local CertFingerprint "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; :local CertFingerprint "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470";
:if (!(([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \ :local CertSettings [ /certificate/settings/get ];
:if (!((($CertSettings->"builtin-trust-anchors") = "trusted" || \
($CertSettings->"builtin-trust-store") ~ "fetch" || \
($CertSettings->"builtin-trust-store") = "all") && \
[[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CertCommonName . "\" ] ]") ]] > 0)) do={ [[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CertCommonName . "\" ] ]") ]] > 0)) do={
:put "Importing certificate..."; :put "Importing certificate...";
/tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value; /tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value;
@ -38,13 +41,10 @@ Run the complete base installation:
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={
:put "Installing $Script..."; :put "Installing $Script...";
/system/script/remove [ find where name=$Script ]; /system/script/remove [ find where name=$Script ];
/system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ($BaseUrl . $Script . ".rsc") output=user as-value]->"data"); /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ($BaseUrl . $Script . ".rsc") output=user as-value ]->"data");
}; };
:put "Loading configuration and functions..."; :put "Loading configuration and functions...";
/system/script { run global-config; run global-functions; }; /system/script { run global-config; run global-functions; };
:put "Scheduling to load configuration and functions...";
/system/scheduler/remove [ find where name="global-scripts" ];
/system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }";
:if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] > 0) do={ :if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] > 0) do={
:put "Renaming certificate by its common-name..."; :put "Renaming certificate by its common-name...";
:global CertificateNameByCN; :global CertificateNameByCN;

View file

@ -2,38 +2,45 @@
# template scripts -> final scripts # template scripts -> final scripts
# markdown files -> html files # markdown files -> html files
CAPSMAN = $(wildcard *.capsman.rsc) ALL_RSC := $(wildcard *.rsc */*.rsc)
LOCAL = $(wildcard *.local.rsc) GEN_RSC := $(wildcard *.capsman.rsc *.local.rsc *.wifi.rsc)
WIFI = $(wildcard *.wifi.rsc)
MARKDOWN = $(wildcard *.md doc/*.md doc/mod/*.md) MARKDOWN := $(wildcard *.md doc/*.md doc/mod/*.md)
HTML = $(MARKDOWN:.md=.html) HTML := $(MARKDOWN:.md=.html)
all: $(CAPSMAN) $(LOCAL) $(WIFI) $(HTML) checksums.json DATE ?= $(shell date --rfc-email)
VERSION ?= $(shell git symbolic-ref --short HEAD 2>/dev/null)/$(shell git rev-list --count HEAD 2>/dev/null)/$(shell git rev-parse --short=8 HEAD 2>/dev/null)
export DATE VERSION
%.html: %.md Makefile .PHONY: all checksums commitinfo docs rsc clean
markdown $< | sed 's/href="\([-_\./[:alnum:]]*\)\.md"/href="\1.html"/g' > $@
%.capsman.rsc: %.template.rsc Makefile all: checksums docs rsc
sed -e '/\/interface\/wifi\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.capsman|' \
-e '/^# NOT \/caps-man\/ #$$/,/^# NOT \/caps-man\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@
%.local.rsc: %.template.rsc Makefile checksums: checksums.json
sed -e '/\/caps-man\//d' -e '/\/interface\/wifi\//d' -e 's|%TEMPL%|.local|' \
-e '/^# NOT \/interface\/wireless\/ #$$/,/^# NOT \/interface\/wireless\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@
%.wifi.rsc: %.template.rsc Makefile checksums.json: contrib/checksums.sh $(ALL_RSC)
sed -e '/\/caps-man\//d' -e '/\/interface\/wireless\//d' -e 's|%TEMPL%|.wifi|' \ contrib/checksums.sh > $@
-e '/^# NOT \/interface\/wifi\/ #$$/,/^# NOT \/interface\/wifi\/ #$$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< $< > $@
checksums.json: contrib/checksums.sh *.rsc */*.rsc commitinfo: global-functions.rsc
contrib/checksums.sh contrib/commitinfo.sh $< > $<~
mv $<~ $<
docs: $(HTML)
%.html: %.md general/style.css contrib/html.sh contrib/html.sh.d/head.html contrib/html.sh.d/foot.html
contrib/html.sh $< > $@
rsc: $(GEN_RSC)
%.capsman.rsc: %.template.rsc contrib/template-capsman.sh
contrib/template-capsman.sh $< > $@
%.local.rsc: %.template.rsc contrib/template-local.sh
contrib/template-local.sh $< > $@
%.wifi.rsc: %.template.rsc contrib/template-wifi.sh
contrib/template-wifi.sh $< > $@
clean: clean:
rm -f $(HTML) checksums.json rm -f $(HTML) checksums.json
make -C contrib/ clean

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Before After
Before After

View file

@ -55,15 +55,18 @@ Initial setup
### Get me ready! ### Get me ready!
If you know how things work just copy and paste the If you know how things work just copy and paste the
[initial commands](INITIAL-COMMANDS.md). Remember to edit and rerun [initial commands](INITIAL-COMMANDS.md). These also support fixing an
existing but broken installation. Remember to edit and rerun
`global-config-overlay`! `global-config-overlay`!
First time users should take the long way below.
> 💡️ **Hint**: First time users should take
> [the long way in detail](#the-long-way-in-detail) below.
### Live presentation ### Live presentation
Want to see it in action? I've had a presentation [Repository based Want to see it in action? I've had a presentation [Repository based
RouterOS script distribution ↗️](https://www.youtube.com/watch?v=B9neG3oAhcY) RouterOS script distribution ↗️](https://www.youtube.com/watch?v=B9neG3oAhcY)
including demonstation recorded live at [MUM Europe including demonstration recorded live at [MUM Europe
2019 ↗️](https://mum.mikrotik.com/2019/EU/) in Vienna. 2019 ↗️](https://mum.mikrotik.com/2019/EU/) in Vienna.
> ⚠️ **Warning**: Some details changed. So see the presentation, then follow > ⚠️ **Warning**: Some details changed. So see the presentation, then follow
@ -79,12 +82,15 @@ download the certificates.
> to [installation of scripts](#installation-of-scripts) if you set the > to [installation of scripts](#installation-of-scripts) if you set the
> trust for these builtin trust anchors: > trust for these builtin trust anchors:
> `/certificate/settings/set builtin-trust-anchors=trusted;` > `/certificate/settings/set builtin-trust-anchors=trusted;`
> With RouterOS 7.21 the functionality was changed. Set this at minimum,
> but make sure not to drop other targets:
> `/certificate/settings/set builtin-trust-store=fetch;`
If you intend to download the scripts from a If you intend to download the scripts from a
different location (for example from github.com) install the corresponding different location (for example from github.com) install the corresponding
certificate chain. certificate chain.
/tool/fetch "https://git.eworm.de/cgit/routeros-scripts/plain/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem"; /tool/fetch "https://rsc.eworm.de/main/certs/ISRG-Root-X2.pem" dst-path="isrg-root-x2.pem";
![screenshot: download certs](README.d/01-download-certs.avif) ![screenshot: download certs](README.d/01-download-certs.avif)
@ -122,16 +128,16 @@ date and time is set correctly!
Now let's download the main scripts and add them in configuration on the fly. Now let's download the main scripts and add them in configuration on the fly.
:foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://git.eworm.de/cgit/routeros-scripts/plain/" . $Script . ".rsc") output=user as-value]->"data"); }; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ /system/script/add name=$Script owner=$Script source=([ /tool/fetch check-certificate=yes-without-crl ("https://rsc.eworm.de/main/" . $Script . ".rsc") output=user as-value ]->"data"); };
![screenshot: import scripts](README.d/04-import-scripts.avif) ![screenshot: import scripts](README.d/04-import-scripts.avif)
And finally load configuration and functions and add the scheduler. And finally run configuration and functions. This will also add the
scheduler for loading at system startup automatically.
/system/script { run global-config; run global-functions; }; /system/script { run global-config; run global-functions; };
/system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }";
![screenshot: run and schedule scripts](README.d/05-run-and-schedule-scripts.avif) ![screenshot: run scripts](README.d/05-run-scripts.avif)
> 💡️ **Hint**: You see complaints regarding syntax errors? Most likely the > 💡️ **Hint**: You see complaints regarding syntax errors? Most likely the
> RouterOS on your device is too old. Check for updates! > RouterOS on your device is too old. Check for updates!
@ -219,7 +225,7 @@ cleanup add a scheduler entry.
$ScriptInstallUpdate dhcp-to-dns,lease-script; $ScriptInstallUpdate dhcp-to-dns,lease-script;
/ip/dhcp-server/set lease-script=lease-script [ find ]; /ip/dhcp-server/set lease-script=lease-script [ find ];
/system/scheduler/add name="dhcp-to-dns" interval=5m on-event="/system/script/run dhcp-to-dns;"; /system/scheduler/add name="dhcp-to-dns" interval=5m start-time=startup on-event="/system/script/run dhcp-to-dns;";
![screenshot: setup lease script](README.d/12-setup-lease-script.avif) ![screenshot: setup lease script](README.d/12-setup-lease-script.avif)
@ -401,14 +407,15 @@ immediately remove the link in question.
Upstream Upstream
-------- --------
[![upstream](README.d/upstream.png)](https://rsc.eworm.de/) [rsc.eworm.de](https://rsc.eworm.de/)
URL: [![upstream](general/qr-code.png)](https://rsc.eworm.de/)
[GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts)
Mirror: ### Code hosting
[eworm.de](https://git.eworm.de/cgit/routeros-scripts/about/)
[GitLab.com](https://gitlab.com/eworm-de/routeros-scripts#routeros-scripts) * [git.eworm.de](https://git.eworm.de/cgit/routeros-scripts/about/)
* [GitHub.com](https://github.com/eworm-de/routeros-scripts#routeros-scripts)
* [GitLab.com](https://gitlab.com/eworm-de/routeros-scripts#routeros-scripts)
--- ---
[⬆️ Go back to top](#top) [⬆️ Go back to top](#top)

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /caps-man/access-list/get $AccList mac-address ]; :local Mac [ /caps-man/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={ :if ($Seen->$Mac = 1) do={
/caps-man/access-list/print where mac-address=$Mac; /caps-man/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={ :if ([ :typeof $Remove ] = "num") do={

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={ :if ($Seen->$Mac = 1) do={
/interface/wireless/access-list/print where mac-address=$Mac; /interface/wireless/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={ :if ([ :typeof $Remove ] = "num") do={

View file

@ -27,9 +27,9 @@
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; :local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ]; :local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={ :if ($Seen->$Mac = 1) do={
/caps-man/access-list/print where mac-address=$Mac; /caps-man/access-list/print without-paging where mac-address=$Mac;
/interface/wifi/access-list/print where mac-address=$Mac; /interface/wifi/access-list/print without-paging where mac-address=$Mac;
/interface/wireless/access-list/print where mac-address=$Mac; /interface/wireless/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={ :if ([ :typeof $Remove ] = "num") do={

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={ :foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ]; :local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={ :if ($Seen->$Mac = 1) do={
/interface/wifi/access-list/print where mac-address=$Mac; /interface/wifi/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ]; :local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={ :if ([ :typeof $Remove ] = "num") do={

View file

@ -21,7 +21,7 @@
:global CertWarnTime; :global CertWarnTime;
:global Identity; :global Identity;
:global CertificateAvailable :global CertificateAvailable;
:global EscapeForRegEx; :global EscapeForRegEx;
:global IfThenElse; :global IfThenElse;
:global LogPrint; :global LogPrint;
@ -189,7 +189,7 @@
fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ]; fingerprint!=[ :tostr ($CertVal->"fingerprint") ] expires-after>$CertRenewTime ];
:local CertNewVal [ /certificate/get $CertNew ]; :local CertNewVal [ /certificate/get $CertNew ];
:if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") ] = false) do={ :if ([ $CertificateAvailable ([ $ParseKeyValueStore ($CertNewVal->"issuer") ]->"CN") "fetch" ] = false) do={
$LogPrint warning $ScriptName ("The certificate chain is not available!"); $LogPrint warning $ScriptName ("The certificate chain is not available!");
} }
@ -231,7 +231,7 @@
:local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ]; :local State [ $IfThenElse (($CertVal->"expired") = true) "expired" "is about to expire" ];
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \ subject=([ $SymbolForNotification "lock-with-ink-pen,warning-sign" ] . "Certificate warning: " . ($CertVal->"name")); \
message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) }); message=("A certificate on " . $Identity . " " . $State . ".\n\n" . [ $FormatInfo $Cert ]) });
$LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \ $LogPrint info $ScriptName ("The certificate '" . ($CertVal->"name") . "' " . $State . \
", it is invalid after " . ($CertVal->"invalid-after") . "."); ", it is invalid after " . ($CertVal->"invalid-after") . ".");

View file

@ -12,6 +12,7 @@
:set ($CheckHealthPlugins->[ :jobname ]) do={ :set ($CheckHealthPlugins->[ :jobname ]) do={
:local FuncName [ :tostr $0 ]; :local FuncName [ :tostr $0 ];
:local ScriptName [ :tostr $1 ];
:global CheckHealthLast; :global CheckHealthLast;
:global Identity; :global Identity;
@ -32,13 +33,13 @@
:if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={ :if ([ :typeof ($CheckHealthLast->$Name) ] != "nothing") do={
:if ($CheckHealthLast->$Name = "ok" && \ :if ($CheckHealthLast->$Name = "ok" && \
$Value != "ok") do={ $Value != "ok") do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \ subject=([ $SymbolForNotification "cross-mark" ] . "Health warning: " . $Name); \
message=("The device '" . $Name . "' on " . $Identity . " failed!") }); message=("The device '" . $Name . "' on " . $Identity . " failed!") });
} }
:if ($CheckHealthLast->$Name != "ok" && \ :if ($CheckHealthLast->$Name != "ok" && \
$Value = "ok") do={ $Value = "ok") do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
message=("The device '" . $Name . "' on " . $Identity . " recovered!") }); message=("The device '" . $Name . "' on " . $Identity . " recovered!") });
} }

View file

@ -12,6 +12,7 @@
:set ($CheckHealthPlugins->[ :jobname ]) do={ :set ($CheckHealthPlugins->[ :jobname ]) do={
:local FuncName [ :tostr $0 ]; :local FuncName [ :tostr $0 ];
:local ScriptName [ :tostr $1 ];
:global CheckHealthLast; :global CheckHealthLast;
:global CheckHealthTemperature; :global CheckHealthTemperature;
@ -54,7 +55,7 @@
} }
:if ($Value > $CheckHealthTemperature->$Name && \ :if ($Value > $CheckHealthTemperature->$Name && \
$CheckHealthTemperatureNotified->$Name != true) do={ $CheckHealthTemperatureNotified->$Name != true) do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \ subject=([ $SymbolForNotification "fire" ] . "Health warning: " . $Name); \
message=("The " . $Name . " on " . $Identity . " is above threshold: " . \ message=("The " . $Name . " on " . $Identity . " is above threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0" . "C") });
@ -62,7 +63,7 @@
} }
:if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \ :if ($Value <= ($CheckHealthTemperature->$Name - $CheckHealthTemperatureDeviation) && \
$CheckHealthTemperatureNotified->$Name = true) do={ $CheckHealthTemperatureNotified->$Name = true) do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \ subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "Health recovery: " . $Name); \
message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \ message=("The " . $Name . " on " . $Identity . " dropped below threshold: " . \
$Value . "\C2\B0" . "C") }); $Value . "\C2\B0" . "C") });

View file

@ -12,6 +12,7 @@
:set ($CheckHealthPlugins->[ :jobname ]) do={ :set ($CheckHealthPlugins->[ :jobname ]) do={
:local FuncName [ :tostr $0 ]; :local FuncName [ :tostr $0 ];
:local ScriptName [ :tostr $1 ];
:global CheckHealthLast; :global CheckHealthLast;
:global CheckHealthVoltageLow; :global CheckHealthVoltageLow;
@ -39,7 +40,7 @@
:if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \ :if ($NumLast * (100 + $CheckHealthVoltagePercent) < $NumCurr * 100 || \
$NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={ $NumLast * 100 > $NumCurr * (100 + $CheckHealthVoltagePercent)) do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \ subject=([ $SymbolForNotification ("high-voltage-sign,chart-" . [ $IfThenElse ($NumLast < \
$NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \ $NumCurr) "in" "de" ] . "creasing") ] . "Health warning: " . $Name); \
message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \ message=("The " . $Name . " on " . $Identity . " jumped more than " . $CheckHealthVoltagePercent . "%.\n\n" . \
@ -47,12 +48,12 @@
[ $FormatLine "new value" ($Value . " V") 12 ]) }); [ $FormatLine "new value" ($Value . " V") 12 ]) });
} else={ } else={
:if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={ :if ($NumCurr <= $CheckHealthVoltageLow && $NumLast > $CheckHealthVoltageLow) do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \ subject=([ $SymbolForNotification "high-voltage-sign,chart-decreasing" ] . "Health warning: Low " . $Name); \
message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") }); message=("The " . $Name . " on " . $Identity . " dropped to " . $Value . " V below hard limit.") });
} }
:if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={ :if ($NumCurr > $CheckHealthVoltageLow && $NumLast <= $CheckHealthVoltageLow) do={
$SendNotification2 ({ origin=$FuncName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \ subject=([ $SymbolForNotification "high-voltage-sign,chart-increasing" ] . "Health recovery: Low " . $Name); \
message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") }); message=("The " . $Name . " on " . $Identity . " recovered to " . $Value . " V above hard limit.") });
} }

View file

@ -92,16 +92,16 @@
:onerror Err { :onerror Err {
/system/script/run $Plugin; /system/script/run $Plugin;
} do={ } do={
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed to run: " . $Err); $LogPrint error $ScriptName ("Plugin '" . $PluginVal->"name" . "' failed to run: " . $Err);
} }
} else={ } else={
$LogPrint error $ScriptName ("Plugin '" . $ScriptVal->"name" . "' failed syntax validation, skipping."); $LogPrint error $ScriptName ("Plugin '" . $PluginVal->"name" . "' failed syntax validation, skipping.");
} }
} }
:foreach PluginName,Discard in=$CheckHealthPlugins do={ :foreach PluginName,Discard in=$CheckHealthPlugins do={
($CheckHealthPlugins->$PluginName) \ ($CheckHealthPlugins->$PluginName) \
("\$CheckHealthPlugins->\"" . $PluginName . "\""); ("\$CheckHealthPlugins->\"" . $PluginName . "\"") $ScriptName;
} }
:set CheckHealthPlugins; :set CheckHealthPlugins;

View file

@ -42,7 +42,7 @@
$LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!"); $LogPrint warning $ScriptName ("Your license expired on " . ($License->"deadline-at") . "!");
:if ($SentCertificateNotification != "expired") do={ :if ($SentCertificateNotification != "expired") do={
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "warning-sign" ] . "License expired!"); \ subject=([ $SymbolForNotification "scroll,warning-sign" ] . "License expired!"); \
message=("Your license expired on " . ($License->"deadline-at") . \ message=("Your license expired on " . ($License->"deadline-at") . \
", can no longer update RouterOS on " . $Identity . "...") }); ", can no longer update RouterOS on " . $Identity . "...") });
:set SentCertificateNotification "expired"; :set SentCertificateNotification "expired";
@ -55,7 +55,7 @@
$LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!"); $LogPrint warning $ScriptName ("Your license will expire on " . ($License->"deadline-at") . "!");
:if ($SentCertificateNotification != "warning") do={ :if ($SentCertificateNotification != "warning") do={
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "warning-sign" ] . "License about to expire!"); \ subject=([ $SymbolForNotification "scroll,warning-sign" ] . "License about to expire!"); \
message=("Your license failed to renew and is about to expire on " . \ message=("Your license failed to renew and is about to expire on " . \
($License->"deadline-at") . " on " . $Identity . "...") }); ($License->"deadline-at") . " on " . $Identity . "...") });
:set SentCertificateNotification "warning"; :set SentCertificateNotification "warning";
@ -68,7 +68,7 @@
[ :totime ($License->"deadline-at") ] - 4w > [ :timestamp ]) do={ [ :totime ($License->"deadline-at") ] - 4w > [ :timestamp ]) do={
$LogPrint info $ScriptName ("Your license was successfully renewed."); $LogPrint info $ScriptName ("Your license was successfully renewed.");
$SendNotification2 ({ origin=$ScriptName; \ $SendNotification2 ({ origin=$ScriptName; \
subject=([ $SymbolForNotification "white-heavy-check-mark" ] . "License renewed"); \ subject=([ $SymbolForNotification "scroll,white-heavy-check-mark" ] . "License renewed"); \
message=("Your license was successfully renewed on " . $Identity . \ message=("Your license was successfully renewed on " . $Identity . \
". It is now valid until " . ($License->"deadline-at") . ".") }); ". It is now valid until " . ($License->"deadline-at") . ".") });
:set SentCertificateNotification; :set SentCertificateNotification;

17
contrib/Makefile Normal file
View file

@ -0,0 +1,17 @@
# Makefile
HTML := $(shell grep -xl '<!-- static html //-->' *.html)
.PHONY: all docs clean
all: docs
badges.html: badges.md
markdown $< > $@
docs: static-html.sh $(HTML) badges.html
./static-html.sh $(HTML)
clean:
rm -f badges.html
git checkout HEAD -- $(HTML)

6
contrib/badges.md Normal file
View file

@ -0,0 +1,6 @@
[![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network)
[![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers)
[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/)
[![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts)
[![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)

View file

@ -6,4 +6,4 @@ set -e
md5sum $(find -name '*.rsc' | sort) | \ md5sum $(find -name '*.rsc' | sort) | \
sed -e "s| \./||" -e 's|.rsc$||' | \ sed -e "s| \./||" -e 's|.rsc$||' | \
jq --raw-input --null-input '[ inputs | split (" ") | { (.[1]): (.[0]) }] | add' > 'checksums.json' jq --raw-input --null-input '[ inputs | split (" ") | { (.[1]): (.[0]) }] | add'

6
contrib/commitinfo.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
sed \
-e "/^:global CommitId/c :global CommitId \"${COMMITID:-unknown}\";" \
-e "/^:global CommitInfo/c :global CommitInfo \"${COMMITINFO:-unknown}\";" \
< "${1}"

23
contrib/html.sh Executable file
View file

@ -0,0 +1,23 @@
#!/bin/sh
set -e
RELTO="$(dirname "${1}")"
sed \
-e "s|__TITLE__|$(head -n1 "${1}")|" \
-e "s|__GENERAL__|$(realpath --relative-to="${RELTO}" general/)|" \
-e "s|__ROOT__|$(realpath --relative-to="${RELTO}" ./)|" \
< "${0}.d/head.html"
markdown -f toc,idanchor "${1}" | sed \
-e 's/href="\([-_\./[:alnum:]]*\)\.md\(#[-[:alnum:]]*\)\?"/href="\1.html\2"/g' \
-e '/<h[1234] /s| id="\(.*\)">| id="\L\1">|' \
-e '/<h[1234] /s|-2[1789cd]-||g' -e '/<h[1234] /s|--26-amp-3b-||g' \
-e '/^<pre>/s|pre|pre class="code" onclick="CopyToClipboard(this)"|g' \
-e '/The above link may be broken on code hosting sites/s|blockquote|blockquote style="display: none;"|'
sed \
-e "s|__DATE__|${DATE:-$(date --rfc-email)}|" \
-e "s|__VERSION__|${VERSION:-unknown}|" \
< "${0}.d/foot.html"

View file

@ -0,0 +1,5 @@
<p class="foot">RouterOS Scripts documentation generated on <i>__DATE__</i> for <i>__VERSION__</i><br />
Copyright &copy; 2013-2025 Christian Hesse &lt;mail@eworm.de&gt;</p>
</body></html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html><html lang="en">
<head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>RouterOS Scripts :: __TITLE__</title>
<link rel="stylesheet" type="text/css" href="__GENERAL__/style.css">
<link rel="icon" type="image/png" href="__ROOT__/logo.png">
<script type="text/javascript" src="__GENERAL__/clipboard.js"></script>
</head><body>
<table><tr>
<td><img src="__GENERAL__/eworm-meadow.avif" alt="eworm on meadow" /></td>
<td><img src="__GENERAL__/qr-code.png" alt="QR code: rsc.eworm.de" /></td>
<td class="head"><span class="top">RouterOS Scripts</span><br />
<span class="bottom">a collection of scripts for MikroTik RouterOS</span></td>
</tr></table>
<hr />

View file

@ -1,5 +0,0 @@
body {
font-family: fira-sans, sans-serif;
font-size: 10pt;
background-color: transparent;
}

View file

@ -1,14 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html><html lang="en">
<html lang="en"> <!-- static html //-->
<head> <head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8"> <title>RouterOS Scripts :: Logo Color Changer</title>
<title>RouterOS-Scripts Logo Color Changer</title> <link rel="stylesheet" type="text/css" href="../general/style.css">
<link rel="stylesheet" type="text/css" href="logo-color.d/style.css"> <link rel="icon" type="image/png" href="../logo.png">
<script src="logo-color.d/script.js"></script> <script src="logo-color.d/script.js"></script>
</head> </head><body>
<body>
<h1>RouterOS-Scripts Logo Color Changer</h1> <table><tr>
<td><img src="../general/eworm-meadow.avif" alt="eworm on meadow" /></td>
<td><img src="../general/qr-code.png" alt="QR code: rsc.eworm.de" /></td>
<td class="head"><span class="top">RouterOS Scripts</span><br />
<span class="bottom">a collection of scripts for MikroTik RouterOS</span></td>
</tr></table>
<hr />
<h1>Logo Color Changer</h1>
<!-- badges here //-->
<p><a href="../README.md">⬅️ Go back to main README</a></p>
<blockquote style="/* display */"><p>💡️ <strong>Hint</strong>: This site or links
on it may be broken on code hosting sites. Use
<a href="https://rsc.eworm.de/main/contrib/logo-color.html">Logo Color Changer</a>
instead.</p></blockquote>
<p>You want the logo for your own notifications? But you joined the <p>You want the logo for your own notifications? But you joined the
<a href="https://t.me/routeros_scripts">Telegram Group</a> and want <a href="https://t.me/routeros_scripts">Telegram Group</a> and want
@ -24,17 +40,23 @@ something that differentiates? Color it!</p>
<p>Then right-click, click "<i>Take Screenshot</i>" and finally select the <p>Then right-click, click "<i>Take Screenshot</i>" and finally select the
logo and download it.</p> logo and download it.</p>
<p><img src="logo-color.d/browser-01.avif" width=533 height=482 alt="Screenshot Browser 01"> <p><img src="logo-color.d/browser-01.avif" alt="Screenshot Browser 01"></p>
<img src="logo-color.d/browser-02.avif" width=533 height=482 alt="Screenshot Browser 02"> <p><img src="logo-color.d/browser-02.avif" alt="Screenshot Browser 02"></p>
<img src="logo-color.d/browser-03.avif" width=533 height=482 alt="Screenshot Browser 03"></p> <p><img src="logo-color.d/browser-03.avif" alt="Screenshot Browser 03"></p>
<p>(This example is with <p>(This example is with
<a href="https://www.mozilla.org/de/firefox/new/">Firefox</a>. The workflow <a href="https://www.mozilla.org/de/firefox/new/">Firefox</a>. The workflow
for other browsers may differ.)</p> for other browsers may differ.)</p>
<p>See how to <p>See how to
<a href="../../about/doc/mod/notification-telegram.md#set-a-profile-photo">Set <a href="../doc/mod/notification-telegram.md#set-a-profile-photo">Set
a profile photo</a> for your Telegram bot.</p> a profile photo</a> for your Telegram bot.</p>
</body> <hr />
</html>
<p><a href="../README.md">⬅️ Go back to main README</a><br/>
<a href="#top">⬆️ Go back to top</a></p>
<p class="foot">Copyright &copy; 2013-2025 Christian Hesse &lt;mail@eworm.de&gt;</p>
</body></html>

View file

@ -1,36 +0,0 @@
body {
font-family: fira-sans, sans-serif;
font-size: 10pt;
background-color: transparent;
}
div.notification {
position: relative;
float: right;
width: 600px;
border: 3px outset #6c5d53;
/* border-radius: 5px; */
padding: 10px;
background-color: #e6e6e6;
}
div.content {
padding-left: 60px;
}
img.logo {
float: left;
border-radius: 50%;
}
p.heading {
margin: 0px;
font-weight: bold;
text-decoration: underline;
}
p.hint {
display: none;
}
pre {
font-family: fira-mono, monospace;
white-space: pre-wrap;
}
span.link {
color: #863600;
}

View file

@ -1,35 +1,57 @@
<!DOCTYPE html> <!DOCTYPE html><html lang="en">
<html lang="en"> <!-- static html //-->
<head> <head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8"> <title>RouterOS Scripts :: Notification Generator</title>
<title>RouterOS-Scripts Notification Generator</title> <link rel="stylesheet" type="text/css" href="../general/style.css">
<link rel="stylesheet" type="text/css" href="notification.d/style.css"> <link rel="icon" type="image/png" href="../logo.png">
<script src="notification.d/script.js"></script> <script src="notification.d/script.js"></script>
</head> </head><body>
<body>
<h1>RouterOS-Scripts Notification Generator</h1> <table><tr>
<td><img src="../general/eworm-meadow.avif" alt="eworm on meadow" /></td>
<td><img src="../general/qr-code.png" alt="QR code: rsc.eworm.de" /></td>
<td class="head"><span class="top">RouterOS Scripts</span><br />
<span class="bottom">a collection of scripts for MikroTik RouterOS</span></td>
</tr></table>
<hr />
<h1>Notification Generator</h1>
<!-- badges here //-->
<p><a href="../README.md">⬅️ Go back to main README</a></p>
<blockquote style="/* display */"><p>💡️ <strong>Hint</strong>: This site or links
on it may be broken on code hosting sites. Use
<a href="https://rsc.eworm.de/main/contrib/notification.html">Notification Generator</a>
instead.</p></blockquote>
<div class="notification"> <div class="notification">
<img src="../logo.svg" alt="logo" class="logo" width=48 height=48> <img src="../logo.svg" alt="logo" class="logo" width=48 height=48>
<div class="content"> <div class="content">
<p id="heading" class="heading">[<span id="hostname">MikroTik</span>] <span id="subject"> Subject</span></p> <p id="heading" class="heading">[<span id="hostname">MikroTik</span>] <span id="subject"> Subject</span></p>
<pre id="message">Message</pre> <pre id="message">Message</pre>
<p id="link" class="hint">🔗 <span id="link-text" class="link">https://eworm.de/</span></p> <p id="link" class="hint">🔗 <span id="link-text" class="link">https://rsc.eworm.de/</span></p>
<p id="queued" class="hint">⏰ This message was queued since <span id="queued-since">oct/18/2022 18:30:48</span> and may be obsolete.</p> <p id="queued" class="hint">⏰ This message was queued since <i><span id="queued-since">2025-10-29 16:06:18</span></i> and may be obsolete.</p>
<p id="cut" class="hint">✂️ The message was too long and has been truncated, cut off <span id="cut-percent">13</span>%!</p> <p id="cut" class="hint">✂️ The message was too long and has been truncated, cut off <i><span id="cut-percent">13</span>%</i>!</p>
</div> </div>
</div> </div>
<p>Hostname: <input type="text" value="MikroTik" onchange="update(this, 'hostname')"></p> <p>Hostname: <input type="text" value="MikroTik" onchange="update(this, 'hostname')"></p>
<p>Subject: <input type="text" size=50 value=" Subject" onchange="update(this, 'subject')"></p> <p>Subject: <input type="text" size=50 value=" Subject" onchange="update(this, 'subject')"></p>
<p>Message: <textarea id="w3review" name="w3review" rows="4" cols="50" onchange="update(this, 'message')">Message</textarea></p> <p>Message: <textarea id="w3review" name="w3review" rows="4" cols="50" onchange="update(this, 'message')">Message</textarea></p>
<p><input type="checkbox" onclick="visible(this, 'link')"> Show link: <input type="text" value="https://eworm.de/" onchange="update(this, 'link-text')"></p> <p><input type="checkbox" onclick="visible(this, 'link')"> Show link: <input type="text" value="https://rsc.eworm.de/" onchange="update(this, 'link-text')"></p>
<p><input type="checkbox" onclick="visible(this, 'queued')"> Queued since <input type="text" value="oct/18/2022 18:30:48" onchange="update(this, 'queued-since')"></p> <p><input type="checkbox" onclick="visible(this, 'queued')"> Queued since <input type="text" value="2025-10-29 16:06:18" onchange="update(this, 'queued-since')"></p>
<p><input type="checkbox" onclick="visible(this, 'cut')"> Cut-off with <input type="number" min=1 max=99 value=13 onchange="update(this, 'cut-percent')"> percent</p> <p><input type="checkbox" onclick="visible(this, 'cut')"> Cut-off with <input type="number" min=1 max=99 value=13 onchange="update(this, 'cut-percent')"> percent</p>
<p>Then right-click, click "<i>Take Screenshot</i>" and finally select the <p>Then right-click, click "<i>Take Screenshot</i>" and finally select the
notification and download it.</p> notification and download it.</p>
</body> <hr />
</html>
<p><a href="../README.md">⬅️ Go back to main README</a><br/>
<a href="#top">⬆️ Go back to top</a></p>
<p class="foot">Copyright &copy; 2013-2025 Christian Hesse &lt;mail@eworm.de&gt;</p>
</body></html>

10
contrib/static-html.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
set -e
sed -i \
-e '/href=/s|\.md|\.html|' \
-e '/blockquote/s|/\* display \*/|display: none;|' \
-e '/<!-- badges here \/\/-->/r badges.html' \
-e '/<!-- badges here \/\/-->/d' \
"${@}"

11
contrib/template-capsman.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -e
sed \
-e '/\/interface\/wifi\//d' \
-e '/\/interface\/wireless\//d' \
-e 's|%TEMPL%|.capsman|' \
-e '/^# NOT \/caps-man\/ #$/,/^# NOT \/caps-man\/ #$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< "${1}"

11
contrib/template-local.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -e
sed \
-e '/\/caps-man\//d' \
-e '/\/interface\/wifi\//d' \
-e 's|%TEMPL%|.local|' \
-e '/^# NOT \/interface\/wireless\/ #$/,/^# NOT \/interface\/wireless\/ #$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< "${1}"

11
contrib/template-wifi.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/sh
set -e
sed \
-e '/\/caps-man\//d' \
-e '/\/interface\/wireless\//d' \
-e 's|%TEMPL%|.wifi|' \
-e '/^# NOT \/interface\/wifi\/ #$/,/^# NOT \/interface\/wifi\/ #$/d' \
-e '/^# !!/,/^# !!/c # !! Do not edit this file, it is generated from template!' \
< "${1}"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -19,9 +19,10 @@ Description
This script tries to download and renew certificates, then notifies about This script tries to download and renew certificates, then notifies about
certificates that are still about to expire. certificates that are still about to expire.
### Sample notification ### Sample notifications
![check-certificates notification](check-certificates.d/notification.avif) ![check-certificates notification warning](check-certificates.d/notification-01-warn.avif)
![check-certificates notification renew](check-certificates.d/notification-02-renew.avif)
Requirements and installation Requirements and installation
----------------------------- -----------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -20,9 +20,10 @@ On *Cloud Hosted Router* (*CHR*) the licensing is perpetual: Buy once, use
forever - but it needs regular renewal. This script checks licensing state forever - but it needs regular renewal. This script checks licensing state
and sends a notification to warn before expiration. and sends a notification to warn before expiration.
### Sample notification ### Sample notifications
![check-perpetual-license notification](check-perpetual-license.d/notification.avif) ![check-perpetual-license notification warn](check-perpetual-license.d/notification-01-warn.avif)
![check-perpetual-license notification renew](check-perpetual-license.d/notification-02-renew.avif)
Requirements and installation Requirements and installation
----------------------------- -----------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -31,13 +31,14 @@ automatically is supported.
> of view. At the same time it can be source of serve breakage. So test > of view. At the same time it can be source of serve breakage. So test
> versions in lab and read > versions in lab and read
> [changelog ↗️](https://mikrotik.com/download/changelogs/) and > [changelog ↗️](https://mikrotik.com/download/changelogs/) and
> [forum ↗️](https://forum.mikrotik.com/viewforum.php?f=21) before deploying > [forum ↗️](https://forum.mikrotik.com/c/announcements/5) before deploying
> to your production environment! Automatic updates should be handled > to your production environment! Automatic updates should be handled
> with care! > with care!
### Sample notification ### Sample notifications
![check-routeros-update notification](check-routeros-update.d/notification.avif) ![check-routeros-update notification found](check-routeros-update.d/notification-01-found.avif)
![check-routeros-update notification neighbor](check-routeros-update.d/notification-02-neighbor.avif)
Requirements and installation Requirements and installation
----------------------------- -----------------------------
@ -87,6 +88,8 @@ Be notified when run from scheduler or run it manually:
If an update is found you can install it right away. If an update is found you can install it right away.
![Terminal](check-routeros-update.d/terminal.avif)
Installing script [packages-update](packages-update.md) gives extra options. Installing script [packages-update](packages-update.md) gives extra options.
Tips & Tricks Tips & Tricks

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

View file

@ -35,9 +35,10 @@ The script works around the limitations, for example it does:
It is intended to be run periodically from scheduler, then collects new It is intended to be run periodically from scheduler, then collects new
log messages and forwards them via notification. log messages and forwards them via notification.
### Sample notification ### Sample notifications
![log-forward notification](log-forward.d/notification.avif) ![log-forward notification info](log-forward.d/notification-01-info.avif)
![log-forward notification warn](log-forward.d/notification-02-warn.avif)
Requirements and installation Requirements and installation
----------------------------- -----------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -33,7 +33,7 @@ Call the function `$InspectVar` with a variable as parameter:
$InspectVar $ModeButton; $InspectVar $ModeButton;
![InspectVar](inspectvar.d/inspectvar.avif) ![InspectVar](inspectvar.d/01-inspectvar.avif)
--- ---
[⬅️ Go back to main README](../../README.md) [⬅️ Go back to main README](../../README.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -43,7 +43,7 @@ It expects an IP address in CIDR notation as argument.
$IPCalc 192.168.88.1/24; $IPCalc 192.168.88.1/24;
![IPCalc](ipcalc.d/ipcalc.avif) ![IPCalc](ipcalc.d/01-ipcalc.avif)
### IPCalcReturn ### IPCalcReturn
@ -53,7 +53,7 @@ the information in a named array.
:put ([ $IPCalcReturn 192.168.88.1/24 ]->"broadcast"); :put ([ $IPCalcReturn 192.168.88.1/24 ]->"broadcast");
![IPCalcReturn](ipcalc.d/ipcalcreturn.avif) ![IPCalcReturn](ipcalc.d/02-ipcalcreturn.avif)
--- ---
[⬅️ Go back to main README](../../README.md) [⬅️ Go back to main README](../../README.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -49,7 +49,7 @@ your server in device's certificate store.
The example below is for `matrix.org`, which uses a trust chain from *Google The example below is for `matrix.org`, which uses a trust chain from *Google
Trust Services*. Run this to import the required certificate: Trust Services*. Run this to import the required certificate:
$CertificateAvailable "GTS Root R4"; $CertificateAvailable "GTS Root R4" "fetch";
Replace the CA certificate name with what ever is needed for your server. Replace the CA certificate name with what ever is needed for your server.
You may want to find the You may want to find the

View file

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -36,7 +36,7 @@ Configuration
Open Telegram, then start a chat with [BotFather ↗️](https://t.me/BotFather) and Open Telegram, then start a chat with [BotFather ↗️](https://t.me/BotFather) and
create your own bot: create your own bot:
![create new bot](notification-telegram.d/newbot.avif) ![create new bot](notification-telegram.d/01-newbot.avif)
Set that token from *BotFather* (use your own!) to `TelegramTokenId`, for Set that token from *BotFather* (use your own!) to `TelegramTokenId`, for
now just temporarily: now just temporarily:
@ -49,7 +49,7 @@ then send your first message. Any text will do. On your device run
$GetTelegramChatId; $GetTelegramChatId;
![get chat id](notification-telegram.d/getchatid.avif) ![get chat id](notification-telegram.d/02-getchatid.avif)
Finally edit `global-config-overlay`, add `TelegramTokenId` with the token Finally edit `global-config-overlay`, add `TelegramTokenId` with the token
from *BotFather* and `TelegramChatId` with your retrieved chat id. Then from *BotFather* and `TelegramChatId` with your retrieved chat id. Then
@ -104,12 +104,15 @@ Tips & Tricks
You can use a profile photo for your bot to make it recognizable. Open the You can use a profile photo for your bot to make it recognizable. Open the
chat with [BotFather ↗️](https://t.me/BotFather) and set it there. chat with [BotFather ↗️](https://t.me/BotFather) and set it there.
![set profile photo](notification-telegram.d/setuserpic.avif) ![set profile photo](notification-telegram.d/03-setuserpic.avif)
Have a look at my Have a look at my [Logo Color Changer](../../contrib/logo-color.html)
[RouterOS-Scripts Logo Color Changer](https://git.eworm.de/cgit/routeros-scripts/plain/contrib/logo-color.html)
to create a colored version of this scripts' logo. to create a colored version of this scripts' logo.
> 💡️ **Hint**: The above link may be broken on code hosting sites.
> Use [Logo Color Changer](https://rsc.eworm.de/main/contrib/logo-color.html)
> instead.
See also See also
-------- --------

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -48,9 +48,9 @@ Usage and invocation
The function `$ScriptRunOnce` expects an URL (or name if The function `$ScriptRunOnce` expects an URL (or name if
`ScriptRunOnceBaseUrl` is given) pointing to a script as parameter. `ScriptRunOnceBaseUrl` is given) pointing to a script as parameter.
$ScriptRunOnce https://git.eworm.de/cgit/routeros-scripts/plain/doc/mod/scriptrunonce.d/hello-world.rsc; $ScriptRunOnce https://rsc.eworm.de/main/doc/mod/scriptrunonce.d/hello-world.rsc;
![ScriptRunOnce](scriptrunonce.d/scriptrunonce.avif) ![ScriptRunOnce](scriptrunonce.d/01-scriptrunonce.avif)
Giving multiple scripts is possible, separated by comma. Giving multiple scripts is possible, separated by comma.

View file

@ -38,8 +38,9 @@ import that key:
$SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin; $SSHKeysImport "ssh-rsa AAAAB3Nza...QYZk8= user" admin;
The third part of the key (`user` in this example) is inherited as The third part of the key (`user` in this example) is inherited as
`key-owner` in RouterOS. Also the `MD5` fingerprint is recorded, this helps `key-owner` in RouterOS (or `info` starting with RouterOS 7.21beta2). Also
to audit and verify the available keys. the `MD5` fingerprint is recorded, this helps to audit and verify the
available keys.
> **Info**: Use `ssh-keygen` to show a fingerprint of an existing public > **Info**: Use `ssh-keygen` to show a fingerprint of an existing public
> key file: `ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub` > key file: `ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub`
@ -50,12 +51,10 @@ The functions `$SSHKeysImportFile` can read an `authorized_keys`-style file
and import all the keys. The user given to the function can be overwritting and import all the keys. The user given to the function can be overwritting
from comments in the file. Create a file `keys.pub` with this content: from comments in the file. Create a file `keys.pub` with this content:
``` ssh-ed25519 AAAAC3Nza...3OcN8A user@client
ssh-ed25519 AAAAC3Nza...3OcN8A user@client ssh-rsa AAAAB3Nza...ozyts= worker@station
ssh-rsa AAAAB3Nza...ozyts= worker@station # user=example
# user=example ssh-rsa AAAAB3Nza...GXQVk= person@host
ssh-rsa AAAAB3Nza...GXQVk= person@host
```
Then import it with: Then import it with:

View file

@ -26,17 +26,15 @@ can configure the reset button to act the same, see
Copy this code to terminal to check: Copy this code to terminal to check:
``` :if ([ :len [ /system/routerboard/mode-button/print as-value ] ] > 0) do={
:if ([ :len [ /system/routerboard/mode-button/print as-value ] ] > 0) do={
:put "Mode button is supported."; :put "Mode button is supported.";
} else={ } else={
:if ([ :len [ /system/routerboard/reset-button/print as-value ] ] > 0) do={ :if ([ :len [ /system/routerboard/reset-button/print as-value ] ] > 0) do={
:put "Mode button is not supported, but reset button is."; :put "Mode button is not supported, but reset button is.";
} else={ } else={
:put "Neither mode button nor reset button is supported."; :put "Neither mode button nor reset button is supported.";
} }
} }
```
Requirements and installation Requirements and installation
----------------------------- -----------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more