
Berdasarkan artikel tersebut,
bot Telegram untuk administrator sistem (artikel ini bukan milik saya, saya baru saja membacanya) ingin berbagi pengalaman membuat bot Telegram di PowerShell untuk mengelola server aplikasi. Akan ada teks, kode, dan beberapa gambar. Kritik konstruktif diterima (yang utama bukan untuk mengatakan "mengapa di PowerShell? Seharusnya ada di perl").
Saya pikir artikel ini akan lebih cocok untuk pendatang baru di PowerShell, tetapi administrator yang berpengalaman dapat melihat sesuatu yang bermanfaat di sini.
Dia mencoba membangun artikel dalam beberapa bagian - dari yang sederhana hingga yang kompleks. Mungkin plagiarisme akan terjadi, hati-hati!
Jadi, kami memiliki kebutuhan untuk mengelola layanan atau aplikasi pada beberapa server (berhenti, mulai), restart server, lihat log dan beberapa informasi lain jika perlu. Semua ini ingin saya lakukan (sebenarnya tidak), berada di kereta bawah tanah, di toko atau bahkan berbaring di sofa, tanpa VPN dan laptop. Dari persyaratan (yang ditulis, tentu saja, di lutut).
- Mudah untuk menambah / mengubah tugas di bot Telegram
- Multitasking atau konkurensi
- Antarmuka manajemen yang intuitif
- Setidaknya keamanan
Pada titik tertentu, diputuskan untuk meletakkan konfigurasi dalam file terpisah - dalam xml kasus kami (di sini seseorang dapat mengatakan bahwa mari kita semua di json, tapi kami melakukannya dalam xml dan puas)
Mari kita mulai dari awal:
Bagian 1: bot telegram sederhana
Kami mencari folder bot (bukan direktori) -
BotFather (@BotFather) di Telegram

Tulis
/ newbotSelanjutnya, Anda perlu mencari nama untuk bot (dalam kasus saya, saya memanggil Haaaabr khusus untuk artikel) dan nama pengguna, yang harus diakhiri dengan "bot" (Haaaabr_bot)
Setelah itu, BotFather akan mengeluarkan token, yang akan kami gunakan:

Kemudian Anda dapat mengunggah gambar untuk bot, letakkan Deskripsi, buat daftar perintah, tapi saya terlalu malas.
Kami membuat bot sederhana yang akan menerima pesan dan meresponsnya.
Saya akan menulis kode PS di bagian dan secara berkala memasukkan kode lengkap untuk referensi.
Untuk referensi, kita akan memerlukan deskripsi panggilan
API Telegram Bot APIKami membutuhkan 2 metode:
getUpdates - menerima pesan dengan bot (skrip)
sendMessage - mengirim pesan dengan bot (skrip) ke pengguna
Di sana, kita melihat bahwa:
Membuat permintaan
Semua pertanyaan ke Telegram Bot API harus dilayani lebih dari HTTPS dan perlu disajikan dalam formulir ini: api.telegram.org/bot<token>/METHOD_NAME
Langkah 1 - terima pesanVariabel
Sekarang kita akan memeriksa apakah ia mengembalikan panggilan ke
$ URL_get Invoke-RestMethod -Uri $URL_get
ok result
-- ------
True {}
Tidak buruk. Mari kita menulis sesuatu ke bot:

Dan baca:
ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
}
Jelas, kami butuh hasil. Saya harus segera mengatakan bahwa kami hanya tertarik pada pesan terakhir dari pengguna, jadi seperti ini:
Sekarang kita perlu mengkonfirmasi bahwa kami menerima pesan. Semua ini dilakukan dengan cara yang sama, melalui metode
getUpdates dengan parameter
ofset :
Secara default, pembaruan yang dimulai dengan pembaruan paling awal yang belum dikonfirmasi dikembalikan. Pembaruan dianggap dikonfirmasi segera setelah getUpdates dipanggil dengan offset yang lebih tinggi daripada pembaruan_idnya
Lakukan
Invoke-RestMethod "$($URL_get)?offset=$($($data.update_id)+1)" -Method Get | Out-Null
Dan kami membuang semuanya ke dalam siklus dengan batas waktu 1 detik:
Sekarang mari kita buat fungsi pembacaan pesan darinya. Karena kita perlu mengembalikan beberapa nilai dari fungsi - kita memutuskan untuk menggunakan HashTable (bernama / array asosiatif)
Langkah 2 - mengirim dataUntuk mengirim pesan, kita memerlukan metode
sendMessage dan
chat_id dan bidang
teks (sisanya opsional
https://core.telegram.org/bots/api#sendmessage ).
Segera fungsi gash
function sendMessage($URL, $chat_id, $text) {
Sekarang dengan menelepon
sendMessage $URL_set <__id> "123"
dapatkan pesan di kereta.
Langkah 3 - Menyatukan SemuanyaDi bawah ini adalah semua kode untuk mengirim dan menerima pesan
Logika lebih lanjut dapat dibangun berdasarkan
$ return.text dan, misalnya,
pernyataan switch :
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 digunakan dalam cmdlet Get-Random, saya tidak bisa menanamkannya dalam kode di artikel, tetapi PS mengerti mereka secara asli

Bagian 2: perlu tombol
Di bot telegram ada opsi untuk menentukan daftar perintah (buka di sini di ikon ini

)
Awalnya, kami melakukan hal itu - ada seperangkat perintah, kami memberikan nama server atau layanan di sana sebagai parameter. Kemudian kami memutuskan bahwa kami perlu bergerak lebih jauh menuju antarmuka yang ramah pengguna dan menghubungkan fungsi tombol.
Digunakan oleh
panggilan sendMessage dengan parameter
reply_markupUntuk fungsionalitas kami, kami menggunakan tipe
InlineKeyboardMarkuphttps://core.telegram.org/bots/api#inlinekeyboardmarkup .
Dari uraian tersebut, bidang
inline_keyboard adalah larik array tombol
(Array Array of InlineKeyboardButton)
Mencoba membuat tombol kirim tes
Kami mendapatkan Galat:
Invoke-RestMethod: {"ok": false, "error_code": 400, "description": "Permintaan Buruk: bidang \" inline_keyboard \ "dari InlineKeyboardMarkup harus menjadi Array of Arays"}
Pada baris: 21 char: 1Memeriksa isi variabel
$ jsonKesimpulan:
{ "reply_markup": { "inline_keyboard": [ "System.Collections.Hashtable System.Collections.Hashtable" ] }, "chat_id": **********, "text": "Test Text", "parse_mode": "Markdown" }
Rupanya, entah bagaimana, objek HashTable ("System.Collections.Hashtable System.Collections.Hashtable") untuk api telegram tidak terlalu mentransmisikan. Sedikit Google dan intinya - ketika mengkonversi ke Json, atur kedalaman konversi
Kami mendapatkan tombol:

Kami membuat fungsi untuk mengirim tombol, kami akan mengirimkan berbagai tombol ke input
Menyatukan semuanya dengan mengubah sedikit saklar blok Sekarang untuk "halo" bot akan mengirimi kami beberapa tombol. Masih memahami tombol mana yang diklik pengguna. Fungsi ps saat ini getUpdates telah memeriksa
if($text)...
Ketika Anda mengklik tombol, tidak ada teks yang dikembalikan, karena itu, Anda perlu memodifikasi fungsinya. Klik pada tombol

Dan jalankan sepotong kode untuk memeriksa isi
$ data
Tidak ada pesan lagi. Sebagai gantinya, sekarang
callback_query . Edit fungsi
Sekarang fungsi mengembalikan
teks jika ada pesan, atau
callback_data jika ada klik tombol. Pada tahap pengujian, mereka menemukan kesalahan saat memanggil:
sendMessage $URL_set $($return.chat_id) $($return.callback_data)
Invoke-RestMethod: {"ok": false, "error_code": 400, "description": "Permintaan Buruk: tidak dapat menguraikan entitas: Tidak dapat menemukan akhir entitas mulai dari byte offset 8"}Karena
parse_mode diatur ke
Markdown , dan teks yang akan dikirim
$return.callback_data = βProject1_CDβ
Anda perlu memformat pesan sebelum mengirim, lebih detail di sini:
https://core.telegram.org/bots/api#formatting-optionsatau hapus garis bawah "_"
Bagian 3: lakukan konfigurasi
Saatnya untuk meletakkan semuanya di konfigurasi. Semuanya sederhana di sini - kami melakukannya 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>
Kami menjelaskan tugas dan menentukan skrip atau perintah untuk setiap tugas.
Kami memeriksa:
[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
Menempatkannya di skrip utama [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text'
Sekarang, jika Anda menulis "halo", bot akan mengembalikan daftar tombol yang sesuai dengan tugas yang dijelaskan dalam file xml. Akan ada perintah atau skrip di callback_data.
Jika Anda melakukan perubahan kosmetik - diinginkan bahwa tombolnya 3-4 per baris, jika tidak mereka tidak sepenuhnya ditampilkan:

Kami akan melakukan 3 tombol per baris (maksimum).
Secara skematis, susunan keyboard akan terlihat seperti ini:

Dengan cara ini:
Tombol [i] - array (asosiatif) dari formulir
$button = @{ "text" = $task.name; callback_data = $task.script}
Baris [1-3] - ini adalah susunan (dari tombol) yang menyimpan susunan tombol (ini penting)
Keyboard - larik Line'ov.
Ubah fungsi
sendKeyboard function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{}
Kami memeriksa:

Naskah akhir [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text'
Bagian 4: penugasan dan multitasking
Saatnya tombol untuk melakukan sesuatu.Untuk multitasking, kami akan menggunakan mekanisme Pekerjaan. Periksa bagian kode ini: $script = "ipconfig" $script_block = { Param($script) ; Invoke-Expression $script } $job_name = "TestJob" Start-Job -ScriptBlock $script_block -ArgumentList $script -Name $job_name | Out-Null
Dan setelah 5 detik kami melakukannya: foreach($job in (Get-Job | Where {$_.State -eq "Completed"} )) { $output = Get-Job -ID $job.Id | Receive-Job $output $job | Remove-Job }
$ output akan mengembalikan ipconfig dengan localhostTambahkan ini ke skrip utama, ke blok callback_data
Dan ini di bawah
Periksa, tangkap kesalahanInvoke-RestMethod: {"ok": false, "error_code": 400, "description": "Permintaan Buruk: pesan terlalu panjang"}Di Internet, kami menemukan informasi bahwa panjang pesan tidak boleh melebihi 4096 karakter. Oke ... $output.Length
mengatakan panjang 39. Kamiberpikir untuk waktu yang lama apa yang salah, sebagai hasilnya, kami mencoba potongan kode ini: $text = $null foreach($string in $output) { $text = "$text`n$string" } sendMessage $URL_set $job.Name $text
Kami mencoba semuanya bersama [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text'
Sekarang mari kita sedikit keamanan.Tambahkan baris baru ke konfigurasi xml, sebut saja pengguna dan tunjukkan ada chat_id dari mereka yang dapat berkomunikasi dengan bot: <system> <token>*********************************</token> <timeout desc="bot check timeout in seconds">1</timeout> <users>111111111, 222222222</users> </system>
Dalam skrip kita akan mendapatkan array pengguna $users = (($xmlConfig.config.system.users).Split(",")).Trim()
Dan periksa if($users -contains $return.chat_id) { ... }
Skrip lengkap [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()
Bagian 5: sebagai kesimpulan
Kami memeriksa fungsionalitas bot - tambahkan skrip di sana yang akan melakukan sesuatu yang berguna.Untuk operasi di server jauh, kami menggunakan Invoke-Command diikuti oleh 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
Dalam hal ini, akun yang menjalankan skrip bot telegram harus memiliki hak yang sesuai pada mesin jarak jauh.Juga, saya tidak menyentuh fungsionalitas logging, tetapi di sini, saya pikir, semuanya sederhana, sesuka hati, semua orang dapat memutuskan apa yang ingin dia login dan apa yang tidak.Tentunya seseorang akan mengalami masalah dalam mengirim pesan> 4096 karakter, tetapi ini diselesaikan oleh Substring dan siklus pengiriman.Dan akhirnya - kendali jarak jauh dari mana saja di dunia (hampir dari mana saja) itu baik, tetapi selalu ada risiko bahwa ada sesuatu yang salah (seseorang yang buruk bisa mendapatkan kendali bot). Untuk kasus ini, kami baru saja menambahkan Keluar dari skrip untuk kata tertentu switch -Wildcard ($return["text"]) { "**" {
Saya memiliki semuanya.