Не самая частая задача на устройствах MikroTik - одномоментное создание большого количества PPP (англ. Point-to-Point Protocol)  пользователей. Но когда она возникает, это превращается в очень скучное и нудное дело, что следует исправить.

Предыдущую статью "MikroTik Скрипт: Уведомление о успешном входе на устройство или простой парсер журнала MikroTik" добавило в закладки в закладки 80+ пользователей, надеюсь и эта статья будет не менее полезна.

- Что, мой мальчик, получается ли тебе собрать слово "Вечность"?

- Трудно, моя госпожа, сложить слово "Вечность" из букв "Ж", "П", "О" и "А" - ответил Кай.

Скриптовый язык MikroTik никак нельзя назвать полноценным языком программирования, поэтому слово "Вечность" будем собирать из того что есть, добавляя костыли и перематывая синей изолентой (ведь нет ничего долговечней, чем ...).

Скрипт рассчитан на внимательных пользователей (регистр имени файла, структура файла) и не рассчитан на любознательных пользователей вида "что будет, если вместо IP адреса поставить деление на ноль?". "Защита от дурака" отсутствует, чтобы искусственно не раздувать размер скрипта.

Планируемая последовательность действий

  1. Скачиваем шаблон CSV файла (FileTemplate.zip на GitHub);

  2. Заполняем шаблон (проверено Microsoft Excel);

  3. Загружаем файл на устройство MikroTik;

  4. Создаем скрипт импорта PPP пользователей;

  5. Включаем Безопасный режим MikroTik;

  6. Запускаем скрипт;

  7. Смотрим лог и список PPP пользователей;

  8. Убедившись, что все прошло хорошо - выключаем Безопасный режим MikroTik;

  9. Пишем в комментарий к статье, что всё прошло хорошо (неплохо указать модель устройства, версию RouterOS).

Создание файла

Настоятельно рекомендую использовать шаблон файла с GitHub (в этом случае пропустите этот раздел).

Но вы конечно можете создавать свой файл с любым расширением (в этом случае настраивайте :set Content [:pick $Content 62 $ContentLen]; вместо 62 выставляя свое значение от начала последовательности, в скрипте "отрезается" 62 символа - с учетом "шапки" таблицы в шаблоне).

Как разделитель элементов используется символ ";", но вы можете указать свой символ.

Как разделитель строк используется символ "\r", поэтому шаблон предоставлен в .zip формате с сохранением всех символов, т.к. множество редакторов, в том числе на GitHub отрезают "лишние" по их мнению символы.

Логика скрипта

Укажите в переменной FileName название импортированного файла (рекомендую скопировать полное название из списка Files);

Укажите в переменной Separator символ разделения полей в файле импорта. Например для региональных настроек ru_RU разделитель по умолчанию - точка с запятой, для en_EN локали - запятая. (Microsoft Excel 2019 RU, при сохранении "CSV UTF-8 (разделитель запятая)", принудительно устанавливает точку с запятой, как символ разделения полей).

Проверка, что размер файла не превышен, запись в журнал устройства при превышении размера и остановка скрипта. Для 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.1
# 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";
:local Separator ";";

: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=$Separator) do={:set StartCursor ($StartCursor - 1)};

        :set EndCursor [:find $Content $Separator $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 != $Separator) do= {:set Command ("$Command" . " password=$UserPassword")};

        :local UserService ($ColumnsArray -> "03Service");
        :if ($UserService != $Separator) do= {:set Command ("$Command" . " service=$UserService")};

        :local UserProfile ($ColumnsArray -> "04Profile");
        :if ($UserProfile != $Separator) do= {:set Command ("$Command" . " profile=$UserProfile")};

        :local UserLocalAdress ($ColumnsArray -> "05LocalAdress");
        :if ($UserLocalAdress != $Separator) do= {:set Command ("$Command" . " local-address=$UserLocalAdress")};

        :local UserRemoveAddress ($ColumnsArray -> "06RemoveAddress");
        :if ($UserRemoveAddress != $Separator) 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).

  1. UPD: 18.12.20 - в скрипт добавлена переменная Separator (см. "Логика скрипта");

  2. UPD: 19.12.20 - добавлено видео работы скрипта.