Автоматизація введення в SecureCRT за допомогою скриптів

У мережевих інженерів часто виникає завдання виконати copy/past певних фрагментів із блокнота в консоль. Копіювати доводиться зазвичай кілька параметрів: Username/Password і ще. Прискорити процес дозволяє використання скриптів. А завдання написання скрипта і виконання скрипта сумарно повинні зайняти менше часу, ніж налаштування вручну, інакше скрипти марні.

Навіщо потрібна ця стаття. Ця стаття з циклу Fast Start і спрямована на економію часу мережевим інженерам при налаштуванні обладнання (одного завдання) на декількох пристроях. Використовується програмне забезпечення SecureCRT і вбудований функціонал виконання скриптів.

Зміст

Запровадження

У програму SecureCRT із коробки вбудований механізм виконання скриптів. Для чого потрібні скрипти в терміналі:

  • Автоматизоване введення та виведення, та мінімальна перевірка коректності вводу/виводу.
  • Прискорити виконання рутинних завдань – зменшення пауз між налаштуванням обладнання. (Де факто зменшення пауз, викликаних часом для виконання дій з copy/past на тому самому устаткуванні, при 3-х і більше фрагментів команд для застосування на устаткуванні.)

У цьому документі розглянуто завдання:

  • Створення найпростіших скриптів.
  • Запуск скриптів на SecureCRT.
  • Приклади використання простих та просунутих скриптів. (Практика із реального життя.)

Створення найпростіших скриптів.

Найпростіші скрипти використовують лише дві команди Send та WaitForString. Цього функціоналу вистачить на 90% (і більше) завдань.

Скрипти можуть працювати мовою Python, JS, VBS (Visual Basic), Perl і т.д.

Python

# $language = "Python"
# $interface = "1.0"
def main():
  crt.Screen.Synchronous = True
  crt.Screen.Send("r")
  crt.Screen.WaitForString("name")
  crt.Screen.Send("adminr")
  crt.Screen.WaitForString("Password:")
  crt.Screen.Send("Password")
  crt.Screen.Synchronous = False
main()

Зазвичай файл з розширенням *.py

VBS

# $language = "VBScript"
# $interface = "1.0"
Sub Main
  crt.Screen.Synchronous = True
  crt.Screen.Send vbcr
  crt.Screen.WaitForString "name"
  crt.Screen.Send "cisco" & vbcr
  crt.Screen.WaitForString "assword"
  crt.Screen.Send "cisco" & vbcr
  crt.Screen.Synchronous = False
End Sub

Зазвичай файл із розширенням «*.vbs»

Створення сценарію за допомогою запису сценарію.

Дозволяє автоматизувати процес написання скрипту. Ви запускаєте запис скрипту. SecureCRT записує команди та подальшу відповідь обладнання та виводить Вам готовий скрипт.

а. Запустити запис скрипту:
Меню SecureCRT => Script => Start Recording Script
б. Виконати дії з консоллю (виконати дії з налаштування CLI).
в. Закінчити запис скрипту:
Меню SecureCRT => Script => Stop Recording Script…
Зберегти файл зі скриптом.

Приклад виконаних команд та збереженого скрипту:

Автоматизація введення в SecureCRT за допомогою скриптів

Запуск скриптів на SecureCRT.

Після створення/редагування скрипта виникає закономірне питання: Як застосувати скрипт?
Існує кілька способів:

  • Запуск вручну з меню Script
  • Автоматичний запуск після підключення (logon script)
  • Автоматичний logon без використання скрипту
  • Запуск вручну за допомогою кнопки в SecureCRT (кнопка ще має бути створена і додана в SecureCRT)

Запуск вручну з меню Script

Меню SecureCRT => Script => Run…
— Останні 10 скриптів запам'ятовуються та доступні для швидкого запуску:
Меню SecureCRT => Script => 1 "Ім'я файлу зі скриптом"
Меню SecureCRT => Script => 2 "Ім'я файлу зі скриптом"
Меню SecureCRT => Script => 3 "Ім'я файлу зі скриптом"
Меню SecureCRT => Script => 4 "Ім'я файлу зі скриптом"
Меню SecureCRT => Script => 5 "Ім'я файлу зі скриптом"

Автоматичний запуск після підключення (logon script)

Налаштування автоматичного скрипту логування налаштовуються для збереженої сесії: Connection => Logon Actions => Logon script

Автоматизація введення в SecureCRT за допомогою скриптів

Автоматичний logon без використання скрипту

Існує можливість автоматичного введення імені користувача пароля без написання скрипта, використовуючи лише вбудований функціонал SecureCRT. У налаштуваннях з'єднання «Connection» => Logon Actions => Automate logon – необхідно заповнити кілька зв'язок – які мають на увазі пари: «Очікуваний текст» + «Символи, що посилаються на цей текст» таких пар може бути багато. (Приклад: 1 пара очікування введення імені користувача, друга очікування введення пароля, третя очікування запрошення в привілейований режим, четверта пароль від привілейованого режиму.)

Приклад автоматичного logon на Cisco ASA:

Автоматизація введення в SecureCRT за допомогою скриптів

Запуск вручну за допомогою кнопки в SecureCRT (кнопка ще має бути створена і додана в SecureCRT)

У SecureCRT можна встановити скрипт – кнопці. Кнопка додається на спеціально створену для цього панель.

а. Додаємо панель до інтерфейсу: Меню SecureCRT => View => Button Bar
б. Додаємо кнопку на панель та додаємо скрипт. – Правою кнопкою мишки клацаємо на панель Button Bar та у контекстному меню вибираємо пункт «New button…».
в. У діалоговому вікні "Map Button" у полі "Action" Вибираємо дію (function) "Run Script".
Вказуємо підпис до кнопки. Колір для кнопки ікон. Закінчуємо налаштування натисканням OK.

Автоматизація введення в SecureCRT за допомогою скриптів

Примітка:

Панель із кнопками дуже корисний функціонал.

1. Є можливість при Logon до певної сесії вказувати панель за замовчуванням відкривати до цієї вкладки.

2. Є можливість для стандартних дій з обладнанням вказати заздалегідь задані дії: показати show version, show running-config, зберегти конфігурацію.

Автоматизація введення в SecureCRT за допомогою скриптів
До цих кнопок не прив'язаний жодний скрипт. Лише рядок з діями:

Автоматизація введення в SecureCRT за допомогою скриптів
Налаштування – щоб при перемиканні на сесію відкривалась необхідна панель з кнопками в налаштуваннях сесії:

Автоматизація введення в SecureCRT за допомогою скриптів
Для замовника має сенс налаштувати індивідуальні скрипти для Login та перехід на панель із частими командами для вендора.

Автоматизація введення в SecureCRT за допомогою скриптів
При натисканні на кнопку Go Cisco панель перемикається на Cisco Button Bar.

Автоматизація введення в SecureCRT за допомогою скриптів

Приклади використання простих та просунутих скриптів. (Практика із реального життя.)

Простих скриптів вистачає майже на всі випадки життя. Але одного разу мені потрібно було трохи ускладнити скрипт – для прискорення роботи. Це ускладнення - лише запитувало додаткові дані в діалоговому вікні у користувача.

Запит даних у користувача за допомогою діалогового вікна

У мене в скрипті запитів даних було 2. Це Hostname і 4 октет IP адреси. Для виконання цієї дії – я загуглив як це зробити та знайшов на офіційному сайті SecureCRT (vandyke). – функціонал називається prompt.

	crt.Screen.WaitForString("-Vlanif200]")
	hostnamestr = crt.Dialog.Prompt("Enter hostname:", "hostname", "", False)
	ipaddressstr = crt.Dialog.Prompt("Enter ip address:", "ip", "", False)
	crt.Screen.Send("ip address 10.10.10.")
	crt.Screen.Send(ipaddressstr)
	crt.Screen.Send(" 23r")
	crt.Screen.Send("quitr")
	crt.Screen.Send("sysname ")
	crt.Screen.Send(hostnamestr)
	crt.Screen.Send("r") 

Ця частина скрипту просила Hostname та цифри з останнього октету. обладнання було 15 шт. І дані були представлені в таблиці, то я копіював з таблиці значення та вставляв у діалогові вікна. Далі скрипт працював самотужки.

FTP копіювання на мережеве обладнання.

Цей скрипт запускав у мене командне вікно (shell) і копіював дані FTP. По завершенню закривав сесію. Використовувати блокнот для цього неможливо, тому що копіювання йде дуже довго і дані в буфері FTP не будуть зберігатися так:

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("ftp 192.168.1.1r")
	crt.Screen.WaitForString("Name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("binaryr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("put S5720LI-V200R011SPH016.patr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("quitr")
	crt.Screen.Synchronous = False
main()

Введення username/password за допомогою скрипту

У одного замовника доступ до мережного обладнання був закритий. Зайти на обладнання можна було спочатку підключившись до Шлюзу за замовчуванням, а з нього потім на підключене обладнання. Для підключення використовувався ssh клієнт, вбудований в IOS/ПО обладнання. Відповідно ім'я користувача та пароль вимагалися в консолі. За допомогою скрипту нижче, ім'я користувача та пароль вводилися автоматично:

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("snmpadminr")
	crt.Screen.WaitForString("assword:")
	crt.Screen.Send("Passwordr")
	crt.Screen.Synchronous = False
main()

Примітка: Скрипт було 2. Один для облікового запису адміністратора, другий для облікового запису eSIGHT.

Скрипт із можливістю безпосередньо дописувати дані під час виконання скрипту.

Завданням було додати по всьому мережевому устаткуванні статичний маршрут. Але шлюз в інтернеті на кожному устаткуванні був свій (і він відрізнявся від шлюзу за умовчанням). Наступний скрипт виводив таблицю маршрутизації, вводив у режим конфігурування недописував до кінця команду (IP-адреса шлюзу в інтернет) – цю частину дописував я. Після того, як я натискав Enter, скрипт продовжував виконання команди.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("Zdes-mogla-bit-vasha-reklamar")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("show run | inc ip router")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("conf tr")
	crt.Screen.WaitForString("(config)#")
	crt.Screen.Send("ip route 10.10.10.8 255.255.255.252 ")
	crt.Screen.WaitForString("(config)#")
	crt.Screen.Send("endr")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("copy run star")
	crt.Screen.WaitForString("[startup-config]?")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("exitr")
	crt.Screen.Synchronous = False
main()

У цьому скрипті в рядку: crt.Screen.Send(«ip route 10.10.10.8 255.255.255.252 „) не дописано IP адресу шлюзу та відсутній символ перекладу каретки. Скрипт чекає появи наступного рядка із символами «(config)#» Ці символи з'являлися після введення мною ip адреси та enter.

Висновок:

При написанні скрипту та виконанні, повинно неодмінно виконуватися правило: Час написання скрипту та виконання скрипту ніколи не повинно бути більше, часу теоретично витраченого на виконання цієї ж роботи вручну (copy/paste з блокнота, написання та налагодження playbook для ansible, написання та налагодження скрипт python). Т. е. використання скрипта має заощаджувати час, а не витрачати час на одноразову автоматизацію процесів (Т. е. коли скрипт унікальний і повторення більше не буде). Але якщо скрипт унікальний і автоматизація зі скриптом і написання/налагодження скрипта займає менше часу, ніж виконання будь-яким іншим способом (ansible, command window), то скрипт — найкраще рішення.
Налагодження скрипта. Скрипт росте поступово, налагодження відбувається на обкаті на першому, другому, третьому пристрої та до четвертого скрипт швидше за все буде повністю робочим.

Запуск скрипта (з введенням username+password) за допомогою мишки зазвичай відбувається швидше, ніж копіювання із блокнота Username та Password. Але не безпечно з погляду безпеки.
Інший (реальний) приклад, коли використання скрипту: Прямого доступу на мережеве обладнання у Вас немає. Але є необхідність доналаштувати все мережне обладнання (завести в систему моніторингу, доналаштувати додатковий Username/password/snmpv3username/password). Є доступ, коли ви заходите на Core комутатор, з нього відкриваєте SSH на інше обладнання. Чому не можна використовувати засоби Ansible. — Тому що ми впираємося в обмеження за кількістю допустимих одночасних сесій на мережевому устаткуванні (line vty 0 4, user-interface vty 0 4) (інше питання як Ansible заводити різне обладнання з одним і тим же SSH першим хопом).

Скрипт зменшує час при тривалих операціях – наприклад, копіювання файлів по FTP. Після закінчення копіювання скрипт одразу починає працювати. Людині потрібно побачити закінчення копіювання, потім усвідомити закінчення копіювання, потім запровадити відповідні команди. Скрипт робить це об'єктивно швидше.

Скрипти можна застосовувати там, де неможливо використовувати засоби масової доставки даних: Консоль. Або коли частина даних обладнання унікальна: hostname, management ip address. Або коли писати програму та налагодження до неї складніше, ніж дописати дані, отримані з обладнання під час роботи скрипту. — Приклад зі скриптом з прописування маршруту, коли на кожному IP-адресі інтернет провайдера свій. (Мої колеги писали такі скрипти - коли DMVPN spoke було за 3 сотні. Необхідно було змінити налаштування DMVPN).

Приклад із практики: Завдання початкових налаштувань на новому комутаторі через консольні порти:

А. Вставив консольний кабель у пристрій.
Б. Запустив скрипт
В. Дочекався виконання скрипту
Г. Переткнув консольний кабель наступного пристрою.
Д. Якщо свитч не останній, перейти до пункту Б.

Разом за підсумками роботи скрипта:

  • на обладнанні встановлено початковий пароль.
  • введено Username
  • введено унікальну IP-адресу пристрою.

PS операцію довелося повторювати. По Default ssh виявився не налаштований/вимкнений. (Та це моя помилка.)

Використані джерела.

1. Про створення скриптів
2. Приклади скриптів

Додаток 1: Приклади скриптів.


Приклад довгого скрипту з двома запитами: Hostname та IP адресою. Створювався для налаштування обладнання через консоль (9600 бод). А також для підготовки підключення обладнання до мережі.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("r")
	crt.Screen.WaitForString("name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.Send("sysr")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("interface Vlanif 1r")
	crt.Screen.WaitForString("Vlanif1]")
	crt.Screen.Send("undo ip addressr")
	crt.Screen.Send("shutdownr")
	crt.Screen.Send("vlan 100r")
	crt.Screen.Send(" description description1r")
	crt.Screen.Send(" name description1r")
	crt.Screen.Send("vlan 110r")
	crt.Screen.Send(" description description2r")
	crt.Screen.Send(" name description2r")
	crt.Screen.Send("vlan 120r")
	crt.Screen.Send(" description description3r")
	crt.Screen.Send(" name description3r")
	crt.Screen.Send("vlan 130r")
	crt.Screen.Send(" description description4r")
	crt.Screen.Send(" name description4r")
	crt.Screen.Send("vlan 140r")
	crt.Screen.Send(" description description5r")
	crt.Screen.Send(" name description5r")
	crt.Screen.Send("vlan 150r")
	crt.Screen.Send(" description description6r")
	crt.Screen.Send(" name description6r")
	crt.Screen.Send("vlan 160r")
	crt.Screen.Send(" description description7r")
	crt.Screen.Send(" name description7r")
	crt.Screen.Send("vlan 170r")
	crt.Screen.Send(" description description8r")
	crt.Screen.Send(" name description8r")               
	crt.Screen.Send("vlan 180r")
	crt.Screen.Send(" description description9r")
	crt.Screen.Send(" name description9r")
	crt.Screen.Send("vlan 200r")
	crt.Screen.Send(" description description10r")
	crt.Screen.Send(" name description10r")
	crt.Screen.Send("vlan 300r")
	crt.Screen.Send(" description description11r")
	crt.Screen.Send(" name description11r")
	crt.Screen.Send("quitr")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("stp region-configurationr")
	crt.Screen.Send("region-name descr")
	crt.Screen.Send("active region-configurationr")
	crt.Screen.WaitForString("mst-region]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("stp instance 0 priority 57344r")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("interface range GigabitEthernet 0/0/1 to GigabitEthernet 0/0/42r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description Usersr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type hybridr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("voice-vlan 100 enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("voice-vlan legacy enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid pvid vlan 120r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid tagged vlan 100r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid untagged vlan 120r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("stp edged-port enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("trust 8021pr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("interface range GigabitEthernet 0/0/43 to GigabitEthernet 0/0/48r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description Printersr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type accessr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port default vlan 130r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("stp edged-port enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("trust 8021pr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("interface range XGigabitEthernet 0/0/1 to XGigabitEthernet 0/0/2r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description uplinkr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type trunkr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port trunk allow-pass vlan 100 110 120 130 140 150 160 170 180 200r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port trunk allow-pass vlan 300r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.4r")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.2r")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.134r")
	crt.Screen.Send("ip route-static 0.0.0.0 0.0.0.0 10.10.10.254r")
	crt.Screen.Send("interface Vlanif 200r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
        hostnamestr = crt.Dialog.Prompt("Enter hostname:", "hostname", "", False)
        ipaddressstr = crt.Dialog.Prompt("Enter ip address:", "ip", "", False)
	crt.Screen.Send("ip address 10.10.10.")
	crt.Screen.Send(ipaddressstr)
	crt.Screen.Send(" 24r")
	crt.Screen.Send("quitr")
	crt.Screen.Send("sysname ")
	crt.Screen.Send(hostnamestr)
	crt.Screen.Send("r")
	crt.Screen.WaitForString("]")
	crt.Screen.Synchronous = False
main()

Такі скрипти зазвичай не потрібні, але кількість обладнання – 15 шт. Дозволило прискорити налаштування. Далі налаштовувати обладнання швидше за допомогою SecureCRT Command window.

Налаштування облікового запису для ssh.

Інший приклад. Налаштування також через консоль.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("r")
	crt.Screen.WaitForString("name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.WaitForString(">")
	crt.Screen.Send("sysr")
	crt.Screen.Send("stelnet server enabler")
	crt.Screen.Send("aaar")
	crt.Screen.Send("local-user admin service-type terminal ftp http sshr")
	crt.Screen.Send("quitr")
	crt.Screen.Send("user-interface vty 0 4r")
	crt.Screen.Send("authentication-mode aaar")
	crt.Screen.Send("quitr")
	crt.Screen.Send("quitr")
	crt.Screen.Synchronous = False
main()


Про SecureCRT:Платне ПЗ: від 99 $ (найменша ціна тільки на SecureCRT на один рік)
Офіційний сайт
1 раз купується ліцензія на ПЗ, з підтримкою (для оновлення), потім ПЗ використовується з цією ліцензією необмежений час.

Працює на операційних системах Mac OS X та Windows.

Є підтримка скриптів (ця стаття)
є Командне вікно
Serial/Telnet/SSH1/SSH2/Shell Операційної системи

Джерело: habr.com