
بناءً على المقالة ، أراد برنامج
Telegram bot الخاص بمسؤول النظام (المقالة ليس مقالاً ، لقد قرأت للتو) مشاركة تجربة إنشاء روبوت Telegram على PowerShell لإدارة خوادم التطبيقات. سيكون هناك نص ورمز وعدد قليل من الصور. النقد البناء هو موضع ترحيب (الشيء الرئيسي هو عدم القول "لماذا على PowerShell؟ كان ينبغي أن يكون على بيرل").
أعتقد أن هذه المقالة ستكون أكثر ملاءمة للقادمين الجدد إلى PowerShell ، ولكن يمكن للمسؤولين ذوي الخبرة رؤية شيء مفيد هنا.
حاول بناء المقال في أجزاء - من البسيط إلى المعقد. ربما سوف يحدث الانتحال ، كن حذرا!
لذلك ، نحن بحاجة إلى إدارة الخدمات أو التطبيقات على عدة خوادم (إيقاف ، بدء) ، إعادة تشغيل الخادم ، إلقاء نظرة على السجلات وبعض المعلومات الأخرى إذا لزم الأمر. كل هذا أريد القيام به (في الواقع لا) ، في مترو الأنفاق ، في المتجر أو حتى الاستلقاء على الأريكة ، بدون VPN وأجهزة الكمبيوتر المحمولة. من المتطلبات (التي كانت مكتوبة ، بالطبع ، على الركبة).
- سهلة لإضافة / تغيير المهام في روبوت Telegram
- تعدد المهام أو التزامن
- واجهة إدارة بديهية
- على الأقل بعض الأمن
في مرحلة ما ، تقرر وضع التهيئة في ملف منفصل - في حالتنا xml (هنا يمكن للشخص أن يقول إن كل شيء في json ، لكننا فعلنا ذلك في xml ورضا)
لنبدأ من البداية:
الجزء 1: روبوت برقية بسيط
نحن نبحث عن مجلد bot (وليس دليل) -
BotFather (BotFather) في Telegram

اكتب
/ newbotبعد ذلك ، عليك أن تجد اسمًا للبوت (في حالتي ، اتصلت Haaaabr خصيصًا للمادة) واسم المستخدم ، والتي يجب أن تنتهي بـ "bot" (Haaaabr_bot)
بعد ذلك ، سيصدر BotFather رمزًا مميزًا ، والذي سنستخدمه:

بعد ذلك يمكنك تحميل صورة للروبوت ، ووضع الوصف ، وإنشاء قائمة من الأوامر ، لكنني كنت كسولًا جدًا.
نحن نصنع روبوتًا بسيطًا يتلقى الرسائل ويستجيب لها.
سأكتب رمز PS في الأجزاء وأدخل الرمز الكامل للمرجع بشكل دوري.
للرجوع إليها ، سنحتاج إلى أوصاف استدعاء
API Telegram Botسنحتاج إلى طريقتين:
getUpdates - تلقي الرسائل عن طريق
الروبوت (البرنامج النصي)
sendMessage - إرسال الرسائل بواسطة
الروبوت (البرنامج النصي) إلى المستخدم
هناك ، نرى أن:
تقديم الطلبات
يجب تقديم جميع الاستفسارات إلى Telegram Bot API عبر HTTPS ويجب تقديمها في هذا النموذج: api.telegram.org/bot<token>/METHOD_NAME
الخطوة 1 - تلقي الرسائلالمتغيرات
الآن سوف نتحقق من أنها
ستعيد مكالمة إلى
$ URL_get Invoke-RestMethod -Uri $URL_get
ok result
-- ------
True {}
ليس سيئا دعنا نكتب شيئا للبوت:

وقراءة:
ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
ok result
-- ------
True {@{update_id=635172027; message=}, @{update_id=635172028; message=}
}
من الواضح أننا نحتاج إلى نتيجة. يجب أن أقول على الفور أننا مهتمون فقط بالرسالة الأخيرة من المستخدم ، مثل هذا:
الآن نحن بحاجة إلى تأكيد أننا تلقينا الرسالة. يتم كل هذا من خلال طريقة
getUpdates مع معلمة
الإزاحة :
بشكل افتراضي ، يتم إرجاع التحديثات التي تبدأ بأقرب تحديث غير مؤكد. يعتبر التحديث مؤكدًا بمجرد استدعاء getUpdates بإزاحة أعلى من update_id الخاص به
فعل
Invoke-RestMethod "$($URL_get)?offset=$($($data.update_id)+1)" -Method Get | Out-Null
ونحن نلقي كل ذلك في دورة مع مهلة من 1 ثانية:
الآن دعونا نجعل رسالة قراءة وظيفة للخروج منه. لأن نحتاج إلى إرجاع العديد من القيم من الوظيفة - قررنا استخدام HashTable (مجموعة المسمى / النقابي)
الخطوة 2 - إرسال البياناتلإرسال رسالة ، نحتاج إلى أسلوب
sendMessage والحقول
النصية و
chat_id (الباقي عبارة عن
https://core.telegram.org/bots/api#sendmessage ) اختياري.
وظيفة الكاش على الفور
function sendMessage($URL, $chat_id, $text) {
الآن عن طريق الاتصال
sendMessage $URL_set <__id> "123"
احصل على رسالة في العربة
الخطوة 3 - وضع كل شيء معاأدناه هو كل رمز لإرسال واستقبال الرسائل
يمكن بناء منطق إضافي على أساس
$ return.text ، على سبيل المثال ،
عبارة التبديل :
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("", "", "", ""))"} }
رمز تعبيري:يتم استخدام الرموز التعبيرية في أمر Get-Random cmdlet ، لكن لا يمكنني تضمينها في الكود في المقالة ، لكن PS يفهمها أصليًا

الجزء 2: أزرار الحاجة
يوجد في telegram bot خيار لتحديد قائمة بالأوامر (يفتح هنا على هذا الرمز

)
في البداية ، لقد فعلنا ذلك تمامًا - كان هناك مجموعة من الأوامر ، لقد تجاوزنا أسماء الخوادم أو الخدمات هناك كمعلمات. ثم قررنا أننا نحتاج إلى المضي قدمًا نحو واجهات سهلة الاستخدام وتوصيل وظائف الأزرار.
يستخدم بواسطة sendMessage
المكالمات مع معلمة
reply_markupللحصول على وظائفنا ، استخدمنا نوع
InlineKeyboardMarkuphttps://core.telegram.org/bots/api#inlinekeyboardmarkup .
من الوصف ، يتبع أن الحقل
inline_keyboard عبارة عن صفيف من مجموعة من الأزرار
(صفيف من صفيف InlineKeyboardButton)
محاولة إجراء اختبار إرسال الأزرار
حصلنا على خطأ:
Invoke-RestMethod: {"ok": false ، "error_code": 400 ، "description": "طلب غير صحيح: field \" inline_keyboard \ "من InlineKeyboardMarkup يجب أن يكون مصفوفة من المصفوفات"}
على الخط: 21 حرفًا: 1التحقق من ما يحتوي عليه متغير
json $الاستنتاج:
{ "reply_markup": { "inline_keyboard": [ "System.Collections.Hashtable System.Collections.Hashtable" ] }, "chat_id": **********, "text": "Test Text", "parse_mode": "Markdown" }
على ما يبدو ، بطريقة ما ، لا يقوم كائن HashTable ("System.Collections.Hashtable System.Collections.Hashtable") الخاص ببرنامج التلغراف بالإرسال. القليل من Google والنتيجة النهائية - عند التحويل إلى Json ، قم بضبط عمق التحويل
نحصل على الأزرار:

نحن نجعل وظيفة لإرسال الأزرار ، وسوف نقدم مجموعة من الأزرار كمدخلات
ضعها جميعًا معًا عن طريق تغيير كتلة التبديل قليلاً الآن من أجل "مرحبًا" ، سيرسلنا الروبوت إلى اثنين من الأزرار. يبقى أن نفهم أي زر نقر المستخدم. وظيفة ps الحالية getUpdates لديها الاختيار ل
if($text)...
عند النقر فوق الزر ، لا يتم إرجاع أي نص ؛ وبالتالي ، تحتاج إلى تعديل الوظيفة. انقر فوق الزر

وتشغيل قطعة من الكود للتحقق من محتويات
البيانات $
لا توجد رسالة تصل بعد الآن. بدلاً من ذلك ، الآن
callback_query . تحرير وظيفة
تقوم الدالة الآن بإرجاع
النص إذا كانت هناك رسالة ، أو
callback_data إذا كان هناك نقرة زر. في مرحلة الاختبار ، وقعوا خطأ عند الاتصال:
sendMessage $URL_set $($return.chat_id) $($return.callback_data)
Invoke-RestMethod: {"ok": false ، "error_code": 400 ، "description": "طلب غير صالح: لا يمكن تحليل الكيانات: لا يمكن العثور على نهاية الكيان بدءًا من بايت 8"منذ
يتم تعيين
parse_mode إلى
تخفيض السعر ، والنص المراد إرسالها
$return.callback_data = “Project1_CD”
تحتاج إلى تنسيق الرسالة قبل الإرسال ، مزيد من التفاصيل هنا:
https://core.telegram.org/bots/api#formatting-optionsأو قم بإزالة الشرطة السفلية "_"
الجزء 3: هل التكوين
حان الوقت لوضع كل شيء في التكوين. كل شيء بسيط هنا - نفعل 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>
وصف المهام وتحديد برنامج نصي أو أمر لكل مهمة.
نتحقق من:
[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
ضعها في النص الرئيسي [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text'
الآن ، إذا كتبت "مرحبًا" ، فسيرجع برنامج الروبوت قائمة الأزرار التي تتوافق مع المهام الموضحة في ملفات xml. سيكون هناك أمر أو برنامج نصي في callback_data.
إذا قمت بإجراء تغييرات تجميلية - من المستحسن أن تكون الأزرار 3-4 لكل سطر ، وإلا فلن يتم عرضها بالكامل:

سنفعل 3 أزرار في كل سطر (الحد الأقصى).
بشكل تخطيطي ، يجب أن تبدو صفيف لوحة المفاتيح بالشكل التالي:

بهذه الطريقة:
زر [i] - صفيف (نقابي) من النموذج
$button = @{ "text" = $task.name; callback_data = $task.script}
السطر [1-3] - هذه صفائف (من أزرار) تخزن صفيفات من الأزرار (هذا مهم)
لوحة المفاتيح - مجموعة من Line'ov.
تعديل وظيفة
sendKeyboard function sendKeyboard($URL, $buttons, $chat_id, $text) { $keyboard = @{}
نتحقق من:

النصي النهائي [xml]$xmlConfig = Get-Content -Path ("c:\Temp\Habr\telegram_bot.xml") $token = $xmlConfig.config.system.token $timeout = $xmlConfig.config.system.timeout.'#text'
الجزء 4: المهام وتعدد المهام
حان الوقت للزر للقيام بالأشياء.لتعدد المهام ، سوف نستخدم آلية الوظيفة. تحقق من هذا الكود: $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 }
يجب أن يُرجع إخراج $ ipconfig مع مضيف محليأضف هذا إلى البرنامج النصي الرئيسي إلى كتلة callback_data
وهذا أدناه
تحقق ، خطأ التقاطInvoke-RestMethod: {"موافق": خطأ ، "error_code": 400 ، "وصف": "طلب غير صحيح: الرسالة طويلة جدًا"}على الإنترنت ، نجد معلومات لا يمكن أن يتجاوز طول الرسالة 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'
الآن دعنا نضع في أمان قليل ،أضف سطرًا جديدًا إلى xml config ، واتصل به للمستخدمين ، وأشر إلى هناك chat_id لأولئك الذين يمكنهم التواصل مع bot: <system> <token>*********************************</token> <timeout desc="bot check timeout in seconds">1</timeout> <users>111111111, 222222222</users> </system>
في البرنامج النصي ، سنحصل على مجموعة المستخدمين $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()
الجزء 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
في هذه الحالة ، يجب أن يكون للحساب الذي سيتم تشغيل البرنامج النصي لـ telegram bot فيه الامتيازات المناسبة على الجهاز البعيد.أيضًا ، لم أتطرق إلى وظيفة التسجيل ، ولكن هنا ، أعتقد ، أن كل شيء بسيط ، حسب الرغبة ، يمكن للجميع تحديد ما يريد تسجيله وما لا.بالتأكيد سيواجه شخص ما مشكلة في إرسال رسالة> 4096 حرفًا ، ولكن يتم حل هذا بواسطة السلسلة الفرعية وحلقة الإرسال.وأخيرًا - يعد التحكم عن بُعد من أي مكان في العالم (من أي مكان تقريبًا) جيدًا ، ولكن هناك دائمًا خطر حدوث خطأ ما (يمكن لأي شخص سيء التحكم في الروبوت). في هذه الحالة ، أضفنا للتو Exit من البرنامج النصي لكلمة معينة switch -Wildcard ($return["text"]) { "**" {
لدي كل شيء.