Телеграмм-бот для системных администраторов. Это ни в коем случае не готовый проект, в нем есть над чем поработать. Это полуфабрикат и набор приемов который каждый админ может подпиливать под свои разные задачи.


В статье содержатся примеры нескольких ботов и примеры работы с апи телеграмм из powershell.

Тут содержится инфо как зарегать бота и получить токен
Прежде чем продолжать у вас должен быть токен бота, чтобы зарегистрировать своего ботика и получить токен нужно найти пользователя @BotFather и написать ему. Нас интересует команда /newbot после чего потребуется наименование и имя бота, можете писать все что хотите главное в конце приставьте _bot. Когда имя будет подобрано вам BotFather вернет вам токен и ссылку на бота для быстрого добавления. На этом бота регистрация бота заканчивается.

Для быстрого добавления бота и чтобы было возможно быстро добавить его к себе лучше всего использовать специальную ссылку начинающуюся с символа @, взять его можно в инфо:




если такую ссылку комуто переслать то он может просто кликнуть по ней чтобы открыть чат с вашим ботом

Готовые шаблоны админботов


Простой бот
Плюсы:

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

Минусы:

  • слишком простая авторизация. Пароль останется в чате на устройстве. Не может отличить устройства

скачать простого бота можно вот отсюда, в архиве содержится: 1. хелп с примерами разметки текста; 2. исходник

Для запуска нужно получить токен бота у BotFather как описывается в начале статьи и прописать в переменную $token скрипта. Работать должно сразу.



Функционал добавлять в функцию logic

Сложный бот
Плюс:

  • Небольшой — всего около 450 строк
  • Может исполнять команды описанные в функции logic
  • Может получать и отправлять сообщения
  • Может принимать файлы
  • Есть проверка по паролю, может дополнительно проверять chat_id
  • Ведет лог присланых команд
  • Может открывать несколько сессий для одновременной работы (реализовано не полностью. На последнем этапе прикручивалась консоль, если работать в ней то у других пользователей будет зависание и может быть кик по таймауту.

Функционал который был реализован для примера:

  • Может принимать файлы, складывает их в папочку
  • Может показывать файлы из папочки
  • Может удалять файлы из папки загрузки
  • Может запускать файл на исполнение (посредством start-process)
  • Показывает список серверов с которым производится работа (просто список имен в текстовом файле)
  • Пингует серверы из списка и показывает какие из них онлайн
  • Отключает компы из списка
  • Показывает пользователей залогинившихся на терминал, делает вызов внешнего скрипта (нужно установить на терминал PSTerminalServices)
  • Делает logoff пользователя на терминале. Входишь в режим консоли и потом пишешь имена пользователей (нужно установить на терминал PSTerminalServices)
  • Делает скриншот того компа на котором запущен (но не передает обратно)
  • Открывает ssh-сессию с устройством в сети и переходит в режим ввода команд (для примера кредиталы и адрес жестко зашиты в скрипт. Для работы требует установки на машину с которой будет вестись управление модуля работы с ssh poshSSH)

Из того, что не было реализовано, но хотелось бы:

  • Обратная передача файлов (напишите кто знает как это сделать через powershell)
  • Неполноценная поддержка многопользовательской работы
  • Неполноценный режим консоли

Скачать бота можно вот отсюда, в архиве содержится:
1. хелп с примерами разметки текста;
2. конфигурационный файл config.csv;
3. сам бот — abormot.ps1;
4. набор вспомогательный файлов;
5. список компов для работы в текстовом файле ping-list.txt

Для запуска нужно получить токен бота у BotFather как описывается в начале статьи и прописать в конфигурационном файле config.csv. Работать должно сразу.



Функционал добавлять в функцию logic

Бот самообслуживания, делающий Unlock учеток в домене
В некоторых организациях по требованиям иб если пароль введен неверное определенное количество раз то лочится учетная запись на определенное время. Чтобы снять лок пользователь должен позвонить админу. Этот бот сделан так что ему можно написать имя учетной записи и он ее разблокирует, но не более 3х раз в сутки. При превышении лимита он перенаправит пользователя к системному администратору и отправит оповещение ему в чат.

Скачать бота можно вот отсюда.

Для запуска нужно получить токен бота у BotFather прописать токен в переменную $token. Выставить номер чата админа в $adminChatID. Прописать адрес доменной машины и кредиталы к ней:



Я встроил в примере функцию unlock прямо в скрипт, для постоянного использования лучше создать реакцию на событие в журнале и самому генерировать это событие. По событию будет запускаться скрипт unlock из места которое доступно только админам, так вы не забудете пароль от домена в скрипте. Это важно.

Бот, принимающий файлы от знакомых ему пользователей
Например нам нужно пробрасывать в общий ресурс фотографии от пользователей на выезде, или просто принимать файлы и знать от кого они пришли и кому отправить. Ниже пример бота принимающего фотографии от знакомых ему пользователей

Скачать бота можно вот отсюда.

Для запуска нужно получить токен бота у BotFather прописать токен в переменную $token, прописать ваш чат в switch 235 строки. Работать должно сразу. Не забудьте добавить нужный вам чат в switch

Как работать с bot api


1. Принять сообщение


Нужно выполнить Invoke-WebRequest на адрес

https://api.telegram.org/bot{Токен}/getUpdates?offset={порядковый ID сообщения}&timeout={время ожидания перед возвратом в секундах}

{Токен} — токен бота полученный от BotFather
{порядковый ID сообщения} — для первого сообщения 0, для последующих номер последнего + 1. Если указывать последний номер то будете получать при каждом обращении последнее сообщение.
{время ожидания перед возвратом в секундах} — время которое телеграмм подождет ответа если его нет прежде чем вернуть обратно пустую структуру. Годится для создания задержки в боте. Я использовал в ботиках задержку в 1 секунду чтобы не ждать на отладке.
на выходе получим структуру JSON которую парсим при помощи ConvertFrom-Json

Листинг кода №1
$ChatTimeout = 1
$UpdateId = 0
$token = "bot token"

$URL = "https://api.telegram.org/bot$token/getUpdates?offset=$UpdateId&timeout=$ChatTimeout"

$Request = Invoke-WebRequest -Uri $URL -Method Get
$content = ConvertFrom-Json $Request.content

# если на выходе 2 и более результатов возьмем только последний
$str = $content.result | select -First 1
$str = ($str).message

$props = [ordered]@{  
                        ok = $content.ok
                        UpdateId = ($str).update_id
                        Message_ID = $str.message_id
                        first_name = ($str.from).first_name
                        last_name = ($str.from).last_name
                        chat_id = ($str.chat).id
                        text = $str.text
                       }
$obj = New-Object -TypeName PSObject -Property $props
$obj

На выходе в объекте $obj будет сообщение и от кого оно пришло

2. Скачать файл


Если передается файл то в структуре JSON будут переданы дополнительные параметры. Чтобы получить файл нужно вытащить file_id из сообщения, затем обратится по адресу:

https://api.telegram.org/bot{token}/getFile?file_id={file_id из сообщения}

Запрос вернет структуру JSON содержащую путь для скачивания. Далее скачиваем файл по ссылке

https://api.telegram.org/file/bot{token}/{file_path}

Предположим что нам передали файл, тогда код для его скачивания будет выглядеть так:


$ChatTimeout = 1
$UpdateId = 0
$token = "bot token"
$Path = "c:\"

##### Получаем сообщение как обычно
$URL = "https://api.telegram.org/bot$token/getUpdates?offset=$UpdateId&timeout=$ChatTimeout"

$Request = Invoke-WebRequest -Uri $URL -Method Get
$content = ConvertFrom-Json $Request.content

# если на выходе 2 и более результатов возьмем только последний
$str = $content.result | select -First 1
$str = ($str).message

##### Если в сообщение передается файл то будут дополнительные поля
# так например мы можем узнать что нам передали картинку
if ( $($str.document).mime_type -eq "image/jpeg" ) {  $isJPG = $true  }

##### Если есть file_name то значит там чтото лежит
# документ на скачивание есть?
if ( $($str.document).file_name -ne $null ) {
        ### разные данные например для логирования
        $DocFileName = ($str.document).file_name
        $DocFileID = ($str.document).file_id
        $DocFileSize = ($str.document).file_size

        # получаем сылку на файл исполняя команду бота /getFile
        $URL = "https://api.telegram.org/bot$token/getFile?file_id=$DocFileID"
        $RequestFile = Invoke-WebRequest -Uri $URL

        ### в $RequestFile если все верно содержится ссылка на скачивание
        foreach ( $JSON in $((ConvertFrom-Json $RequestFile.Content).result) ) {
            $FilePath = $json.file_path
            $URL = "https://api.telegram.org/file/bot$token/$FilePath"
            $FilePath = Split-Path -Leaf $FilePath
            $OutputFile = "$Path\$FilePath"

            # качаем без проверки
            Invoke-WebRequest -Uri $URL -OutFile $OutputFile
        }
}

3. Написать что-нибудь


Телеграмм-бот поддерживает 2 режима разметки текста markdown и html.

Внимание: в html-режиме тэг br не поддерживается

Примеры markdown разметки
*bold text* — жирный текст
_italic text_ — наклонный текст
[text](http://www.example.com/) — ссылка
`inline fixed-width code` — фиксированный

текстовый блок
```text
pre-formatted fixed-width code block
```

Для переноса строк используйте последовательность %0A

Пример отправки сообщения


$token = "ваш токен"
$сhatid = "ID чата в который нужно послать сообщение"
$text = "привет habr"

$payload = @{ "parse_mode" = "Markdown"; "disable_web_page_preview" = "True" }

$URL = "https://api.telegram.org/bot$token/sendMessage?chat_id=$сhatid&text=$text"

$request = Invoke-WebRequest -Uri $URL -Method Post `
                              -ContentType "application/json; charset=utf-8" `
                              -Body (ConvertTo-Json -Compress -InputObject $payload)

Если данный код даст ошибку например при отправке строки вот такого типа:


"$FDownload : file name is ""$($JSON.file_path)""; size $($json.file_size) kb"

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


$token = "ваш токен"
$chat_id = "ID chata"
$text = "сообщение"
$markdown = $true

$preview_mode = "True" 
if ($markdown) { $markdown_mode = "Markdown" } else {$markdown_mode = ""}

$payload = @{   "chat_id" = $chat_id;
                    "text" = $text
                    "parse_mode" = $markdown_mode;
                    "disable_web_page_preview" = $preview_mode;
                }

$URL = "https://api.telegram.org/bot$token/sendMessaget"

$request = Invoke-WebRequest -Uri $URL `
                -Method Post -ContentType "application/json; charset=utf-8" `
                -Body (ConvertTo-Json -Compress -InputObject $payload)

Если кто знает, как закачать файл обратно — скиньте, я дополню.
Поделиться с друзьями
-->

Комментарии (23)


  1. GennPen
    21.12.2016 23:26

    «Написать удаленное управление и мониторинг за сервером» — по-моему это первая мысль приходит сисадмину на вопрос: «Какого первого бота написать для Telegram?»


  1. riot26
    21.12.2016 23:29
    +9

    Почему код в архиве и вконтактике, если есть гитхаб (или даже gist)?


    1. KaneUA
      22.12.2016 01:02
      +6

      По той же причине, что бот для телеграма, когда есть терминал.


      1. arvitaly
        22.12.2016 01:31

        Не скажите, терминал есть не везде, а телеграм везде.


        1. NorthDakota
          22.12.2016 02:28
          +2

          А интернет из воздуха можно вырабатывать


        1. pak-nikolai
          22.12.2016 08:32

          вырубать компы при проверке можно, прикрутить функцию из за которой тебя дергают на объект по ночам или с гостей. Репорты о состояниях и какихто авариях можно прикрутить


      1. medaved
        22.12.2016 08:28

        Ну терминал это же сложно, нужно руками команды вбивать. Используя бота, это все можно отмести, и одним пальцем пытаться угадать, как поведет себя система в той или иной ситуации. И именно по этому в этом вопросе я выбиру консоль, а вот иметь справочник по нужной тебе теме в телеграме я был бы рад. Посмотреть состояние "умного дома", это очень удобно! Но компенсировать консоль сервера, нет я не выберу телеграмме! Хотя заиметь полноценное ssh, в окне чата бота тоже был рад.


        1. pak-nikolai
          22.12.2016 08:31

          а он может это делать, нужно только в скрипте кредиталы указать, он отправляет присланую команды по ssh, ждет 1 секунду, забирает ответ и отправляет обратно. Если ssh сессию установит не удается то и в режим не войдет


    1. pak-nikolai
      22.12.2016 08:31

      потому что я еще не освоил гитхаб )


      1. kAIST
        22.12.2016 11:51
        +2

        Это не страшно. Если вам нужно просто сделать так, чтоб остальным было удобно, то просто создаёте репозитарий из веб интерфейса и создаёте/загружаете файлы ручками.
        Следующий этап, это официальный клиент (есть под windows) с GUI. Там все очень просто. Достаточно один раз где то прочитать что вообще такое система контроля версий, и знать базовые вещи (комит, бранч и пр.).
        Потом и глазом не успеете моргнуть, как начнёте использовать систему контроля версий даже для своих локальный поделок.


  1. Kondra007
    22.12.2016 02:53

    Расскажите, пожалуйста, как через этот [вырезано] Powershell загрузить в Telegram изображение? (Bot API). С текстом проблем нет, но изображение — никак не получается, в гугле ответ не находится тоже.


    1. pak-nikolai
      22.12.2016 09:51

      это можно сделать из пхп вот таким образом:

      $url  = $apiURL. "sendPhoto?chat_id=" . $chatID";
        $post_fields = array('chat_id'   => $chatID,
        'caption' => 'Подпись под картинкой',
              'photo'     => new CURLFile(realpath('/img/1.png'))
        );
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
              "Content-Type:multipart/form-data"
        ));
        curl_setopt($ch, CURLOPT_URL, $url); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); 
        $output = curl_exec($ch);
      


      на c# есть примеры, но как это выглядит именно на пошике запихать файл в структуру которая передается через post?

      вообще удобная тема, есть пользователи которые на выезде и им нужно забрасывать быстро фотографии на терминал, раньше это вообще никак не реализовывалось, а тут красота — записал сотку в бота, поставил телеграмм, объяснил пользователю что у него будет отжираться интернет и он убежал в поля.
      Или аварийное отключение, или репорт о состоянии служб на терминалах которые никогда не отключаются.

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

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


      1. Kondra007
        22.12.2016 12:16

        Большое спасибо, но вопрос был именно про Powershell (который у Вас в статье), и ответ про PHP, увы, не отвечает на него.
        У Вас статья про работу с Bot API в Powershell, Вы можете ответить на вопрос: "Как через Powershell отправить локальное изображение с помощью Bot API"? (речь конкретно про метод sendPhoto)


        1. pak-nikolai
          22.12.2016 12:59

          ну я и говорю что на других языках реализация есть, надо именно на пошике разобраться как это делать. Если что найдете скиньте пожалуйста я в статью допишу а то прям не хватает отправки файлов


  1. shutkarmannbii
    22.12.2016 09:51

    а у меня одного ssh так сказать весит бота? То есть сессию он отрыл все хорошо, но не принимает команды и в консольке просто цикл обработки. а то я что то не силен в ps


    1. pak-nikolai
      22.12.2016 09:56

      вы установили модуль posh-ssh?
      если нет то скачать можно так:

      iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev")
      


      проверьте работает ли на той машине с которой запускаете бота

      как проверить работает ли описывается тут: https://habrahabr.ru/post/314990/


      1. shutkarmannbii
        22.12.2016 12:10

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


        1. pak-nikolai
          22.12.2016 12:22

          спасибо нашел баг не скопипастил 1 строку

          нужно вставить в цикл while в 478 строку

          $ConsoleMsg = Bot-Listen -ChatTimeOut $ChatTimeOutSeconds -UpdateId $botUpdateId
          

          он не получал сообщения из чата и циклился

          сейчас перезалью исходники


          1. shutkarmannbii
            22.12.2016 13:12

            на здоровье, прям вот чувствовал что до него не доходит ничего. Спасибо за бота
            Все завелось, вот только как то странно приходят ответы, толи у меня большая задержка, толи что — но сообщения приходят с опозданием на 1 команду… забавный эффект


            1. pak-nikolai
              22.12.2016 13:20

              переставить нужно опрос ssh, такое бывает. Однажды при работе с сетевым устройством через SSH у меня был случай что оно как бы подтупливало и надо было задержку делать перед read

              замените код в районе 490 строки с

                                              if ( $text.length -gt 0 ) {
                                                  Start-Sleep -Seconds 1
                                                  $ssh.WriteLine( $text )
                                                  $response = $ssh.read()
                                                  BotSay -text $response
                                              }
              


              на такую
                                              if ( $text.length -gt 0 ) {
                                                  $ssh.WriteLine( $text )
                                                  Start-Sleep -Seconds 2
                                                  $response = $ssh.read()
                                                  BotSay -text $response
                                              }
              


  1. ookay
    22.12.2016 13:24
    -1

    Неплохо.


  1. Fanta
    22.12.2016 23:33

    Сделайте бота который будет по имени сервера/пк выводить его аптайм и прочую инфу!


  1. malay
    26.12.2016 06:22

    Большое Вам Админское Спасибо!