Не самая частая задача на устройствах MikroTik - одномоментное создание большого количества PPP(англ.Point-to-Point Protocol) пользователей. Но когда она возникает, это превращается в очень скучное и нудное дело, что следует исправить.
Предыдущую статью "MikroTik Скрипт: Уведомление о успешном входе на устройство или простой парсер журнала MikroTik" добавило в закладки в закладки 80+ пользователей, надеюсь и эта статья будет не менее полезна.
- Что, мой мальчик, получается ли тебе собрать слово "Вечность"?
- Трудно, моя госпожа, сложить слово "Вечность" из букв "Ж", "П", "О" и "А" - ответил Кай.
Скриптовый язык MikroTik никак нельзя назвать полноценным языком программирования, поэтому слово "Вечность" будем собирать из того что есть, добавляя костыли и перематывая синей изолентой (ведь нет ничего долговечней, чем ...).
Скрипт рассчитан на внимательных пользователей (регистр имени файла, структура файла) и не рассчитан на любознательных пользователей вида "что будет, если вместо IP адреса поставить деление на ноль?". "Защита от дурака" отсутствует, чтобы искусственно не раздувать размер скрипта.
Планируемая последовательность действий
-
Скачиваем шаблон CSV файла (FileTemplate.zip на GitHub);
-
Заполняем шаблон (проверено Microsoft Excel);
-
Загружаем файл на устройство MikroTik;
-
Создаем скрипт импорта PPP пользователей;
-
Включаем Безопасный режим MikroTik;
-
Запускаем скрипт;
-
Смотрим лог и список PPP пользователей;
-
Убедившись, что все прошло хорошо - выключаем Безопасный режим MikroTik;
-
Пишем в комментарий к статье, что всё прошло хорошо (неплохо указать модель устройства, версию RouterOS).
Создание файла
Настоятельно рекомендую использовать шаблон файла с GitHub (в этом случае пропустите этот раздел).
Но вы конечно можете создавать свой файл с любым расширением (в
этом случае настраивайте :set Content [:pick $Content 62
$ContentLen];
вместо 62 выставляя свое значение от начала
последовательности, в скрипте "отрезается" 62 символа - с учетом
"шапки" таблицы в шаблоне).
Как разделитель элементов используется символ ";", но вы можете указать свой символ.
Как разделитель строк используется символ "\r", поэтому шаблон предоставлен в .zip формате с сохранением всех символов, т.к. множество редакторов, в том числе на GitHub отрезают "лишние" по их мнению символы.
Логика скрипта
Укажите в строке :local FileName
"FileTemplate.csv";
название импортированного файла
(рекомендую скопировать полное название из списка Files);
Проверка, что размер файла не превышен, запись в журнал устройства при превышении размера и остановка скрипта. Для RouterOS6 существует ограничение на размер переменной в 4КБ (у меня это было 80 пользователей, в RouterOS7 вроде как обещают снять ограничения);
"Разбираем" файл, разбивая его на строки и запуская деление на элементы в каждой строке;
Значение найденного элемента присваиваем соответствующему ключу массива ColumnsArray;
Закончив разбор строки, формируем команду MikroTik для создания PPP пользователя;
Если имя пользователя уже существует - пропускаем создание пользователя (вы можете самостоятельно добавить удаление пользователя, если требуется массовое пересоздание пользователей);
Добавляем каждое из значений массива ColumnsArray в текст команды, если значение отсутствует, попускаем.
Выполняем сформированную команду создания пользователя;
Переходим к разбору следующей строки, если индекс последнего элемента строки меньше общего количества элементов в файле.
Создать скрипт
Для запуска скрипта необходимы разрешения: read, write, test, policy.
[System] -> [Scripts] -> [+] -> [Name: CreatePPPUsers] -> [Policy: read, write, test, policy]
Внимание: излишние права (выставляются по умолчанию новому скрипту) могут привести к появлению ошибки "could not run script ParseLogAccountEvents: not enough permissions" (RouterOS 6.48), устанавливайте только указанные в статье права.
Код скрипта
# Name: CreatePPPUsers v1# Description: Bulk create VPN users from a file# Author: Yun Sergey, MHelp.pro 2020# License: GPL-3.0 License# Description, purpose and questions: https://mhelp.pro/mikrotik-script-bulk-create-vpn-users-from-a-file/# More scripts Mikrotik: https://mhelp.pro/tag/mikrotik/:local FileName "FileTemplate.csv";:log warning "Script CreatePPPUsers: running. Import from file: $FileName";:if ([/file get $FileName size] > 4096) do={ :log error "Error run script CreatePPPUsers: file size exceeded 4 KB (size constraint of a variable in Router OS 6). Split the file $FileName into several parts."; :error "File size exceeded 4 KB. Stop script."};:local Content [/file get $FileName contents];:local ContentLen [:len $Content];:set Content [:pick $Content 62 $ContentLen];:local StartCursor 0;:local EndCursor;:local LineEndCursor;:while ($StartCursor < [:len $Content]) do={ :set LineEndCursor [:find $Content "\r" $StartCursor]; :local Cont; :local ColumnsArray { "01Name"="" ; "02Password"="" ; "03Service"="" ; "04Profile"="" ; "05LocalAdress"="" ; "06RemoveAddress"=""}; # START PARSING STRING :foreach Key,Value in=$ColumnsArray do={ :local Symbol [:pick $Content $StartCursor]; :if ($Symbol =";") do={:set StartCursor ($StartCursor - 1)}; :set EndCursor [:find $Content ";" $StartCursor]; :if (($EndCursor > $LineEndCursor) or ([:typeof $EndCursor]="nil")) do={:set EndCursor [:find $Content "\r" ($StartCursor-1)];}; :set Cont [:pick $Content $StartCursor $EndCursor]; :set ($ColumnsArray -> $Key ) $Cont; :set StartCursor ($EndCursor+1); }; # END PARSING STRING # START CREATE COMMAND :local UserName ($ColumnsArray -> "01Name"); :if ([/ppp secret find name=$UserName ]) do={ :log info "Add PPP user: $UserName - already exist! Skipped."; } else={ :local Command "/ppp secret add name=$UserName"; :local UserPassword ($ColumnsArray -> "02Password"); :if ($UserPassword != ";") do= {:set Command ("$Command" . " password=$UserPassword")}; :local UserService ($ColumnsArray -> "03Service"); :if ($UserService != ";") do= {:set Command ("$Command" . " service=$UserService")}; :local UserProfile ($ColumnsArray -> "04Profile"); :if ($UserProfile != ";") do= {:set Command ("$Command" . " profile=$UserProfile")}; :local UserLocalAdress ($ColumnsArray -> "05LocalAdress"); :if ($UserLocalAdress != ";") do= {:set Command ("$Command" . " local-address=$UserLocalAdress")}; :local UserRemoveAddress ($ColumnsArray -> "06RemoveAddress"); :if ($UserRemoveAddress != ";") do= {:set Command ("$Command" . " remote-address=$UserRemoveAddress")}; [:parse $Command]; }; # END CREATE COMMAND :set StartCursor ($EndCursor+2);};:delay 2;:log warning "Script CreatePPPUsers: completed.";
Скрипт намеренно сделан в упрощенном виде, избегая вложенных конструкций, затрудняющих чтение кода, но никто не мешает вам "дооптимизировать" скрипт в "одну" или минимальное количество строк.
Если вам интересны другие мои скрипты MikroTik, их можно увидеть здесь или на GitHub.
Если вы использовали скрипт, оставьте пожалуйста обратную связь "Работает. Модель устройства и версия RouterOS". Это поможет другим. Спасибо.
Проверено: MikroTik hAP ac lite (RouterBOARD 952Ui-5ac2nD), RouterOS 6.47.8 (stable).