MikroTik Скрипт: Массовое создание VPN (PPP) пользователей, из csv файла

  • Tutorial

Не самая частая задача на устройствах 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 - добавлено видео работы скрипта.

Комментарии 9

    0
    У меня возникает сразу простой вопрос — если встроенный ЯП так себе, зачем страдать?

    Пример обращения к логам фаерволла на Python. В итоге у нас есть удобный язык программирования и немного непривычная конверсия привычных команд в апи.
    from routeros_api import Api
    ...
    response = []
    router = Api(IP, user=USER, password=PASS)    
    r = router.talk('/ip/firewall/address-list/print')
    for item in r:
        if name==item['list']:
            response.append(item['address'])
    
      0
      «Спортивный интерес», а так же — скрипты всегда на «борту» MikroTik, не требуя ни установки сторонних программ, ни настроек доступа к устройству/множеству_устройств для сторонних программ (например при смене адреса/логина/пароля как самого устройства или изменении географического местоположения администратора).
      Если бы у MikroTik были списки Python и возможность поиска «от сих и до сих», никаких костылей +1, -1, +2 не понадобилось бы. :)
        +1
        Когда микротиков десяток еще можно так развлекаться :) когда счет идет на сотни, ходить по ним руками — безумие. Примерно из этой же обсласти создавать отдельные учетки для впн на самом микроте, для этого давно существует RADIUS.
          0
          Верно, но не у всех такие масштабы. :)
            0
            Переход от 10 к 300 вообще не заметен. Ты уверен что в отделе не хватает людей и много работы, а на самом деле ты просто не сделал автоматизацию там где она должна была быть сразу :)
      –1
      Подскажите пожалуйста, почему используется устаревший способ подключения к серверу, который давно уже depricated (например, в MacOS уго уже давно «удалили» из системы)?
        +1

        Обратите внимание: никто не говорит про PPTP, который в маках действительно удалили. Пользовательские данные в разделе PPP на Микротике используются для всех VPN кроме IPsec.

          0
          Потому что сам IPsec не создает интерфейсов.
            0

            Согласен, надо было писать полностью IPsec/IKEv2. И соответствующие данные хранятся в разделе IPsec на вкладке Identities.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое