قالب یک ربات تلگرام ساده برای دانش آموزان کلاس 7-9 با استفاده از Powershell

در خلال صحبت با یکی از دوستان، ناگهان متوجه شدم که به بچه های کلاس 8 تا 10 مدرسه آنها اصلا برنامه نویسی آموزش داده نمی شود. ورد، اکسل و همه چیز. بدون لوگو، حتی پاسکال، حتی VBA برای اکسل.

من خیلی تعجب کردم، اینترنت را باز کردم و شروع به خواندن کردم -
یکی از وظایف مدرسه تخصصی، ارتقای آموزش نسل جدید است که شرایط جامعه اطلاعاتی را در سطح توسعه و سبک زندگی خود برآورده کند.
این دوره به دانش آموزان اجازه می دهد تا در عمل دانش خود را در مورد ساختارهای اساسی زبان برنامه نویسی پاسکال تثبیت کنند. (از برنامه چند سالن بدنسازی برای سال 2017)

در پایان، تصمیم گرفتم چند ساعت وقت بگذارم و نمونه‌ای از «چگونه یک ربات ساده برای دانش‌آموزان ایجاد کنیم» را ترسیم کنم.

در زیر برش نحوه نوشتن یک ربات ساده دیگر در Powershell و کارکرد آن بدون webhook، IP های سفید، سرورهای اختصاصی، ماشین های مجازی مستقر در فضای ابری و غیره در یک کامپیوتر خانگی معمولی با ویندوز معمولی آمده است.

TLDR: یک مقاله خسته کننده دیگر با اشتباهات گرامری و واقعی، چیزی برای خواندن، بدون طنز، بدون عکس.

هیچ چیز جدیدی در مقاله وجود ندارد، تقریباً همه چیزهایی که قبلاً نوشته شده است قبلاً در هابره بوده است، به عنوان مثال در مقالات دستورالعمل: نحوه ایجاد ربات در تلگرام и ربات تلگرام برای مدیر سیستم.
ضمناً مقاله عمداً اضافی است تا هر بار به ادبیات آموزشی مراجعه نشود. هیچ اشاره ای به Gang 4، PowerShell Deep Dives یا مثلاً 5 Pillars of the AWS Well-Architected Framework در متن وجود ندارد.

به جای پیشگفتار، می توانید از آن بگذرید

راحت بگذریددر سال 2006، مایکروسافت PowerShell 1.0 را برای ویندوز XP، ویستا و سرور 2003 آن زمان منتشر کرد. از برخی جهات، جایگزین مواردی مانند اسکریپت های cmdbat، اسکریپت های vb، میزبان اسکریپت ویندوز و JScript شد.

حتی در حال حاضر، با وجود حلقه‌ها، کلاس‌ها، توابع، فراخوان‌های MS GUI، حتی در حال حاضر، PowerShell تنها می‌تواند به‌عنوان مرحله بعدی بعد از گزینه‌های Logo، به جای دلفی (یا چیزی قدیمی‌تر) در نظر گرفته شود. یکپارچه سازی Git و به همین ترتیب.

Powershell نسبتاً به ندرت استفاده می شود؛ شما فقط می توانید با آن در قالب PowerShell Core، VMware vSphere PowerCLI، Azure PowerShell، MS Exchange، Desired State Configuration، مواجه شوید. دسترسی به وب پاورشل و ده ها یا بیشتر از برنامه ها و توابع به ندرت استفاده می شود. شاید با رها شدن باد دومی به او برسد WSL2، اما دقیقاً اینطور نیست.

Powershell همچنین دارای سه مزیت بزرگ است:

  1. نسبتاً ساده است، ادبیات و نمونه های زیادی در مورد آن وجود دارد، و حتی به زبان روسی، به عنوان مثال، مقاله ای در مورد Foreach - از کتاب پاورشل در عمق - درباره تفاوت () و {}
  2. با سردبیر می رود ISE، همراه با ویندوز. حتی نوعی دیباگر وجود دارد.
  3. تماس از آن آسان است اجزای ساخت یک رابط گرافیکی.

0. آماده سازی.

ما نیاز داریم:

  • ویندوز کامپیوتر (من ویندوز 10 دارم)
  • حداقل نوعی دسترسی به اینترنت (برای مثال از طریق NAT)
  • برای کسانی که دسترسی محدودی به تلگرام دارند - فری گیت را در مرورگر نصب و پیکربندی کرده اند، در برخی موارد سخت به همراه Symple DNS Crypt
  • داشتن یک کلاینت فعال تلگرام در گوشی شما
  • درک اصول اولیه - متغیر، آرایه، حلقه چیست.

مقالات باز شده و خوانده شده - دستورالعمل: نحوه ایجاد ربات در تلگرام и ربات تلگرام برای مدیر سیستم

1. بیایید یک ربات آزمایشی دیگر ایجاد کنیم.

از آنجایی که همه قبلاً این را می‌دانند و قبلاً اتفاق افتاده است، می‌توانید از آن صرف نظر کنیدهمانطور که در مقاله بالا گفته شد - اول از همه، یک ربات برای تلگرام - این هنوز یک برنامه کاربردی است که در کنار شما اجرا می شود و درخواست هایی را به API ربات تلگرام می دهد. علاوه بر این، API واضح است - ربات به یک URL خاص با پارامترها دسترسی پیدا می کند و تلگرام با یک شی JSON پاسخ می دهد.

مشکلات مرتبط: اگر به روشی ناشناخته مقداری کد از یک شی JSON بگیرید و به نحوی آن را برای اجرا بفرستید (نه عمدا)، کد برای شما اجرا می شود.

روند ایجاد در دو مقاله در بالا توضیح داده شده است، اما تکرار می کنم: در تلگرام مخاطبین را باز می کنیم، دنبال @botfather می گردیم، به او می گوییم /newbot، یک ربات Botfortest12344321 ایجاد می کنیم، آن را Mynext1234bot می نامیم و یک پیام با یک کلید منحصر به فرد دریافت می کنیم. فرم 1234544311: AbcDefNNNNNNNNNNNNNN

مراقب کلید باشید و آن را ندهید!

سپس می توانید ربات را پیکربندی کنید، به عنوان مثال، افزودن آن به گروه ها را ممنوع کنید، اما در مراحل اول این کار ضروری نیست.

بیایید از BotFather "/mybot" بخواهیم و اگر چیزی را دوست نداشتیم، تنظیمات را انجام دهیم.

بیایید دوباره مخاطبین را باز کنیم، @Botfortest12344321 را در آنجا پیدا کنیم (شروع جستجو با @ اجباری است)، روی "شروع" کلیک کنید و به ربات بنویسید "/Glory to the robots". علامت / مورد نیاز است، نقل قول لازم نیست.
ربات، البته، هیچ پاسخی نخواهد داد.

بیایید بررسی کنیم که ربات ایجاد شده است و آن را باز کنیم.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNNN/getMe
که در آن 1234544311:AbcDefNNNNNNNNNNNNNN کلید دریافتی قبلی است،
و یک خط مانند دریافت کنید
{"ok":true,"result":{""}}

اولین عبارت مخفی (ژتون) را داریم. اکنون باید شماره مخفی دوم را پیدا کنیم - شناسه چت با ربات. هر چت، گروه و غیره فردی است و شماره مخصوص به خود را دارد (گاهی اوقات با منهای - برای گروه های باز). برای فهمیدن این شماره، باید در مرورگر درخواست کنیم (در واقع در مرورگر اصلاً لازم نیست، اما برای درک بهتر می توانید با آن شروع کنید) آدرس (که در آن 1234544311:NNNNNNNNNN رمز شما است)

https://api.telegram.org/bot1234544311:NNNNNNNNN/getUpdates

و پاسخی مانند دریافت کنید

{"ok":true,"result":[{"update_id":...،... گپ":{"شناسه":123456789

ما به chat_id نیاز داریم.

بیایید بررسی کنیم که می توانیم به صورت دستی در چت بنویسیم: از طریق مرورگر با آدرس تماس بگیرید

https://api.telegram.org/botваштокен/sendMessage?chat_id=123456789&text="Life is directed motion"

اگر پیامی از یک ربات در چت خود دریافت کردید، بسیار خوب، به مرحله بعدی می روید.

به این ترتیب (از طریق مرورگر) همیشه می توانید بررسی کنید که آیا مشکلی در تولید پیوند وجود دارد یا اینکه چیزی در جایی پنهان است و کار نمی کند.

آنچه باید قبل از ادامه خواندن بدانید

تلگرام چندین نوع چت گروهی (باز، بسته) دارد. برای این چت ها، برخی از عملکردها (مثلا id) متفاوت است که گاهی اوقات باعث ایجاد مشکلاتی می شود.

بیایید فرض کنیم که پایان سال 2019 است، و حتی قهرمان زمان ما، Man-Orchestra معروف (مدیر، وکیل، متخصص امنیت اطلاعات، برنامه نویس و عملا MVP) Evgeniy V. متغیر $i را از یک آرایه متمایز می کند. تا به حلقه تسلط، نگاه در چند سال آینده خواهد شد Chocolatey استاد، و سپس پردازش موازی با PowerShell и ForEach-Object Parallel خواهد آمد.

1. ما به این فکر می کنیم که ربات ما چه خواهد کرد

هیچ ایده ای نداشتم، باید فکر می کردم. من قبلا یک ربات نوت بوک نوشته ام. من نمی خواستم رباتی بسازم "که چیزی را به جایی می فرستد." برای اتصال به Azure به کارت اعتباری نیاز دارید، اما دانشجو آن را از کجا می گیرد؟ لازم به ذکر است که همه چیز چندان بد نیست: ابرهای اصلی نوعی دوره آزمایشی را به صورت رایگان ارائه می دهند (اما شما هنوز به شماره کارت اعتباری نیاز دارید - و به نظر می رسد یک دلار از آن کسر می شود. به یاد ندارم که آیا بعدا برگردانده شد.)

بدون AI ML ساختن یک ربات-شاعر-بافنده فقیر چندان جالب نیست.

تصمیم گرفتم رباتی بسازم که مرا (یا نه) را به یاد کلمات انگلیسی از فرهنگ لغت بیاندازد.
برای جلوگیری از دستکاری با پایگاه داده، فرهنگ لغت در یک فایل متنی ذخیره می شود و به صورت دستی به روز می شود.
در این مورد، وظیفه نشان دادن اصول اولیه کار است و نه ساختن حداقل یک محصول نیمه تمام.

2. تلاش برای اولین بار چه چیزی و چگونه

بیایید یک پوشه C:poshtranslate ایجاد کنیم
ابتدا، بیایید ببینیم چه نوع powershell داریم، بیایید ISE را از طریق start-run راه اندازی کنیم
powershell ise
یا Powershell ISE را در برنامه های نصب شده پیدا کنید.
پس از راه اندازی، "نوعی ویرایشگر" آشنا معمولی باز می شود؛ اگر فیلد متنی وجود نداشته باشد، همیشه می توانید روی "فایل - ایجاد جدید" کلیک کنید.

بیایید به نسخه powershell نگاه کنیم - در قسمت متن بنویسید:

get-host 

و F5 را فشار دهید.

Powershell پیشنهاد ذخیره می دهد - "اسکریپتی که می خواهید اجرا کنید ذخیره خواهد شد."، ما موافقت می کنیم و فایل را از powershell با نام C: poshtranslate ذخیره کنید. myfirstbotBT100.

پس از راه‌اندازی، در پنجره متن پایین جدول داده‌ای را دریافت می‌کنیم:

Name             : Windows PowerShell ISE Host
Version          : 5.1.(и так далее)

من چیزی 5.1 دارم، کافی است. اگر ویندوز 7/8 قدیمی دارید، مشکل خاصی نیست - اگرچه PowerShell باید به نسخه 5 به روز شود - به عنوان مثال. دستورالعمل.

Get-Date را در خط فرمان زیر تایپ کنید، Enter را فشار دهید، زمان را نگاه کنید، با دستور به پوشه root بروید.
cd
و با دستور cls صفحه را پاک کنید (نه، نیازی به استفاده از rm نیست)

حالا بیایید بررسی کنیم که چه چیزی و چگونه کار می کند - بیایید نه حتی کد، بلکه دو خط را بنویسیم و سعی کنیم بفهمیم آنها چه می کنند. بیایید خط را با get-host با نماد # کامنت کنیم و کمی اضافه کنیم.

# Пример шаблона бота 
# get-host
<# это пример многострочного комментария #>
$TimeNow = Get-Date
$TimeNow

(چیز جالب این است که در لیست کشویی قالب بندی کد در Habré دو دوجین گزینه وجود دارد - اما Powershell وجود ندارد. Dos وجود دارد. Perl وجود دارد.)

و اجازه دهید کد را با فشار دادن F5 یا ">" از رابط کاربری گرافیکی اجرا کنیم.

خروجی زیر را دریافت می کنیم:

Saturday, December 8, 2019 21:00:50 PM (или что-то типа)

حال بیایید به این دو خط و چند نکته جالب توجه کنیم تا در آینده به این موضوع برنگردیم.

برخلاف پاسکال (و نه تنها)، خود PowerShell سعی می کند تعیین کند که چه نوع به یک متغیر اختصاص دهد؛ جزئیات بیشتر در مورد این در مقاله نوشته شده است. برنامه آموزشی تایپ در زبان های برنامه نویسی
بنابراین، با ایجاد یک متغیر $TimeNow و اختصاص دادن مقدار تاریخ و زمان فعلی (Get-Date) به آن، نیازی نیست که خیلی نگران نوع داده‌ای باشیم.

درست است، این ناآگاهی ممکن است بعداً صدمه ببیند، اما این برای بعد است. در زیر در متن یک مثال وجود خواهد داشت.
ببینیم چی گرفتیم بیایید اجرا کنیم (در خط فرمان)

$TimeNow | Get-member

و صفحه ای از متن نامفهوم دریافت کنید

نمونه متن نامفهوم شماره 1

PS C:> $TimeNow | Get-member
   TypeName: System.DateTime
Name                 MemberType     Definition                                                                                                                                       
----                 ----------     ----------                                                                                                                                       
Add                  <b>Method         </b>datetime Add(timespan value)  
..
DisplayHint          NoteProperty   DisplayHintType DisplayHint=DateTime                                                                                                             
Date                 <b>Property       </b>datetime Date {get;}                                                                                                                             
Year                 Property       int Year {get;}   
..                                                                                                                               
DateTime             ScriptProperty System.Object DateTime {get=if ((& { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Date")...                                         

همانطور که می بینید، یک متغیر از نوع TypeName: System.DateTime با دسته ای از متدها (به معنای آنچه می توانیم با این شی متغیر انجام دهیم) و ویژگی ها ایجاد شده است.

بیا تماس بگیریم $TimeNow.DayOfYear - عدد روز سال را بدست می آوریم.
بیا تماس بگیریم $TimeNow.DayOfYear | Get-Member - ما گرفتیم TypeName: System.Int32 و گروهی از روشها
بیا تماس بگیریم $TimeNow.ToUniversalTime() - و زمان را در UTC دریافت کنید

رفع اشکال

گاهی پیش می آید که لازم است یک برنامه را تا یک خط مشخص اجرا کنیم و وضعیت برنامه را در آن لحظه ببینیم. برای این منظور، ISE دارای یک تابع Debug - toggle break point است
نقطه شکست را جایی در وسط قرار دهید، این دو خط را اجرا کنید و ببینید شکست به چه شکل است.

3. درک تعامل با ربات تلگرام

البته حتی ادبیات بیشتری در مورد تعامل با ربات، با همه getpush و غیره نوشته شده است، اما موضوع تئوری را می توان به صورت اختیاری در نظر گرفت.

در مورد ما لازم است:

  • یاد بگیرید که در مکاتبات چیزی بفرستید
  • یاد بگیرید که از مکاتبات چیزی دریافت کنید

3.1 آموزش ارسال چیزی در مکاتبات و دریافت از آن

یک کد کوچک - قسمت 3

Write-output "This is part 3"
$MyToken = "1234544311:AbcDefNNNNNNNNNNNNN"
$MyChatID = "123456789"
$MyProxy = "http://1.2.3.4:5678" 

$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
$BotVersion = "BT102"

$MyText01 = "Life is directed motion - " + $TimeNow

$URL4SEND = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText01"

Invoke-WebRequest -Uri $URL4SEND

و در فدراسیون روسیه در این مرحله با خطای Unable to connect to the remote server مواجه می شویم.

یا ما آن را دریافت نمی کنیم - بستگی به اپراتور مخابراتی دارد و اینکه آیا پروکسی پیکربندی شده و کار می کند
خوب، تنها چیزی که باقی می ماند اضافه کردن یک پروکسی است. لطفا توجه داشته باشید که استفاده از یک پروکسی رمزگذاری نشده و به طور کلی تقلبی برای سلامتی شما بسیار خطرناک است.

کار پیدا کردن یک پروکسی کار بسیار دشوار نیست - اکثر پراکسی های http منتشر شده کار می کنند. فکر کنم پنجمی برای من کار کرد.

نحو با استفاده از پروکسی:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

اگر در چت خود با یک ربات پیامی دریافت کردید، پس همه چیز خوب است، می توانید ادامه دهید. اگر نه، به رفع اشکال ادامه دهید.

می توانید ببینید که رشته $URL4SEND شما به چه چیزی تبدیل می شود و سعی کنید آن را در مرورگر درخواست کنید، مانند این:

$URL4SEND2 = '"'+$URL4SEND+'"'
start chrome $URL4SEND2 

3.2. ما یاد گرفتیم که چگونه در چت "چیزی" بنویسیم، اکنون بیایید سعی کنیم آن را بخوانیم

بیایید 4 خط دیگر اضافه کنیم و ببینیم داخل آن از طریق | عضو شدن

$URLGET = "https://api.telegram.org/bot$MyToken/getUpdates"
$MyMessageGet = Invoke-WebRequest -Uri $URLGET -Method Get -Proxy $MyProxy
Write-Host "Get-Member"
$MyMessageGet | Get-Member

جالب ترین چیز در اختیار ما قرار گرفته است

Content           Property   string Content {get;}  
ParsedHtml        Property   mshtml.IHTMLDocument2 ParsedHtml {get;}                                    
RawContent        Property   string RawContent {get;set;}

بیایید ببینیم چه چیزی در آنها وجود دارد:

Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # тут интересное
Write-Host "RawContent"
$MyMessageGet.RawContent # и тут интересное, но еще к тому же и читаемое. 
Write-Host "Content"
$MyMessageGet.Content

اگر همه چیز برای شما کار کند، یک صف طولانی مانند زیر دریافت خواهید کرد:

{"ok":true,"result":[{"update_id":12345678,
"message":{"message_id":3,"from":{"id"

خوشبختانه در مقاله قبلی منتشر شده ربات تلگرام برای مدیر سیستم این خط (بله، طبق $MyMessageGet.RawContent | get-member System.String است) قبلاً جدا شده است.

4. آنچه دریافت می کنید پردازش کنید (ما قبلاً می دانیم که چگونه چیزی را ارسال کنیم)

همانطور که قبلاً نوشته شده است اینجا، ضروری ترین چیزها در محتوا نهفته است. بیایید نگاهی دقیق تر به آن بیندازیم.

ابتدا چند عبارت دیگر از رابط وب یا از تلفن برای ربات می نویسیم

/message1
/message2
/message3

و از طریق مرورگر به آدرسی که در متغیر $URLGET تشکیل شده است نگاه کنید.

چیزی شبیه این را خواهیم دید:

{"ok":true,"result":[{"update_id":NNNNNNN,
"message":{"message_id":10, .. "text":"/message1"
"message":{"message_id":11, .. "text":"/message2 
"message":{"message_id":12, .. "text":"/message3 

آن چیست؟ برخی از شی های پیچیده از آرایه های اشیاء حاوی شناسه پیام سرتاسر، شناسه چت، شناسه ارسال و بسیاری از اطلاعات دیگر.

با این حال، نیازی نیست که بفهمیم "این چه نوع شی است" - بخشی از کار قبلاً برای ما انجام شده است. بیایید ببینیم داخل آن چیست:

خواندن پیام های دریافتی یا قسمت 4

Write-Host "This is part 4" <# конечно эта строка нам не нужна в итоговом тексте, но по ней удобно искать. #> 

$Content4Pars01 = ConvertFrom-Json $MyMessageGet.Content
$Content4Pars01 | Get-Member
$Content4Pars01.result
$Content4Pars01.result[0]
$Content4Pars01.result[0] | Get-Member
$Content4Pars01.result[0].update_id
$Content4Pars01.result[0].message
$Content4Pars01.result[0].message.text
$Content4Pars01.result[1].message.text
$Content4Pars01.result[2].message.text

5. در حال حاضر چه کاری باید انجام دهیم؟

بیایید فایل حاصل را با نام myfirstbotBT105 یا هر چیزی که بیشتر دوست دارید ذخیره کنید، عنوان را تغییر دهید و تمام کدهای قبلاً نوشته شده را از طریق نظر بگذارید

<#start comment 105 end comment 105#>

اکنون باید تصمیم بگیریم که فرهنگ لغت را از کجا دریافت کنیم (خوب، از کجا - روی دیسک در یک فایل) و چگونه به نظر می رسد.

البته، شما می توانید یک دیکشنری عظیم را درست در متن اسکریپت بنویسید، اما این کاملاً غیر از نکته است.
بنابراین بیایید ببینیم که پاورشل به طور معمول با چه چیزی کار می کند.
به طور کلی، او اهمیتی ندارد که با کدام پرونده کار کند، برای ما مهم نیست.
ما یک انتخاب داریم: txt (شما می توانید، اما چرا)، csv، xml.
آیا می توانیم همه را تماشا کنیم؟ بیایید همه را ببینیم.
بیایید یک کلاس MyVocabClassExample1 و یک متغیر $MyVocabExample1 ایجاد کنیم
توجه داشته باشم که کلاس بدون $ نوشته شده است

مقداری کد 5

write-host "This is part 5"
class MyVocabClassExample1 {
    [string]$Original  # слово
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # очень интересный момент. Использование int с его ограничениями может порой приводить к диким последствиям, для примера - недавний случай с SSD HPE. Изначально я не стал добавлять этот элемент, потом все же дописал и закомментировал.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Яблоко"
$MyVocabExample1.Example = "An apple is a sweet, edible fruit produced by an apple tree (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1

$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Pear"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Груша"
$MyVocabExample2.Example = "The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus"
# $MyVocabExample1.$VocWordID = 2

بیایید سعی کنیم این را با استفاده از فایل ها بنویسیم نمونه.

مقداری کد #5.1

Write-Host $ScriptDir # надеюсь $ScriptDir вы не закомментировали 
$MyFilenameExample01 = $ScriptDir + "Example01.txt"
$MyFilenameExample02 = $ScriptDir + "Example02.txt"
Write-Host $MyFilenameExample01
Out-File  -FilePath $MyFilenameExample01 -InputObject $MyVocabExample1

Out-File  -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2
notepad $MyFilenameExample01

- و یک خطا در خط Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2 دریافت می کنیم.

او نمی خواهد اضافه کند، آه-آه، چه شرم آور است.

$MyVocabExample3AsArray = @($MyVocabExample1,$MyVocabExample2)
Out-File  -FilePath $MyFilenameExample02 -InputObject $MyVocabExample3AsArray
notepad $MyFilenameExample02

بذار ببینیم چه اتفاقی میافتد. نمای متن عالی - اما چگونه آن را دوباره صادر کنیم؟ آیا باید نوعی جداکننده متن مانند کاما معرفی کنم؟

و در پایان شما یک فایل A با مقادیر جدا شده با کاما (CSV) دریافت می کنید توقف صبر کنید.
#

$MyFilenameExample03 = $ScriptDir + "Example03.csv"
$MyFilenameExample04 = $ScriptDir + "Example04.csv"
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample1 
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample2 -Append 
Export-Csv  -Path $MyFilenameExample04 -InputObject $MyVocabExample3AsArray 

همانطور که به راحتی قابل مشاهده است، MS به طور خاص با منطق خود متمایز نیست؛ برای یک رویه مشابه، در یک مورد -FilePath و در مورد دیگر -Path استفاده می شود.

علاوه بر این، در فایل سوم زبان روسی ناپدید شد، در فایل چهارم معلوم شد ... خوب، یک اتفاق افتاده است. #TYPE System.Object[] 00
# «تعداد»، «طول»، «طول طولانی»، «رتبه»، «SyncRoot»، «IsReadOnly»، «IsFixedSize»، «IsSynchronized»
#
بیایید کمی آن را بازنویسی کنیم:

Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample1 -Encoding Unicode
Export-Csv  -Path $MyFilenameExample03 -InputObject $MyVocabExample2 -Append -Encoding Unicode
notepad $MyFilenameExample03
notepad $MyFilenameExample04

به نظر می رسد کمک کرده است، اما من هنوز فرمت را دوست ندارم.

من به خصوص دوست ندارم که نمی توانم خطوط را از یک شی به طور مستقیم در یک فایل قرار دهم.
به هر حال، از زمانی که شروع به نوشتن روی فایل ها کردیم، آیا می توانیم شروع به نگه داشتن گزارش راه اندازی کنیم؟ ما زمان را به عنوان یک متغیر داریم، می توانیم نام فایل را تنظیم کنیم.

درست است، هنوز چیزی برای نوشتن وجود ندارد، اما می توانید در مورد بهترین روش برای چرخاندن سیاههها فکر کنید.
بیایید فعلا xml را امتحان کنیم.

مقداری xml

$MyFilenameExample05 = $ScriptDir + "Example05.xml"
$MyFilenameExample06 = $ScriptDir + "Example06.xml"
Export-Clixml  -Path $MyFilenameExample05 -InputObject $MyVocabExample1 
Export-Clixml  -Path $MyFilenameExample05 -InputObject $MyVocabExample2 -Append -Encoding Unicode
Export-Clixml  -Path $MyFilenameExample06 -InputObject $MyVocabExample3AsArray
notepad $MyFilenameExample05
notepad $MyFilenameExample06

صادرات به xml مزایای زیادی دارد - خوانایی، صادرات کل شی و عدم نیاز به انجام آپند.

بیایید سعی کنیم خواندن فایل xml.

خواندن کمی از xml

$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray 
# $MyVocabExample4AsArray[0]
# и немного о совершенно неочевидных нюансах. Powershell время от времени ведет себя не так, как вроде бы как бы стоило бы ожидать бы.
# например у меня эти два вывода отличаются
# Write-Output $MyVocabExample4AsArray 
# write-host $MyVocabExample4AsArray 

به وظیفه برگردیم. ما یک فایل آزمایشی نوشتیم، آن را بخوانید، فرمت ذخیره سازی مشخص است، در صورت لزوم می توانید یک ویرایشگر فایل کوچک جداگانه برای اضافه کردن و حذف خطوط بنویسید.

بگذارید یادآوری کنم که وظیفه ساخت یک ربات آموزشی کوچک بود.

فرمت کار: من دستور "مثال" را برای ربات ارسال می کنم، ربات یک کلمه و رونویسی تصادفی انتخاب شده را برای من ارسال می کند و بعد از 10 ثانیه ترجمه و نظر را برای من ارسال می کند. ما می‌دانیم چگونه دستورات را بخوانیم، همچنین می‌خواهیم نحوه انتخاب و بررسی خودکار پراکسی‌ها و بازنشانی شمارنده پیام به فراموشی را بیاموزیم.

بیایید همه چیزهایی را که قبلاً نظر داده شده به عنوان غیرضروری از کامنت خارج کنیم، نمونه های غیرضروری را با txt و csv کامنت کنیم و فایل را به عنوان نسخه B106 ذخیره کنیم.

آه بله. بیایید دوباره چیزی به ربات بفرستیم.

6. اعزام از توابع و بیشتر

قبل از پردازش دریافت، باید یک تابع برای ارسال "حداقل چیزی" غیر از یک پیام آزمایشی ایجاد کنید.

البته در مثال ما فقط یک ارسال و فقط یک پردازش خواهیم داشت، اما اگر لازم باشد یک کار را چندین بار انجام دهیم چه؟

نوشتن یک تابع راحت تر است. بنابراین، ما یک متغیر از نوع شی $MyVocabExample4AsArray داریم که از فایل خوانده می شود، به شکل آرایه ای از دو عنصر.
بریم بخونیم

در همان زمان، ما با ساعت سروکار خواهیم داشت؛ بعداً به آن نیاز خواهیم داشت (در واقع، در این مثال به آن نیازی نخواهیم داشت :)

مقداری کد #6.1

Write-Output "This is Part 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # приведенное время
    ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # и вот тут мы получим ошибку
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # а тут не получим, кто догадается почему - тот молодец.

$URL4SendFromFunction = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText02"
Invoke-WebRequest -Uri $URL4SendFromFunction -Proxy $MyProxy
}

همانطور که می توانید به راحتی مشاهده کنید، این تابع $MyToken و $MyChatID را فراخوانی می کند که قبلا به صورت هارد کدگذاری شده بودند.

نیازی به این کار نیست و اگر $MyToken برای هر ربات یکی باشد، بسته به چت $MyChatID تغییر می کند.

با این حال، از آنجایی که این یک نمونه است، فعلاً آن را نادیده می گیریم.

از آنجایی که $MyVocabExample4AsArray یک آرایه نیست، اگرچه بسیار شبیه به یک آرایه است، پس شما نمی توانید آن را فقط تحمل کنید طول آن را درخواست کنید

یک بار دیگر باید کاری را انجام دهیم که انجام نمی شود - چتر نجات نه طبق کد - آن را بردارید و بشمارید

مقداری کد #6.2

$MaxRandomExample = 0 
foreach ($Obj in $MyVocabExample4AsArray) {
$MaxRandomExample ++
}
Write-Output $MaxRandomExample
$RandomExample = Get-Random -Minimum 0 -Maximum ($MaxRandomExample)
$TextForExample1 = $MyVocabExample4AsArray[$RandomExample].Original
# MyFirstFunction($TextForExample1)
# или в одну строку
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Угадайте сами, какой пример легче читается посторонними людьми.

تصادفی ویژگی جالب. فرض کنید می خواهیم 0 یا 1 را دریافت کنیم (فقط دو عنصر در آرایه داریم). آیا هنگام تنظیم مرزهای 0..1، "1" را دریافت می کنیم؟
خیر - ما آن را دریافت نخواهیم کرد، یک مثال خاص داریم مثال 2: یک عدد صحیح تصادفی بین 0 و 99 دریافت کنید - تصادفی - حداکثر 100
بنابراین، برای 0..1 باید اندازه 0..2 را با حداکثر عدد عنصر = 1 تنظیم کنیم.

7. پردازش پیام های دریافتی و حداکثر طول صف

زودتر کجا توقف کردیم؟ ما متغیر دریافتی $MyMessageGet را داریم
و $Content4Pars01 از آن به دست آمد که ما به عناصر آرایه Content4Pars01.result علاقه مندیم.

$Content4Pars01.result[0].update_id
$Content4Pars01.result[0].message
$Content4Pars01.result[0].message.text

بیایید ربات /message10، /message11، /message12، /word و دوباره /word و /hello را ارسال کنیم.
بیایید ببینیم چه چیزی بدست آوردیم:

$Content4Pars01.result[0].message.text
$Content4Pars01.result[2].message.text

بیایید همه چیزهای دریافتی را بررسی کنیم و اگر پیام / word بود، پاسخی ارسال کنیم
مورد ساخت، چیزی که برخی آن را if-elseif توصیف می کنند، در powershell نامیده می شود از طریق سوئیچ. در عین حال کد زیر از کلید -wildcard استفاده می کند که کاملا غیر ضروری و حتی مضر است.

مقداری کد #7.1

Write-Output "This is part 7"
Foreach ($Result in $Content4Pars01.result) # Да, можно сделать быстрее 
 { 
    switch -wildcard ($Result.message.text) 
            {
            "/word" {MyFirstFunction($TextForExample1)}
            }
}

بیایید اسکریپت را چند بار اجرا کنیم. ما دو بار برای هر تلاش اجرا یک کلمه را دریافت خواهیم کرد، به خصوص اگر در اجرای تصادفی اشتباه کرده باشیم.

اما بس کن ما / word را دوباره ارسال نکردیم، پس چرا پیام دوباره در حال پردازش است؟

صف ارسال پیام به ربات طول محدودی دارد (فکر می کنم 100 یا 200 پیام) و باید به صورت دستی پاک شود.

این البته در مستندات توضیح داده شده است، اما شما باید آن را بخوانید!

در این مورد، به پارامتر ?chat_id نیاز داریم و &timeout، &limit، &parse_mode=HTML و &disable_web_page_preview=true هنوز مورد نیاز نیستند.

مستندات برای api تلگرام اینجاست
به رنگ سفید و انگلیسی می گوید:
شناسه اولین به روز رسانی که بازگردانده می شود. باید یک بزرگتر از بالاترین در میان شناسه‌های به‌روزرسانی‌های دریافتی قبلی باشد. به‌طور پیش‌فرض، به‌روزرسانی‌ها با اولین‌ها شروع می‌شوند
تأیید نشده به روز رسانی بازگشته است. به محض فراخوانی getUpdates با یک به‌روزرسانی تأیید شده در نظر گرفته می‌شود چاپ افست بالاتر نسبت به update_id آن. افست منفی را می توان برای بازیابی به روز رسانی ها از به روز رسانی -offset از انتهای صف به روز رسانی ها مشخص کرد. تمام به روز رسانی های قبلی فراموش خواهد شد.

بیایید نگاهی بیندازیم به:

$Content4Pars01.result[0].update_id
$Content4Pars01.result[1].update_id 
$Content4Pars01.result | select -last 1
($Content4Pars01.result | select -last 1).update_id

بله، و ما آن را بازنشانی می کنیم و عملکرد را کمی بازنویسی می کنیم. ما دو گزینه داریم - کل پیام را به تابع منتقل کنید و آن را به طور کامل در تابع پردازش کنید، یا فقط شناسه پیام را بدهید و آن را بازنشانی کنید. به عنوان مثال، دومی ساده تر به نظر می رسد.

قبلاً، رشته پرس و جو «همه پیام‌ها» ما شبیه بود

$URLGET = "https://api.telegram.org/bot$MyToken/getUpdates"

و به نظر خواهد رسید

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
$MyMessageGet = Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy 

هیچ کس شما را منع نمی کند که ابتدا همه پیام ها را دریافت کنید، آنها را پردازش کنید، و تنها پس از تایید نشدن درخواست پردازش موفقیت آمیز -> تایید شد.

چرا پس از اتمام تمام پردازش، تماس تاییدیه منطقی است؟ شکست در میانه اجرا ممکن است، و اگر به عنوان مثال یک چت بات رایگان، از دست دادن یک پیام چیز خاصی نیست، اگر در حال پردازش حقوق یا تراکنش کارت شخصی هستید، ممکن است نتیجه بدتر باشد.

چند خط دیگر از کد

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id  #ошибку в этом месте предполагается исправить самостоятельно. 
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy

8. به جای نتیجه گیری

توابع اساسی - خواندن پیام ها، تنظیم مجدد صف، خواندن از فایل و نوشتن به فایل انجام و نشان داده شده است.

فقط چهار کار باقی مانده است:

  • ارسال پاسخ صحیح به یک درخواست در چت
  • ارسال پاسخ به هر چتی که ربات به آن اضافه شده است
  • اجرای کد در یک حلقه
  • راه اندازی یک ربات از زمانبندی ویندوز.

همه این کارها ساده هستند و با خواندن مستندات در مورد پارامترهایی مانند
Set-ExecutionPolicy نامحدود و -ExecutionPolicy Bypass
چرخه فرم

$TimeToSleep = 3 # опрос каждые 3 секунды
$TimeToWork = 10 # минут
$HowManyTimes = $TimeToWork*60/$TimeToSleep # счетчик для цикла
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

با تشکر از همه کسانی که خواندند.

منبع: www.habr.com

اضافه کردن نظر