mikrotik-wiki.ru
Главная
Загрузка...

Скрипты RouterOS — автоматизация задач на MikroTik

RouterOS 7.xSystem11 мин230 мар. 2026 г.
TelegramVK

RouterOS имеет встроенный скриптовый язык, позволяющий автоматизировать рутинные задачи: резервное копирование, мониторинг каналов, обновление списков блокировки, отправку уведомлений. В этом руководстве разберём синтаксис языка, планировщик задач, полезные готовые скрипты и лучшие практики.

Описание

Возможности скриптового языка RouterOS

Скриптовый язык RouterOS — это не полноценный язык программирования, а специализированный DSL (domain-specific language) для управления маршрутизатором. Он поддерживает:

ВозможностьОписание
ПеременныеЛокальные (:local) и глобальные (:global)
Условия:if ... do= ... else=
Циклы:foreach, :for, :while
МассивыПоддержка массивов и работа с ними
ФункцииГлобальные переменные-функции
Работа с файлами/file print, /tool fetch
HTTP-запросы/tool/fetch url=...
Email/tool/e-mail send
Работа со строкамиКонкатенация, поиск подстроки, срезы
Регулярные выраженияОператор ~ для поиска по regex
Выполнение CLI-командЛюбая команда RouterOS может быть частью скрипта

Где размещаются скрипты

Скрипты хранятся в /system/script. Каждый скрипт имеет имя, политику доступа и тело (source). Запустить скрипт можно вручную, по расписанию через /system/scheduler или по событию через /tool/netwatch.

Настройка

Основы синтаксиса

Переменные:

[admin@MikroTik] >
# Локальная переменная — видна только в текущем скрипте
:local myVar "Hello"
:local myNum 42
:local myBool true
:local myIP 192.168.1.1

# Глобальная переменная — доступна из любого скрипта
:global sharedVar "Shared value"

# Массив
:local myArray {"item1"; "item2"; "item3"}

# Получение значения из команды
:local hostname [/system/identity/get name]

Вывод и логирование:

[admin@MikroTik] >
# Вывод в терминал
:put "Current hostname: $hostname"

# Запись в системный лог
:log info "Script started"
:log warning "Disk space low"
:log error "Backup failed"

Условные конструкции:

routeros
:local cpuLoad [/system/resource/get cpu-load]

:if ($cpuLoad > 80) do={
    :log warning "High CPU load: $cpuLoad%"
} else={
    :log info "CPU load normal: $cpuLoad%"
}

Сравнение строк и проверка существования:

routeros
:local ifName "ether1"
:local ifComment [/interface/get $ifName comment]

:if ([:len $ifComment] = 0) do={
    :log info "Interface $ifName has no comment"
}

# Проверка наличия интерфейса
:if ([:len [/interface/find name=$ifName]] > 0) do={
    :log info "Interface $ifName exists"
}

Циклы:

[admin@MikroTik] >
# foreach — перебор элементов
:local interfaces [/interface/find type=ether]
:foreach iface in=$interfaces do={
    :local ifName [/interface/get $iface name]
    :local ifStatus [/interface/get $iface running]
    :log info "Interface $ifName running=$ifStatus"
}

# for — цикл со счётчиком
:for i from=1 to=5 do={
    :log info "Iteration $i"
}

# while — цикл с условием
:local count 0
:while ($count < 10) do={
    :set count ($count + 1)
}

Работа со строками:

routeros
:local str1 "Hello"
:local str2 "World"

# Конкатенация
:local result "$str1 $str2"

# Длина строки
:local len [:len $str1]

# Подстрока (pick)
:local sub [:pick $str1 0 3]
# Результат: "Hel"

# Поиск подстроки (find)
:local pos [:find $str1 "ll"]
# Результат: 2

# Преобразование типов
:local numStr [:tostr 42]
:local strNum [:tonum "42"]

Работа с массивами:

[admin@MikroTik] >
# Создание массива
:local servers {"8.8.8.8"; "1.1.1.1"; "9.9.9.9"}

# Добавление элемента
:set ($servers->[:len $servers]) "208.67.222.222"

# Перебор массива
:foreach server in=$servers do={
    :local pingResult [/ping $server count=1 as-value]
    :if ([:len $pingResult] > 0) do={
        :log info "Server $server is reachable"
    } else={
        :log warning "Server $server is unreachable"
    }
}

Планировщик задач (Scheduler)

Scheduler позволяет запускать скрипты по расписанию. Каждое задание имеет start-date, start-time и interval.

[admin@MikroTik] >
# Запуск скрипта каждый день в 03:00
/system/scheduler add name=daily-backup \
  start-time=03:00:00 \
  interval=1d \
  on-event="/system/script/run backup-to-email" \
  policy=read,write,test,policy \
  comment="Daily backup at 3 AM"

# Запуск каждые 5 минут
/system/scheduler add name=health-check \
  interval=5m \
  on-event="/system/script/run health-monitor" \
  policy=read,write,test

# Запуск один раз в определённое время
/system/scheduler add name=one-time-task \
  start-date=2025-01-15 \
  start-time=12:00:00 \
  on-event=":log info \"One-time task executed\"" \
  policy=read

Параметр policy определяет, какие права имеет скрипт при выполнении:

PolicyОписание
readЧтение конфигурации
writeИзменение конфигурации
testВыполнение ping, traceroute, bandwidth-test
policyУправление пользователями и политиками
rebootПерезагрузка маршрутизатора
sensitiveЧтение чувствительных данных (пароли, ключи)

Скрипт 1: Резервное копирование с отправкой на email

Настроим автоматическое ежедневное резервное копирование конфигурации с отправкой на почту.

Шаг 1: Настройка email-клиента:

[admin@MikroTik] >
/tool/e-mail set server=smtp.gmail.com \
  port=587 \
  tls=starttls \
  from=mikrotik-backup@company.com \
  user=mikrotik-backup@company.com \
  password="AppSpecificPassword"

Шаг 2: Создание скрипта:

[admin@MikroTik] >
/system/script add name=backup-to-email policy=read,write,test,sensitive source={
    :local hostname [/system/identity/get name]
    :local dateStr [/system/clock/get date]
    :local timeStr [/system/clock/get time]
    :local fileName "$hostname-$dateStr"

    # Создаём binary backup (полная копия, включая пароли)
    /system/backup/save name=$fileName encryption=aes-sha256 \
      password="BackupEncryptionKey2024"

    # Создаём текстовый export (читаемый, без паролей)
    /export file=$fileName

    :delay 5s

    # Отправляем binary backup
    /tool/e-mail send \
      to="admin@company.com" \
      subject="[$hostname] Backup $dateStr $timeStr" \
      body="Automated backup from $hostname\nDate: $dateStr $timeStr\nBinary backup (encrypted) attached." \
      file="$fileName.backup"

    :delay 3s

    # Отправляем текстовый export
    /tool/e-mail send \
      to="admin@company.com" \
      subject="[$hostname] Export $dateStr $timeStr" \
      body="Automated export from $hostname\nDate: $dateStr $timeStr\nText export attached." \
      file="$fileName.rsc"

    :delay 3s

    # Удаляем локальные файлы (опционально)
    /file/remove "$fileName.backup"
    /file/remove "$fileName.rsc"

    :log info "Backup sent to email successfully"
}

Шаг 3: Создание расписания:

[admin@MikroTik] >
/system/scheduler add name=daily-backup \
  start-time=03:00:00 interval=1d \
  on-event="/system/script/run backup-to-email" \
  policy=read,write,test,sensitive \
  comment="Daily backup to email"

Скрипт 2: Мониторинг каналов с переключением

Скрипт проверяет доступность основного канала и переключает default route на резервный при отказе.

[admin@MikroTik] >
/system/script add name=failover-monitor policy=read,write,test source={
    :local mainGateway "203.0.113.1"
    :local backupGateway "198.51.100.1"
    :local checkHost "8.8.8.8"
    :local failCount 0
    :local maxFails 3

    # Проверяем связь через основной канал
    :for i from=1 to=$maxFails do={
        :local pingResult [/ping $checkHost count=1 interface=ether1-wan \
          as-value]
        :if ([:len $pingResult] = 0) do={
            :set failCount ($failCount + 1)
        }
    }

    :if ($failCount >= $maxFails) do={
        # Основной канал недоступен — проверяем текущий маршрут
        :local currentRoute [/ip/route/find where dst-address="0.0.0.0/0" \
          gateway=$mainGateway]
        :if ([:len $currentRoute] > 0) do={
            /ip/route/disable $currentRoute
            :log warning "Main gateway $mainGateway DOWN - switched to backup"

            # Отправляем уведомление
            /tool/e-mail send \
              to="admin@company.com" \
              subject="[ALERT] Main gateway DOWN" \
              body="Main gateway $mainGateway is unreachable.\nSwitched to backup: $backupGateway"
        }
    } else={
        # Основной канал доступен — проверяем, не отключен ли маршрут
        :local disabledRoute [/ip/route/find where dst-address="0.0.0.0/0" \
          gateway=$mainGateway disabled=yes]
        :if ([:len $disabledRoute] > 0) do={
            /ip/route/enable $disabledRoute
            :log info "Main gateway $mainGateway UP - restored primary route"

            /tool/e-mail send \
              to="admin@company.com" \
              subject="[OK] Main gateway restored" \
              body="Main gateway $mainGateway is back online."
        }
    }
}

Запуск каждые 30 секунд:

[admin@MikroTik] >
/system/scheduler add name=failover-check \
  interval=30s \
  on-event="/system/script/run failover-monitor" \
  policy=read,write,test

Скрипт 3: Обновление DNS-blacklist через fetch

Скрипт загружает список рекламных доменов и добавляет их в Static DNS с перенаправлением на 0.0.0.0.

[admin@MikroTik] >
/system/script add name=dns-blacklist-update policy=read,write,test source={
    :local blacklistUrl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
    :local fileName "hosts.txt"
    :local addedCount 0
    :local maxEntries 5000

    # Загружаем файл
    :log info "DNS blacklist: downloading..."
    /tool/fetch url=$blacklistUrl dst-path=$fileName mode=https

    :delay 5s

    # Удаляем старые записи
    :local oldEntries [/ip/dns/static/find where comment="blacklist"]
    :foreach entry in=$oldEntries do={
        /ip/dns/static/remove $entry
    }
    :log info "DNS blacklist: removed old entries"

    # Читаем файл построчно
    :local fileContent [/file/get $fileName contents]
    :local lineStart 0
    :local fileLen [:len $fileContent]

    :while ($lineStart < $fileLen && $addedCount < $maxEntries) do={
        :local lineEnd [:find $fileContent "\n" $lineStart]
        :if ([:typeof $lineEnd] = "nil") do={
            :set lineEnd $fileLen
        }

        :local line [:pick $fileContent $lineStart $lineEnd]
        :set lineStart ($lineEnd + 1)

        # Пропускаем комментарии и пустые строки
        :if ([:len $line] > 0 && [:pick $line 0 1] != "#") do={
            # Формат: "0.0.0.0 domain.com"
            :local spacePos [:find $line " " 0]
            :if ([:typeof $spacePos] != "nil") do={
                :local domain [:pick $line ($spacePos + 1) [:len $line]]
                # Убираем возможный \r
                :if ([:pick $domain ([:len $domain] - 1) [:len $domain]] = "\r") do={
                    :set domain [:pick $domain 0 ([:len $domain] - 1)]
                }

                :if ([:len $domain] > 0 && $domain != "localhost") do={
                    :do {
                        /ip/dns/static/add name=$domain address=0.0.0.0 \
                          comment="blacklist" ttl=1d
                        :set addedCount ($addedCount + 1)
                    } on-error={
                        # Запись уже существует или невалидная — пропускаем
                    }
                }
            }
        }
    }

    # Удаляем скачанный файл
    /file/remove $fileName

    :log info "DNS blacklist: added $addedCount entries"
}

Запуск раз в сутки:

[admin@MikroTik] >
/system/scheduler add name=dns-blacklist \
  start-time=04:00:00 interval=1d \
  on-event="/system/script/run dns-blacklist-update" \
  policy=read,write,test \
  comment="Update DNS blacklist daily"

Скрипт 4: Netwatch — мониторинг хостов

Netwatch — встроенный инструмент для мониторинга доступности IP-адресов с выполнением скриптов при изменении состояния.

[admin@MikroTik] >
# Мониторинг доступности сервера
/tool/netwatch add host=10.0.0.100 \
  interval=30s \
  timeout=2s \
  type=icmp \
  up-script={
      :log info "Server 10.0.0.100 is UP"
  } \
  down-script={
      :log error "Server 10.0.0.100 is DOWN"
      /tool/e-mail send \
        to="admin@company.com" \
        subject="[ALERT] Server 10.0.0.100 DOWN" \
        body="Server 10.0.0.100 is not responding to ICMP."
  }

Netwatch поддерживает несколько типов проверки:

ТипОписание
icmpСтандартный ping
tcp-connПроверка TCP-подключения к указанному порту
http-getHTTP GET-запрос с проверкой кода ответа

Пример мониторинга веб-сервера:

[admin@MikroTik] >
/tool/netwatch add host=10.0.0.100 \
  type=http-get \
  http-code-min=200 \
  http-code-max=299 \
  port=443 \
  tls=yes \
  interval=1m \
  down-script={
      :log error "Web server HTTPS check failed"
  }

Скрипт 5: Автоматическая перезагрузка при утечке памяти

[admin@MikroTik] >
/system/script add name=memory-watchdog policy=read,write,reboot source={
    :local totalMem [/system/resource/get total-memory]
    :local freeMem [/system/resource/get free-memory]
    :local freePercent (($freeMem * 100) / $totalMem)
    :local hostname [/system/identity/get name]

    :if ($freePercent < 10) do={
        :log warning "Memory critically low: $freePercent% free"

        /tool/e-mail send \
          to="admin@company.com" \
          subject="[CRITICAL] $hostname - Low memory, rebooting" \
          body="Free memory: $freePercent%\nTotal: $totalMem\nFree: $freeMem\nInitiating reboot..."

        :delay 10s
        /system/reboot
    } else={
        :if ($freePercent < 25) do={
            :log warning "Memory low: $freePercent% free"
        }
    }
}

Скрипт 6: HTTP-запросы через /tool/fetch

/tool/fetch позволяет отправлять HTTP/HTTPS запросы — полезно для интеграции с внешними системами.

[admin@MikroTik] >
# GET-запрос
/tool/fetch url="https://api.example.com/status" mode=https \
  dst-path=api-response.txt

# POST-запрос (отправка данных)
/tool/fetch url="https://hooks.slack.com/services/XXX/YYY/ZZZ" \
  mode=https \
  http-method=post \
  http-header-field="Content-Type: application/json" \
  http-data="{\"text\": \"MikroTik alert: link down\"}" \
  output=none

Пример интеграции с Telegram:

[admin@MikroTik] >
/system/script add name=telegram-notify policy=read,write,test source={
    :local botToken "123456789:ABCdefGHI_jklMNOpqrSTUvwxyz"
    :local chatId "-1001234567890"
    :local hostname [/system/identity/get name]

    :global telegramMessage
    :if ([:len $telegramMessage] = 0) do={
        :set telegramMessage "No message specified"
    }

    :local url "https://api.telegram.org/bot$botToken/sendMessage"
    :local postData "chat_id=$chatId&text=$telegramMessage&parse_mode=HTML"

    :do {
        /tool/fetch url=$url mode=https http-method=post \
          http-data=$postData output=none
    } on-error={
        :log error "Failed to send Telegram notification"
    }
}

Использование:

routeros
:global telegramMessage "<b>Alert:</b> Interface ether1 is down"
/system/script/run telegram-notify

Проверка

Просмотр всех скриптов

[admin@MikroTik] >
/system/script print
/system/script print detail where name=backup-to-email

Ручной запуск скрипта

[admin@MikroTik] >
/system/script/run backup-to-email

Проверка планировщика

[admin@MikroTik] >
/system/scheduler print

Поля next-run и run-count показывают, когда скрипт запустится в следующий раз и сколько раз уже выполнялся.

Просмотр логов скриптов

[admin@MikroTik] >
/log print where topics~"script"
/log print where message~"backup"

Просмотр Netwatch

[admin@MikroTik] >
/tool/netwatch print
# Колонка STATUS показывает текущее состояние: up или down

Проверка переменных окружения

[admin@MikroTik] >
# Просмотр всех глобальных переменных
/system/script/environment print

Типичные ошибки

1. Скрипт не запускается: «insufficient permissions»

Причина: policy скрипта или scheduler не включает нужные права.

Решение:

[admin@MikroTik] >
# Проверьте policy скрипта
/system/script print detail where name=backup-to-email

# Установите нужные rights
/system/script set backup-to-email policy=read,write,test,sensitive

# Также проверьте policy у scheduler
/system/scheduler set daily-backup policy=read,write,test,sensitive

2. Email не отправляется

Причина: неправильная настройка SMTP или блокировка порта.

Решение:

[admin@MikroTik] >
# Проверьте настройки email
/tool/e-mail print

# Тестовая отправка
/tool/e-mail send to="admin@company.com" \
  subject="Test" body="Test email from MikroTik"

# Проверьте логи
/log print where topics~"e-mail"

Распространённые проблемы с email:

  • Gmail требует App Password (не обычный пароль аккаунта)
  • Порт 587 + TLS=starttls для большинства провайдеров
  • Порт 465 + TLS=tls для implicit TLS
  • DNS должен резолвить SMTP-сервер — проверьте /ip/dns/print

3. Ошибка парсинга: «expected command name»

Причина: синтаксические ошибки в скрипте. Распространённые причины:

  • Пропущены пробелы вокруг операторов: $a+$b вместо ($a + $b)
  • Не закрыты кавычки или скобки
  • Использование = вместо == в сравнениях (в RouterOS = используется и для присвоения, и для сравнения в зависимости от контекста)

Решение: тестируйте скрипты по частям в терминале перед сохранением.

[admin@MikroTik] >
# Проверка синтаксиса — просто вставьте код в терминал
# Если ошибка — RouterOS укажет номер строки

4. Переменные теряют значение между вызовами

Причина: использование :local вместо :global. Локальные переменные уничтожаются по завершении скрипта.

Решение: для передачи данных между скриптами используйте :global:

[admin@MikroTik] >
# Скрипт 1: устанавливает переменную
:global lastBackupTime [/system/clock/get time]

# Скрипт 2: читает переменную
:global lastBackupTime
:log info "Last backup was at $lastBackupTime"

5. /tool/fetch зависает или возвращает ошибку

Причина: DNS не настроен, сертификат не принимается, или файрвол блокирует исходящие подключения.

Решение:

[admin@MikroTik] >
# Проверьте DNS
/ip/dns/print
/ping dns.google count=3

# Для HTTPS — проверьте наличие CA-сертификатов
/certificate print

# Если CA нет — скачайте
/tool/fetch url="https://curl.se/ca/cacert.pem" dst-path=cacert.pem
/certificate/import file-name=cacert.pem passphrase=""

6. Scheduler показывает run-count=0

Причина: неверно указан start-time или start-date в будущем.

Решение:

[admin@MikroTik] >
# Проверьте системное время
/system/clock/print

# Удалите start-date для немедленного начала
/system/scheduler set daily-backup start-date=""

# Или запустите вручную для проверки
/system/script/run backup-to-email

Лучшие практики

  1. Всегда оборачивайте опасные операции в :do { } on-error={ } — это предотвращает остановку скрипта при ошибке
  2. Используйте :delay между сетевыми операциями — email-отправка и fetch требуют времени
  3. Логируйте начало и конец скрипта — это помогает при диагностике
  4. Не храните пароли в скриптах открытым текстом — используйте переменные окружения или отдельные зашифрованные файлы
  5. Ограничивайте policy минимально необходимыми правами — не давайте reboot скрипту мониторинга
  6. Тестируйте скрипты в терминале перед добавлением в scheduler
  7. Следите за размером логов — debug-логирование может быстро заполнить память
[admin@MikroTik] >
# Очистка старых логов
/system/logging/action set memory memory-lines=1000

Скриптовый язык RouterOS — мощный инструмент для автоматизации. Несмотря на своеобразный синтаксис, он позволяет решать большинство задач по мониторингу, резервному копированию и интеграции с внешними системами. Начинайте с простых скриптов и постепенно наращивайте сложность, всегда тестируя изменения в терминале перед добавлением в планировщик.

[admin@MikroTik] >
# Локальная переменная — видна только в текущем скрипте
:local myVar "Hello"
:local myNum 42
:local myBool true
:local myIP 192.168.1.1

# Глобальная переменная — доступна из любого скрипта
:global sharedVar "Shared value"

# Массив
:local myArray {"item1"; "item2"; "item3"}

# Получение значения из команды
:local hostname [/system/identity/get name]
# Вывод в терминал
:put "Current hostname: $hostname"

# Запись в системный лог
:log info "Script started"
:log warning "Disk space low"
:log error "Backup failed"
:local cpuLoad [/system/resource/get cpu-load]

:if ($cpuLoad > 80) do={
    :log warning "High CPU load: $cpuLoad%"
} else={
    :log info "CPU load normal: $cpuLoad%"
}
:local ifName "ether1"
:local ifComment [/interface/get $ifName comment]

:if ([:len $ifComment] = 0) do={
    :log info "Interface $ifName has no comment"
}

# Проверка наличия интерфейса
:if ([:len [/interface/find name=$ifName]] > 0) do={
    :log info "Interface $ifName exists"
}
# foreach — перебор элементов
:local interfaces [/interface/find type=ether]
:foreach iface in=$interfaces do={
    :local ifName [/interface/get $iface name]
    :local ifStatus [/interface/get $iface running]
    :log info "Interface $ifName running=$ifStatus"
}

# for — цикл со счётчиком
:for i from=1 to=5 do={
    :log info "Iteration $i"
}

# while — цикл с условием
:local count 0
:while ($count < 10) do={
    :set count ($count + 1)
}
:local str1 "Hello"
:local str2 "World"

# Конкатенация
:local result "$str1 $str2"

# Длина строки
:local len [:len $str1]

# Подстрока (pick)
:local sub [:pick $str1 0 3]
# Результат: "Hel"

# Поиск подстроки (find)
:local pos [:find $str1 "ll"]
# Результат: 2

# Преобразование типов
:local numStr [:tostr 42]
:local strNum [:tonum "42"]
# Создание массива
:local servers {"8.8.8.8"; "1.1.1.1"; "9.9.9.9"}

# Добавление элемента
:set ($servers->[:len $servers]) "208.67.222.222"

# Перебор массива
:foreach server in=$servers do={
    :local pingResult [/ping $server count=1 as-value]
    :if ([:len $pingResult] > 0) do={
        :log info "Server $server is reachable"
    } else={
        :log warning "Server $server is unreachable"
    }
}
# Запуск скрипта каждый день в 03:00
/system/scheduler add name=daily-backup \
  start-time=03:00:00 \
  interval=1d \
  on-event="/system/script/run backup-to-email" \
  policy=read,write,test,policy \
  comment="Daily backup at 3 AM"

# Запуск каждые 5 минут
/system/scheduler add name=health-check \
  interval=5m \
  on-event="/system/script/run health-monitor" \
  policy=read,write,test

# Запуск один раз в определённое время
/system/scheduler add name=one-time-task \
  start-date=2025-01-15 \
  start-time=12:00:00 \
  on-event=":log info \"One-time task executed\"" \
  policy=read
/tool/e-mail set server=smtp.gmail.com \
  port=587 \
  tls=starttls \
  from=mikrotik-backup@company.com \
  user=mikrotik-backup@company.com \
  password="AppSpecificPassword"
/system/script add name=backup-to-email policy=read,write,test,sensitive source={
    :local hostname [/system/identity/get name]
    :local dateStr [/system/clock/get date]
    :local timeStr [/system/clock/get time]
    :local fileName "$hostname-$dateStr"

    # Создаём binary backup (полная копия, включая пароли)
    /system/backup/save name=$fileName encryption=aes-sha256 \
      password="BackupEncryptionKey2024"

    # Создаём текстовый export (читаемый, без паролей)
    /export file=$fileName

    :delay 5s

    # Отправляем binary backup
    /tool/e-mail send \
      to="admin@company.com" \
      subject="[$hostname] Backup $dateStr $timeStr" \
      body="Automated backup from $hostname\nDate: $dateStr $timeStr\nBinary backup (encrypted) attached." \
      file="$fileName.backup"

    :delay 3s

    # Отправляем текстовый export
    /tool/e-mail send \
      to="admin@company.com" \
      subject="[$hostname] Export $dateStr $timeStr" \
      body="Automated export from $hostname\nDate: $dateStr $timeStr\nText export attached." \
      file="$fileName.rsc"

    :delay 3s

    # Удаляем локальные файлы (опционально)
    /file/remove "$fileName.backup"
    /file/remove "$fileName.rsc"

    :log info "Backup sent to email successfully"
}
/system/scheduler add name=daily-backup \
  start-time=03:00:00 interval=1d \
  on-event="/system/script/run backup-to-email" \
  policy=read,write,test,sensitive \
  comment="Daily backup to email"
/system/script add name=failover-monitor policy=read,write,test source={
    :local mainGateway "203.0.113.1"
    :local backupGateway "198.51.100.1"
    :local checkHost "8.8.8.8"
    :local failCount 0
    :local maxFails 3

    # Проверяем связь через основной канал
    :for i from=1 to=$maxFails do={
        :local pingResult [/ping $checkHost count=1 interface=ether1-wan \
          as-value]
        :if ([:len $pingResult] = 0) do={
            :set failCount ($failCount + 1)
        }
    }

    :if ($failCount >= $maxFails) do={
        # Основной канал недоступен — проверяем текущий маршрут
        :local currentRoute [/ip/route/find where dst-address="0.0.0.0/0" \
          gateway=$mainGateway]
        :if ([:len $currentRoute] > 0) do={
            /ip/route/disable $currentRoute
            :log warning "Main gateway $mainGateway DOWN - switched to backup"

            # Отправляем уведомление
            /tool/e-mail send \
              to="admin@company.com" \
              subject="[ALERT] Main gateway DOWN" \
              body="Main gateway $mainGateway is unreachable.\nSwitched to backup: $backupGateway"
        }
    } else={
        # Основной канал доступен — проверяем, не отключен ли маршрут
        :local disabledRoute [/ip/route/find where dst-address="0.0.0.0/0" \
          gateway=$mainGateway disabled=yes]
        :if ([:len $disabledRoute] > 0) do={
            /ip/route/enable $disabledRoute
            :log info "Main gateway $mainGateway UP - restored primary route"

            /tool/e-mail send \
              to="admin@company.com" \
              subject="[OK] Main gateway restored" \
              body="Main gateway $mainGateway is back online."
        }
    }
}
/system/scheduler add name=failover-check \
  interval=30s \
  on-event="/system/script/run failover-monitor" \
  policy=read,write,test
/system/script add name=dns-blacklist-update policy=read,write,test source={
    :local blacklistUrl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
    :local fileName "hosts.txt"
    :local addedCount 0
    :local maxEntries 5000

    # Загружаем файл
    :log info "DNS blacklist: downloading..."
    /tool/fetch url=$blacklistUrl dst-path=$fileName mode=https

    :delay 5s

    # Удаляем старые записи
    :local oldEntries [/ip/dns/static/find where comment="blacklist"]
    :foreach entry in=$oldEntries do={
        /ip/dns/static/remove $entry
    }
    :log info "DNS blacklist: removed old entries"

    # Читаем файл построчно
    :local fileContent [/file/get $fileName contents]
    :local lineStart 0
    :local fileLen [:len $fileContent]

    :while ($lineStart < $fileLen && $addedCount < $maxEntries) do={
        :local lineEnd [:find $fileContent "\n" $lineStart]
        :if ([:typeof $lineEnd] = "nil") do={
            :set lineEnd $fileLen
        }

        :local line [:pick $fileContent $lineStart $lineEnd]
        :set lineStart ($lineEnd + 1)

        # Пропускаем комментарии и пустые строки
        :if ([:len $line] > 0 && [:pick $line 0 1] != "#") do={
            # Формат: "0.0.0.0 domain.com"
            :local spacePos [:find $line " " 0]
            :if ([:typeof $spacePos] != "nil") do={
                :local domain [:pick $line ($spacePos + 1) [:len $line]]
                # Убираем возможный \r
                :if ([:pick $domain ([:len $domain] - 1) [:len $domain]] = "\r") do={
                    :set domain [:pick $domain 0 ([:len $domain] - 1)]
                }

                :if ([:len $domain] > 0 && $domain != "localhost") do={
                    :do {
                        /ip/dns/static/add name=$domain address=0.0.0.0 \
                          comment="blacklist" ttl=1d
                        :set addedCount ($addedCount + 1)
                    } on-error={
                        # Запись уже существует или невалидная — пропускаем
                    }
                }
            }
        }
    }

    # Удаляем скачанный файл
    /file/remove $fileName

    :log info "DNS blacklist: added $addedCount entries"
}
/system/scheduler add name=dns-blacklist \
  start-time=04:00:00 interval=1d \
  on-event="/system/script/run dns-blacklist-update" \
  policy=read,write,test \
  comment="Update DNS blacklist daily"
# Мониторинг доступности сервера
/tool/netwatch add host=10.0.0.100 \
  interval=30s \
  timeout=2s \
  type=icmp \
  up-script={
      :log info "Server 10.0.0.100 is UP"
  } \
  down-script={
      :log error "Server 10.0.0.100 is DOWN"
      /tool/e-mail send \
        to="admin@company.com" \
        subject="[ALERT] Server 10.0.0.100 DOWN" \
        body="Server 10.0.0.100 is not responding to ICMP."
  }
/tool/netwatch add host=10.0.0.100 \
  type=http-get \
  http-code-min=200 \
  http-code-max=299 \
  port=443 \
  tls=yes \
  interval=1m \
  down-script={
      :log error "Web server HTTPS check failed"
  }
/system/script add name=memory-watchdog policy=read,write,reboot source={
    :local totalMem [/system/resource/get total-memory]
    :local freeMem [/system/resource/get free-memory]
    :local freePercent (($freeMem * 100) / $totalMem)
    :local hostname [/system/identity/get name]

    :if ($freePercent < 10) do={
        :log warning "Memory critically low: $freePercent% free"

        /tool/e-mail send \
          to="admin@company.com" \
          subject="[CRITICAL] $hostname - Low memory, rebooting" \
          body="Free memory: $freePercent%\nTotal: $totalMem\nFree: $freeMem\nInitiating reboot..."

        :delay 10s
        /system/reboot
    } else={
        :if ($freePercent < 25) do={
            :log warning "Memory low: $freePercent% free"
        }
    }
}
# GET-запрос
/tool/fetch url="https://api.example.com/status" mode=https \
  dst-path=api-response.txt

# POST-запрос (отправка данных)
/tool/fetch url="https://hooks.slack.com/services/XXX/YYY/ZZZ" \
  mode=https \
  http-method=post \
  http-header-field="Content-Type: application/json" \
  http-data="{\"text\": \"MikroTik alert: link down\"}" \
  output=none
/system/script add name=telegram-notify policy=read,write,test source={
    :local botToken "123456789:ABCdefGHI_jklMNOpqrSTUvwxyz"
    :local chatId "-1001234567890"
    :local hostname [/system/identity/get name]

    :global telegramMessage
    :if ([:len $telegramMessage] = 0) do={
        :set telegramMessage "No message specified"
    }

    :local url "https://api.telegram.org/bot$botToken/sendMessage"
    :local postData "chat_id=$chatId&text=$telegramMessage&parse_mode=HTML"

    :do {
        /tool/fetch url=$url mode=https http-method=post \
          http-data=$postData output=none
    } on-error={
        :log error "Failed to send Telegram notification"
    }
}
:global telegramMessage "<b>Alert:</b> Interface ether1 is down"
/system/script/run telegram-notify
/system/script print
/system/script print detail where name=backup-to-email
/system/script/run backup-to-email
/system/scheduler print
/log print where topics~"script"
/log print where message~"backup"
/tool/netwatch print
# Колонка STATUS показывает текущее состояние: up или down
# Просмотр всех глобальных переменных
/system/script/environment print
# Проверьте policy скрипта
/system/script print detail where name=backup-to-email

# Установите нужные rights
/system/script set backup-to-email policy=read,write,test,sensitive

# Также проверьте policy у scheduler
/system/scheduler set daily-backup policy=read,write,test,sensitive
# Проверьте настройки email
/tool/e-mail print

# Тестовая отправка
/tool/e-mail send to="admin@company.com" \
  subject="Test" body="Test email from MikroTik"

# Проверьте логи
/log print where topics~"e-mail"
# Проверка синтаксиса — просто вставьте код в терминал
# Если ошибка — RouterOS укажет номер строки
# Скрипт 1: устанавливает переменную
:global lastBackupTime [/system/clock/get time]

# Скрипт 2: читает переменную
:global lastBackupTime
:log info "Last backup was at $lastBackupTime"
# Проверьте DNS
/ip/dns/print
/ping dns.google count=3

# Для HTTPS — проверьте наличие CA-сертификатов
/certificate print

# Если CA нет — скачайте
/tool/fetch url="https://curl.se/ca/cacert.pem" dst-path=cacert.pem
/certificate/import file-name=cacert.pem passphrase=""
# Проверьте системное время
/system/clock/print

# Удалите start-date для немедленного начала
/system/scheduler set daily-backup start-date=""

# Или запустите вручную для проверки
/system/script/run backup-to-email
# Очистка старых логов
/system/logging/action set memory memory-lines=1000
System / Скрипты RouterOS — автоматизация задач на MikroTik