Telegramm-Bot für das Infrastrukturmanagement

Bild

Basierend auf dem Artikel wollte der Telegramm-Bot für den Systemadministrator (der Artikel gehört nicht mir, ich habe ihn nur gelesen) die Erfahrungen beim Erstellen eines Telegramm-Bot in PowerShell für die Verwaltung von Anwendungsservern teilen. Es wird Text, Code und ein paar Bilder geben. Konstruktive Kritik ist willkommen (Hauptsache nicht "Warum auf PowerShell? Es sollte auf Perl sein").

Ich denke, dass dieser Artikel eher für PowerShell-Neulinge geeignet ist, aber erfahrene Administratoren können hier etwas Nützliches sehen.

Er versuchte, den Artikel in Teilen aufzubauen - von einfach bis komplex. Vielleicht kommt es zu Plagiaten, seien Sie vorsichtig!

Wir müssen also Dienste oder Anwendungen auf mehreren Servern verwalten (stoppen, starten), den Server neu starten, die Protokolle und ggf. einige andere Informationen einsehen. All das möchte ich tun (eigentlich nicht), in der U-Bahn, im Laden oder sogar auf der Couch liegen, ohne VPN und Laptops. Von den Anforderungen (die natürlich am Knie geschrieben wurden).

  • Einfaches Hinzufügen / Ändern von Aufgaben im Telegramm-Bot
  • Multitasking oder Parallelität
  • Intuitive Verwaltungsoberfläche
  • Zumindest etwas Sicherheit

Irgendwann wurde beschlossen, die Konfiguration in einer separaten Datei abzulegen - in unserem Fall in xml (hier kann jemand sagen, dass wir alle in json sind, aber wir haben es in xml gemacht und waren zufrieden).
Fangen wir von vorne an:

Teil 1: Ein einfacher Telegramm-Bot


Wir suchen einen Bot-Ordner (kein Verzeichnis) - BotFather (@BotFather) in Telegram

Botvater

Write / Newbot
Als nächstes müssen Sie einen Namen für den Bot (in meinem Fall habe ich Haaaabr speziell für den Artikel genannt) und einen Benutzernamen eingeben, der auf "bot" (Haaaabr_bot) enden sollte.

Danach stellt BotFather einen Token aus, den wir verwenden werden:

Bild

Dann kannst du ein Bild für den Bot hochladen, Beschreibung eingeben, eine Befehlsliste erstellen, aber ich war zu faul.

Wir machen einen einfachen Bot, der Nachrichten empfängt und darauf reagiert.

Ich werde den PS-Code in Teilen schreiben und in regelmäßigen Abständen den vollständigen Code als Referenz einfügen.

Als Referenz benötigen wir die API- Aufrufbeschreibungen der Telegramm-Bot-API

Wir brauchen 2 Methoden:

getUpdates - Empfangen von Nachrichten per Bot (Skript)
sendMessage - Senden von Nachrichten von einem Bot (Skript) an einen Benutzer

Dort sehen wir, dass:
Anfragen stellen
Alle Abfragen an die Telegramm-Bot-API müssen über HTTPS erfolgen und in der folgenden Form erfolgen: api.telegram.org/bot<token>/METHOD_NAME

Schritt 1 - Nachrichten empfangen
Variablen

# Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" 

Jetzt werden wir überprüfen, ob ein Aufruf von $ URL_get zurückgegeben wird

 Invoke-RestMethod -Uri $URL_get 

ok result
-- ------
True {}


Nicht schlecht Schreiben wir etwas an den Bot:

Hallo

Und lies:

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" Invoke-RestMethod -Uri $URL_get 


ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
}

Offensichtlich brauchen wir Ergebnis. Ich muss gleich sagen, dass wir nur an der letzten Nachricht des Benutzers interessiert sind, also so:

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" $json = Invoke-RestMethod -Uri $URL_get $data = $json.result | Select-Object -Last 1 $data.update_id $data.message.chat.id $data.message.text $data.message.chat.first_name $data.message.chat.last_name $data.message.chat.type $data.message.chat.username 

Jetzt müssen wir bestätigen, dass wir die Nachricht erhalten haben. Dies geschieht jedoch mit der Methode getUpdates mit dem Parameter offset :
Standardmäßig werden Updates zurückgegeben, die mit dem frühesten nicht bestätigten Update beginnen. Ein Update gilt als bestätigt, sobald getUpdates mit einem Offset höher als dessen update_id aufgerufen wird

Tun

 Invoke-RestMethod "$($URL_get)?offset=$($($data.update_id)+1)" -Method Get | Out-Null 

Und wir werfen alles in einen Zyklus mit einem Timeout von 1 Sekunde:

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 while($true) #   { $json = Invoke-RestMethod -Uri $URL_get $data = $json.result | Select-Object -Last 1 $data.update_id $data.message.chat.id $data.message.text $data.message.chat.first_name $data.message.chat.last_name $data.message.chat.type $data.message.chat.username Invoke-RestMethod "$($URL_get)?offset=$($($data.update_id)+1)" -Method Get | Out-Null Start-Sleep -s $timeout } 

Lassen Sie uns nun eine Nachrichtenlesefunktion daraus machen. Weil Wir müssen mehrere Werte von der Funktion zurückgeben - wir haben uns für die Verwendung einer HashTable (named / associative array) entschieden

Skript zum Empfangen von Nachrichten
 # Token $token = "***********************"# Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #$data.update_id $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username #   text  if($text) { # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null # HashTable $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username return $ht } } while($true) #   { #   getUpdates $URL_get Start-Sleep -s $timeout } 



Schritt 2 - Daten senden
Zum Senden einer Nachricht benötigen wir die sendMessage- Methode sowie die Felder chat_id und text (der Rest ist optional https://core.telegram.org/bots/api#sendmessage ).

Sofort Schnittfunktion

 function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } 

Jetzt telefonisch

 sendMessage $URL_set <__id> "123" 

bekomme eine nachricht in den warenkorb

Schritt 3 - Alles zusammenfügen

Nachfolgend finden Sie den gesamten Code zum Senden und Empfangen von Nachrichten

Code anzeigen
 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #$data.update_id $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username #   text  if($text) { # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null # HashTable $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username return $ht } } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } while($true) #   { $return = getUpdates $URL_get if($return) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) } Start-Sleep -s $timeout } 


Weitere Logik kann auf der Basis von $ return.text und zum Beispiel der switch-Anweisung erstellt werden :
 switch -Wildcard ($return["text"]) { "**" { sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } 

Emoji:
emoji wird im Cmdlet "Get-Random" verwendet. Ich konnte sie nicht in den Code des Artikels einbetten, aber PS versteht sie nativ
Holen Sie sich zufällig

Teil 2: brauche Knöpfe


Im Telegramm-Bot gibt es die Möglichkeit, eine Liste von Befehlen anzugeben (wird hier über dieses Symbol geöffnet) Icon )
Am Anfang haben wir genau das getan - es gab eine Reihe von Befehlen, wir haben die Namen von Servern oder Diensten als Parameter übergeben. Dann haben wir beschlossen, dass wir uns weiter in Richtung benutzerfreundlicher Oberflächen bewegen und die Tastenfunktionen miteinander verbinden müssen.

Wird von sendMessage- Aufrufen mit dem reply_markup- Parameter verwendet

Für unsere Funktionalität haben wir den Typ InlineKeyboardMarkup verwendet
https://core.telegram.org/bots/api#inlinekeyboardmarkup .

Aus der Beschreibung folgt, dass das Feld inline_keyboard ein Array aus einem Array von Schaltflächen ist
(Array von Array von InlineKeyboardButton)

Versucht, einen Test zu senden

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" #   callback_data  ,     $button1 = @{ "text" = "Test1"; callback_data = "Test1_CD"} $button2 = @{ "text" = "Test2"; callback_data = "Test2_CD"} $keyboard = @{"inline_keyboard" = @(,@($button1, $button2))} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = ******** #     Telegram ID text = "Test Text" } $json = $ht | ConvertTo-Json Invoke-RestMethod $URL_set -Method Post -ContentType 'application/json; charset=utf-8' -Body $json 

Wir bekommen Fehler:
Invoke-RestMethod: {"ok": false, "error_code": 400, "description": "Bad Request: Feld" inline_keyboard "des InlineKeyboardMarkup sollte ein Array von Arrays sein"}
In der Zeile: 21 Zeichen: 1

Überprüfen, was die Variable $ json enthält

Fazit:

 { "reply_markup": { "inline_keyboard": [ "System.Collections.Hashtable System.Collections.Hashtable" ] }, "chat_id": **********, "text": "Test Text", "parse_mode": "Markdown" } 

Anscheinend überträgt das HashTable-Objekt ("System.Collections.Hashtable System.Collections.Hashtable") für die Telegramm-API nicht sehr viel. Ein bisschen Google und das Endergebnis - beim Konvertieren in Json legen Sie die Konvertierungstiefe fest

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" #   callback_data  ,     $button1 = @{ "text" = "Test1"; callback_data = "Test1_CD"} $button2 = @{ "text" = "Test2"; callback_data = "Test2_CD"} $keyboard = @{"inline_keyboard" = @(,@($button1, $button2))} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = ******** text = "Test Text" } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL_set -Method Post -ContentType 'application/json; charset=utf-8' -Body $json 

Wir bekommen die Knöpfe:

Schaltflächen

Wir machen eine Funktion zum Senden von Buttons, wir werden ein Array von Buttons als Eingabe übergeben

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" #   callback_data  ,     $button1 = @{ "text" = "Test1"; callback_data = "Test1_CD"} $button2 = @{ "text" = "Test2"; callback_data = "Test2_CD"} $buttons = ($button1, $button2) function sendKeyboard($URL, $buttons) { $keyboard = @{"inline_keyboard" = @(,$buttons)} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = ******** text = "Test Text" } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL_set -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } sendKeyboard $URL_set $buttons 

Alles zusammenfügen, indem Sie den Schalterblock ein wenig ändern
 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #$data.update_id $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username #   text  if($text) { # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null # HashTable $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username return $ht } } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{"inline_keyboard" = @(,$buttons)} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get if($return) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) write-host "$($return["chat_id"])" switch -Wildcard ($return["text"]) { "**" { $button1 = @{ "text" = "Project1"; callback_data = "Project1_CD"} $button2 = @{ "text" = "Project2"; callback_data = "Project2_CD"} $buttons = ($button1, $button2) $text = "Available projects:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } Start-Sleep -s $timeout } 


Jetzt schickt uns der Bot für "Hallo" ein paar Knöpfe. Es bleibt zu verstehen, auf welche Schaltfläche der Benutzer geklickt hat. Die aktuelle ps-Funktion getUpdates hat eine Prüfung auf

 if($text)... 

Wenn Sie auf die Schaltfläche klicken, wird kein Text zurückgegeben und Sie müssen die Funktion entsprechend ändern. Klicken Sie auf die Schaltfläche

Druckknopf

Führen Sie einen Code aus, um den Inhalt von $ data zu überprüfen

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 $data <# $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username #   text  if($text) { # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null # HashTable $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username return $ht } #> } getUpdates $URL_get 

Es kommt keine Nachricht mehr an. Stattdessen jetzt callback_query . Bearbeitungsfunktion

 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } getUpdates $URL_get 

Jetzt gibt die Funktion Text zurück, wenn eine Nachricht vorliegt , oder callback_data, wenn auf eine Schaltfläche geklickt wurde. In der Testphase haben sie beim Aufrufen einen Fehler festgestellt:

 sendMessage $URL_set $($return.chat_id) $($return.callback_data) 

Invoke-RestMethod: {"ok": false, "error_code": 400, "description": "Ungültige Anforderung: Entitäten können nicht analysiert werden: Ende der Entität ab Byte-Offset 8 kann nicht gefunden werden"}

Da parse_mode auf Markdown gesetzt ist , soll auch der Text gesendet werden

 $return.callback_data = “Project1_CD” 

Sie müssen die Nachricht vor dem Senden formatieren. Weitere Informationen finden Sie hier:
https://core.telegram.org/bots/api#formatting-options
oder entfernen Sie den Unterstrich "_"

Letztes Drehbuch
 # Token $token = "***********************" # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" # timeout sec $timeout = 1 function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #   $text = $null $callback_data = $null #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{"inline_keyboard" = @(,$buttons)} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get #$return #    if($return.text) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) write-host "$($return["chat_id"])" switch -Wildcard ($return["text"]) { "**" { $button1 = @{ "text" = "Project1"; callback_data = "Project1CD"} $button2 = @{ "text" = "Project2"; callback_data = "Project2CD"} $buttons = ($button1, $button2) $text = "Available projects:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } #      elseif($return.callback_data) { sendMessage $URL_set $($return.chat_id) $($return.callback_data) } Start-Sleep -s $timeout } 


Teil 3: Mach die Konfiguration

Es ist Zeit, alles in die Konfiguration zu setzen. Hier ist alles einfach - wir machen xml:

 <config> <system> <token>***********************</token> <timeout desc="bot check timeout in seconds">1</timeout> </system> <tasks> <task name=" " script="c:\Temp\Habr\reboot_all.ps1"></task> <task name=" " script="c:\Temp\Habr\status.ps1"></task> <task name="ipconfig1" script="ipconfig"></task> <task name="ipconfig2" script="ipconfig"></task> <task name="ipconfig3" script="ipconfig"></task> <task name="ipconfig4" script="ipconfig"></task> <task name="ipconfig5" script="ipconfig"></task> </tasks> </config> 

Wir beschreiben Aufgaben und geben für jede Aufgabe ein Skript oder einen Befehl an.
Wir prüfen:

 [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text' foreach($task in $xmlConfig.config.tasks.task) { $task.name #   $task.script #  } 

Putting es in das Hauptskript
 [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text' # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #   $text = $null $callback_data = $null #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{"inline_keyboard" = @(,$buttons)} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get #    if($return.text) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) write-host "$($return["chat_id"])" switch -Wildcard ($return["text"]) { "**" { #   $buttons = @() foreach($task in $xmlConfig.config.tasks.task) { $button = @{ "text" = $task.name; callback_data = $task.script} $buttons += $button } $text = "Available tasks:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } #      elseif($return.callback_data) { sendMessage $URL_set $($return.chat_id) $($return.callback_data) } Start-Sleep -s $timeout } 


Wenn Sie nun "Hallo" schreiben, gibt der Bot eine Liste von Schaltflächen zurück, die den in XML-Dateien beschriebenen Aufgaben entsprechen. In callback_data gibt es einen Befehl oder ein Skript.

Wenn Sie kosmetische Änderungen vornehmen, ist es wünschenswert, dass die Schaltflächen 3-4 pro Zeile waren, andernfalls werden sie nicht vollständig angezeigt:

Tastatur

Wir werden maximal 3 Buttons pro Zeile machen.

Schematisch sollte das Tastatur-Array so aussehen:

Tastatur

Auf diese Weise:
Button [i] - ein Array (assoziativ) des Formulars

 $button = @{ "text" = $task.name; callback_data = $task.script} 

Zeile [1-3] - das sind Arrays (von Buttons), die Arrays von Buttons speichern (das ist wichtig)
Keyboard - eine Reihe von Line'ov.

Ändern Sie die sendKeyboard- Funktion

 function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{} #    ArrayList, .       -   $lines = 3 $buttons_line = New-Object System.Collections.ArrayList for($i=0; $i -lt $buttons.Count; $i++) { #     (line).    3 -  line  keyboard $buttons_line.Add($buttons[$i]) | Out-Null #   -      0 if( ($i + 1 )%$lines -eq 0 ) { #     keyboard $keyboard["inline_keyboard"] += @(,@($buttons_line)) $buttons_line.Clear() } } #     $keyboard["inline_keyboard"] += @(,@($buttons_line)) #$keyboard = @{"inline_keyboard" = @(,$buttons)} $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } 

Wir prüfen:

Keyboard_Telegram

Letztes Drehbuch
 [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text' # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #   $text = $null $callback_data = $null #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{} #    ArrayList, .       -   $lines = 3 $buttons_line = New-Object System.Collections.ArrayList for($i=0; $i -lt $buttons.Count; $i++) { #     (line).    3 -  line  keyboard $buttons_line.Add($buttons[$i]) | Out-Null #   -      0 if( ($i + 1 )%$lines -eq 0 ) { #     keyboard $keyboard["inline_keyboard"] += @(,@($buttons_line)) $buttons_line.Clear() } } #     $keyboard["inline_keyboard"] += @(,@($buttons_line)) $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get #$return.text = "" #    if($return.text) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) switch -Wildcard ($return["text"]) { "**" { #   $buttons = @() foreach($task in $xmlConfig.config.tasks.task) { $i++ $button = @{ "text" = $task.name; callback_data = $task.script} $buttons += $button } $text = "Available tasks:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } #      elseif($return.callback_data) { #sendMessage $URL_set $($return.chat_id) $($return.callback_data) write-host "$($return.chat_id) $($return.callback_data)" } Start-Sleep -s $timeout } 


4:


.

Job'. :

 $script = "ipconfig" $script_block = { Param($script) ; Invoke-Expression $script } $job_name = "TestJob" Start-Job -ScriptBlock $script_block -ArgumentList $script -Name $job_name | Out-Null 

5 :
 foreach($job in (Get-Job | Where {$_.State -eq "Completed"} )) { $output = Get-Job -ID $job.Id | Receive-Job $output $job | Remove-Job } 

$output ipconfig localhost

, callback_data

 #      elseif($return.callback_data) { $script = $($return.callback_data) $job_name = $($return.chat_id) $script_block = { Param($script) ; Invoke-Expression $script } # Job Start-Job -ScriptBlock $script_block -ArgumentList $script -Name $job_name | Out-Null } 



 # ,  job'   foreach($job in (Get-Job | Where {$_.State -eq "Completed"} )) { $output = Get-Job -ID $job.Id | Receive-Job #   ,   job sendMessage $URL_set $job.Name $output $job | Remove-Job #     $text = "Available tasks:" sendKeyboard $URL_set $buttons $job.Name $text } 

, error
Invoke-RestMethod: {«ok»:false,«error_code»:400,«description»:«Bad Request: message is too long»}

, 4096 . …

 $output.Length 
39
, :

 $text = $null foreach($string in $output) { $text = "$text`n$string" } sendMessage $URL_set $job.Name $text 

 [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text' # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #   $text = $null $callback_data = $null #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{} $lines = 3 #    ArrayList, .       -   $buttons_line = New-Object System.Collections.ArrayList for($i=0; $i -lt $buttons.Count; $i++) { #     (line).    3 -  line  keyboard $buttons_line.Add($buttons[$i]) | Out-Null #   -      0 if( ($i + 1 )%$lines -eq 0 ) { #     keyboard $keyboard["inline_keyboard"] += @(,@($buttons_line)) $buttons_line.Clear() } } #     $keyboard["inline_keyboard"] += @(,@($buttons_line)) $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get #$return.text = "" #    if($return.text) { # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) switch -Wildcard ($return["text"]) { "**" { #   $buttons = @() foreach($task in $xmlConfig.config.tasks.task) { $i++ $button = @{ "text" = $task.name; callback_data = $task.script} $buttons += $button } $text = "Available tasks:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } #      elseif($return.callback_data) { $script = $($return.callback_data) $job_name = $($return.chat_id) write-host "$script $job_name" $script_block = { Param($script) ; Invoke-Expression $script } # Job Start-Job -ScriptBlock $script_block -ArgumentList $script -Name $job_name | Out-Null } # ,  job'   foreach($job in (Get-Job | Where {$_.State -eq "Completed"} )) { $output = Get-Job -ID $job.Id | Receive-Job $text = $null foreach($string in $output) { $text = "$text`n$string" } #   ,   job sendMessage $URL_set $job.Name $text $job | Remove-Job #     $text = "Available tasks:" sendKeyboard $URL_set $buttons $job.Name $text } Start-Sleep -s $timeout } 


Output

« »

xml , users chat_id , :

  <system> <token>*********************************</token> <timeout desc="bot check timeout in seconds">1</timeout> <users>111111111, 222222222</users> </system> 

users

 $users = (($xmlConfig.config.system.users).Split(",")).Trim() 



  if($users -contains $return.chat_id) { ... } 

 [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text' $users = (($xmlConfig.config.system.users).Split(",")).Trim() # Telegram URLs $URL_get = "https://api.telegram.org/bot$token/getUpdates" $URL_set = "https://api.telegram.org/bot$token/sendMessage" function getUpdates($URL) { $json = Invoke-RestMethod -Uri $URL $data = $json.result | Select-Object -Last 1 #   $text = $null $callback_data = $null #    if($data.callback_query) { $callback_data = $data.callback_query.data $chat_id = $data.callback_query.from.id $f_name = $data.callback_query.from.first_name $l_name = $data.callback_query.from.last_name $username = $data.callback_query.from.username } #   elseif($data.message) { $chat_id = $data.message.chat.id $text = $data.message.text $f_name = $data.message.chat.first_name $l_name = $data.message.chat.last_name $type = $data.message.chat.type $username = $data.message.chat.username } $ht = @{} $ht["chat_id"] = $chat_id $ht["text"] = $text $ht["f_name"] = $f_name $ht["l_name"] = $l_name $ht["username"] = $username $ht["callback_data"] = $callback_data # confirm Invoke-RestMethod "$($URL)?offset=$($($data.update_id)+1)" -Method Get | Out-Null return $ht } function sendMessage($URL, $chat_id, $text) { #  HashTable,       $ht = @{ text = $text #    Markdown parse_mode = "Markdown" chat_id = $chat_id } #      json $json = $ht | ConvertTo-Json #   Invoke-RestMethod,        Invoke-WebRequest # Method Post - ..  ,   Get Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json | Out-Null } function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{} $lines = 3 #    ArrayList, .       -   $buttons_line = New-Object System.Collections.ArrayList for($i=0; $i -lt $buttons.Count; $i++) { #     (line).    3 -  line  keyboard $buttons_line.Add($buttons[$i]) | Out-Null #   -      0 if( ($i + 1 )%$lines -eq 0 ) { #     keyboard $keyboard["inline_keyboard"] += @(,@($buttons_line)) $buttons_line.Clear() } } #     $keyboard["inline_keyboard"] += @(,@($buttons_line)) $ht = @{ parse_mode = "Markdown" reply_markup = $keyboard chat_id = $chat_id text = $text } $json = $ht | ConvertTo-Json -Depth 5 Invoke-RestMethod $URL -Method Post -ContentType 'application/json; charset=utf-8' -Body $json } while($true) #   { $return = getUpdates $URL_get if($users -contains $return.chat_id) { #    if($return.text) { #write-host $return.chat_id # http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons #sendMessage $URL_set $return.chat_id (Get-Random("", "", "", "")) switch -Wildcard ($return["text"]) { "**" { #   $buttons = @() foreach($task in $xmlConfig.config.tasks.task) { $i++ $button = @{ "text" = $task.name; callback_data = $task.script} $buttons += $button } $text = "Available tasks:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } } #      elseif($return.callback_data) { $script = $($return.callback_data) $job_name = $($return.chat_id) write-host "$script $job_name" $script_block = { Param($script) ; Invoke-Expression $script } # Job Start-Job -ScriptBlock $script_block -ArgumentList $script -Name $job_name | Out-Null } # ,  job'   foreach($job in (Get-Job | Where {$_.State -eq "Completed"} )) { $output = Get-Job -ID $job.Id | Receive-Job $text = $null foreach($string in $output) { $text = "$text`n$string" } #   ,   job sendMessage $URL_set $job.Name $text $job | Remove-Job #     $text = "Available tasks:" sendKeyboard $URL_set $buttons $job.Name $text } } else { if($return.text) { sendMessage $URL_set $return.chat_id "  ?    !" } } Start-Sleep -s $timeout } 


5:


– , -
Invoke-Command Write-Output

 $hostname = "hostname" $service = "MSSQLSERVER" $output = Invoke-Command -ComputerName $hostname -ScriptBlock{param($service); (Get-Service -Name $service).Status} -ArgumentList $service write-output $output.Value 

, , - - .

, , , , , , .

- > 4096 , Substring .

– ( ) , , - ( - ). Exit

  switch -Wildcard ($return["text"]) { "**" { #   $buttons = @() foreach($task in $xmlConfig.config.tasks.task) { $i++ $button = @{ "text" = $task.name; callback_data = $task.script} $buttons += $button } $text = "Available tasks:" $chat_id = $return.chat_id sendKeyboard $URL_set $buttons $chat_id $text #sendMessage $URL_set $return.chat_id ", $($return["f_name"])" } "* ?*" { sendMessage $URL_set $return.chat_id "" } "!" {sendMessage $URL_set $return.chat_id "bb" ; Exit} default {sendMessage $URL_set $return.chat_id "$(Get-Random("", "", "", ""))"} } 

.

Source: https://habr.com/ru/post/de483660/


All Articles