Šablon najjednostavnijeg bota za Telegram za učenike 7-9 razreda na Powershell

Med pogovorom s prijateljem sem nenadoma izvedel, da učenci v 8.-10. razredu njihove šole sploh ne učijo programiranja. Word, Excel in nič drugega. Niti Logo, niti Pascal, niti VBA za Excel.

Zelo sem se presenetil, odprl sem internet in začel brati —
Ena od nalog usmerjene šole je spodbujati vzgojo nove generacije, ki ustreza svojemu razvoju in življenjskemu slogu zahtevam informatične družbe.
Ta tečaj bo učencem omogočil, da v praksi utrdijo znanje o osnovnih konstrukcijah programskega jezika Pascal. (iz programa neke gimnazije iz leta 2017)

Na koncu sem se odločil, da porabim nekaj ur in napišem primer 'kako ustvariti preprostega bota — za šolarje'.

Pod robom o tem, kako napisati še en preprost bot v PowerShellu in ga spraviti v delovanje brez webhook, belih IP-jev, namenskih strežnikov, v oblaku nameščenih virtualnih naprav itd. — na običajnem domačem računalniku z običajnim Windows.

TLDR: Še en dolgočasen članek z pravopisnimi in dejanskimi napakami, ni vredno brati, ni humorja, ni slik.

V članku ni nič novega, skoraj vse, kar je napisano, je že bilo na Habrju, na primer v člankih Navodilo: Kako ustvariti bote v Telegramu in Telegram bot za sistemskega administratorja.
Poleg tega je članek posebej obsežen, da se ne sklicuje vsakič na učbenike. V besedilu ni omemb skupine 4, PowerShell Deep Dives ali The 5 Pillars of the AWS Well-Architected Framework.

Namesto predgovora lahko preskočimo

Brez zadržkov preskočimoLeta 2006 je Microsoft izdal PowerShell 1.0 za tedaj še Windows XP, Vista in strežnik 2003. V nečem je nadomestil takšne stvari kot so cmdbat skripti, vb skripti, Windows Script Host in JScript.

Tudi danes je PowerShell mogoče obravnavati le kot naslednji korak po različicah Logo, namesto nekje verjetno še vedno uporabljenih Delphi (ali kakšnih starejših), kljub temu, da vsebuje zanke, razrede, funkcije, klice MS GUI, integracijo z Git in tako naprej.

PowerShell se relativno redko uporablja, srečamo ga lahko predvsem v obliki PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, PowerShell Web Access in še deset do dvanajst redko uporabljenih programov in funkcij. Morda bo dobil nov zagon ob izidu WSL2, toda to ni gotovo.

PowerShell ima tri velike prednosti:

  1. Je relativno preprost, o njem so na voljo številne literature in primeri, tudi v ruščini, na primer članek o Foreach - iz knjige PowerShell v globini — o razliki () in {}
  2. Prihaja s paketom ISE, v paketu z Windows. V njem je celo nekaj od debuggerja.
  3. Iz njega lahko enostavno kličete komponente za gradnjo grafičnega vmesnika.

0. Priprava.

Potrebujemo:

  • PC z Windows (imam Windows 10)
  • Vsaj nekaj izhoda v internet (na primer prek NAT)
  • Za tiste, ki imajo omejen dostop do Telegrame - nameščen in nastavljen freegate v brskalniku, v nekaterih zapletenih primerih skupaj s Symple DNS Crypt
  • Delujoč Telegram odjemalec na telefonu
  • Razumevanje osnov - kaj je spremenljivka, matrika, cikel.

Odprti in prebrani članki - Navodilo: Kako ustvariti bote v Telegramu in Telegram bot za sistemskega administratorja

1. Ustvarimo novega testnega bota.

Ker to vsi že vedo, in to je že bilo, lahko tudi to preskočimoKot je zapisano v zgoraj navedeni članku - Predvsem, bot za Telegram - je še vedno aplikacija, ki se izvaja na vaši strani in pošilja zahtevke Telegram Bot API-ju. API je razumljiv - bot se poveže na določen URL s parametri, Telegram pa odgovori z JSON objektom.

S tem povezane težave: če na kakršenkoli skrivnosten način vzamete določeno kodo iz JSON objekta in jo nekako pošljete na izvedbo (ne namenoma) - koda bo izvedena pri vas.

Postopek ustvarjanja je opisan v dveh zgoraj navedenih člankih, vendar ponovim: v Telegramu odprete stike, poiščete @botfather, mu poveste /newbot, ustvarimo bota Botfortest12344321, ga poimenujemo Mynext1234bot in dobimo sporočilo z edinstvenim ključem v obliki 1234544311:AbcDefNNNNNNNNNNNNN

Ključ varujte in ga ne delite!

Nato lahko bota nastavite, na primer prepoveste dodajanje v skupine, toda na začetnih korakih to ni potrebno.

Vprašamo BotFatherja «/mybot» in popravimo nastavitve, če nam kaj ni všeč.

Spet bomo odprli stike, tam poiskali @Botfortest12344321 (iskanje začnite z @), pritisnemo 'začni' in pišemo botu 'Slava robotom'. Znak / je obvezen, narekovaji - niso potrebni.
Bot, seveda, ne bo nič odgovoril.

Preverimo, da je bot ustvarjen - odpremo.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNN/getMe
kjer je 1234544311:AbcDefNNNNNNNNNNNNN - prej pridobljen ključ,
in dobimo vrsto v obliki
{«ok»:true,«result»:{«»}}

Prva tajna fraza (token) je ovde. Sada treba da saznamo drugi tajni broj — ID čata sa botom. Svaki čat, grupa i slično — su jedinstveni i imaju svoj vlastiti broj (ponekad sa minusom — za otvorene grupe). Da bismo saznali ovaj broj, potrebno je da u pretraživaču (mada u stvari nije neophodno u pretraživaču, ali za bolje razumevanje, može se početi od njega) zatražimo adresu (gde je 1234544311:NNNNNNNNN — to je vaš token

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

i dobijemo odgovor u obliku

{„ok“:true„result“:[{„update_id“:…,… chat„:{„id“:123456789

Nama je potreban upravo chat_id.

Proverićemo da li možemo ručno pisati u čat: pozvaćemo iz pretraživača adresu

https://api.telegram.org/botvaštokend/sendMessage?chat_id=123456789&text="Život je usmereni pokret"

Ako je poruka od bota stigla u vaš čat — u redu, prelazite na sledeći korak.

Na taj način (kroz pretraživač) uvek možete proveriti gde su problemi — da li kod vas prilikom generisanja linka ili nešto drugo nije u funkciji.

Šta treba znati pre nego što nastavimo sa čitanjem

U Telegramu postoji nekoliko tipova grupnih čatova (otvoreni, zatvoreni). Za te čatove neki delovi funkcionalnosti (kao što je id) se razlikuju, što ponekad izaziva određene probleme.

Da pretpostavimo da je kraj 2019. i čak i junak našeg vremena, svima poznati Čovek-Orkestar (administrator, pravnik, infobezbednjak, programer i praktično MVP) Evgenij V. prepoznaje varijablu $i od niza, savladao je petlje, možda će u naredne dve godine ovladati Chocolatey, a zatim će paralelno procesuiranje sa PowerShell-om in ForEach-Object Paralelno stignuti.

1. Razmišljamo, šta će naš bot raditi

Nisam imao nikakvih ideja, morao sam da razmišljam. Već sam pravio bota beležnicu. Ne želeći da pravim bota „koji nešto preusmerava negde“. Za povezivanje sa Azure-om potrebna je kreditna kartica, a odakle je školarcu? Treba napomenuti da nije sve tako loše: glavni oblaci daju neki probni period besplatno (ali broj kreditne kartice je i dalje potreban — i od njega će, čini mi se, biti naplaćen dolar. Ne sećam se da li je kasnije vraćen.)

Bez AI ML nije toliko zanimljivo praviti bota-boksera-šaljivdžiju.

Odlučio sam da napravim bota koji će mi (ili ne meni) podsećati na engleske reči iz rečnika.
Rečnik, da se ne mučim sa DB, biće u tekstualnoj datoteci i dopunjavaće se ručno.
U ovom slučaju, cilj je pokazati osnove rada, a ne napraviti makar delimično gotov proizvod.

2. Poskušamo, kar in kako prvič

Ustvarimo mapo C:poshtranslate
Na začetku poglejmo, kaj imamo za powershell, zaženimo ISE preko zaženite-izvršite
powershell ise
ali poiščemo Powershell ISE med nameščenimi programi.
Po zagonu se odpre običajen znani "kakšen koli urednik", če ne bo besedilnega polja, vedno lahko pritisnete "File — create new".

Poglejmo različico powershell - v besedilno polje vpišimo:

get-host 

in pritisnemo F5.

Powershell bo predlagal, da shranimo - "The script you are about to run will be saved.", strinjamo se, in shranimo v C:poshtranslate datoteko iz powershell z imenom myfirstbotBT100.

Po zagonu bomo v spodnjem besedilnem oknu dobili tabelo podatkov:

Name             : Windows PowerShell ISE Host
Version          : 5.1.(in tako naprej)

Imam 5.1 s čim, to je dovolj. Če imate star Windows 7/8, ni nič hudega - čeprav je PowerShell potrebno posodobiti na različico 5 - na primer po navodilih.

V spodnjem ukaznem pozivniku vpišimo Get-Date, pritisnemo Enter, pogledamo čas, in preidemo v osnovno mapo z ukazom
cd
in očistimo zaslon z ukazom cls (ne, ne uporabljajte rm)

Zdaj preverimo, kaj in kako deluje - ne bomo napisali kode, ampak dve vrstici, in poskusimo razumeti, kaj počneta. Zakomentirali bomo vrstico z get-host simbolom # in malo dopisali.

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

(Kar je zanimivo. V padajočem meniju oblikovanja kode na habru je dva ducata možnosti - a powershell tam ni. Dos je. Perl je.)

In zaženemo kodo, tako da pritisnemo F5 ali ">" iz GUI.

Dobili bomo izhod:

Sobota, 8. december 2019 21:00:50 PM (ali nekaj takega)

Zdaj razjasnimo teh dveh vrstic in nekaj zanimivih stvari, da se v prihodnje ne vrnemo k temu.

Za razliko od pascal (in ne samo), powershell sam poskuša določiti, kakšno vrsto dodeliti spremenljivki, podrobneje o tem piše članek Osnovno znanje o tipizaciji v programskih jezikih
Zato, ko uvedemo spremenljivko $TimeNow in ji dodelimo vrednost trenutnega datuma in časa (Get-Date), se nam ni potrebno posebej obremenjevati, kakšna bo vrsta podatkov tam.

Res je, da lahko to neznanje kasneje povzroči težave, ampak to je že drugič. Spodaj v besedilu bo primer.
Poglejmo, kaj smo dobili. Izvedimo (v ukaznem pozivniku)

$TimeNow | Get-member

in dobimo stran nejasnega besedila

Primer nejasnega besedila številka 1

PS C:&gt; $TimeNow | Get-member
   TypeName: System.DateTime
Name                 MemberType     Definition                                                                                                                                       
----                 ----------     ----------                                                                                                                                       
Add                  <b>Metoda         </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 ((&amp; { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Date")...                                         

Kot je razvidno, je bila ustvarjena spremenljivka tipa TypeName: System.DateTime s kupom metod (v smislu, kaj lahko počnemo s tem objektomspremenljivko) in lastnostmi.

Pokličimo $TimeNow.DayOfYear — pridobimo številko dneva v letu.
Pokličimo $TimeNow.DayOfYear | Get-Member — pridobimo TypeName: System.Int32 in skupino metod.
Pokličimo $TimeNow.ToUniversalTime() — in pridobimo čas po UTC

Debuger

Včasih je potrebno izvesti program do določene vrstice in si ogledati stanje programa v tistem trenutku. Za to v ISE obstaja funkcija Debug — toggle break point
Postavite točko prekinitve nekje v sredini, zaženite ti dve vrstici za izvajanje in si oglejte, kako izgleda prekinitev.

3. Raziskujemo interakcijo z botom Telegram

Seveda je o interakciji z botom, vseh getpush in podobnih stvareh napisanega še več literature, vendar lahko teorijo obravnavamo fakultativno.

V našem primeru je potrebno:

  • Naučiti se pošiljati nekaj v pogovor
  • Naučiti se prejemati nekaj iz pogovora

3.1 Učimo se pošiljati nekaj v pogovor in prejemati iz njega

Malo kode — del 3

Write-output "To je del 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 = "Življenje je usmerjeno gibanje - " + $TimeNow

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

Invoke-WebRequest -Uri $URL4SEND

in v RS na tem mestu dobimo napako Unable to connect to the remote server.

Ali je ne dobimo — odvisno od operaterja in tega, ali je proxy nastavljen in deluje.
No, dodati moramo proxy. Upoštevajte — uporaba nešifriranega in sploh neznanega proxyja je izredno nevarna za vaše zdravje.

Naloga iskanja delujočega proxyja ni zelo zapletena — večina objavljenih http proxyjev deluje. Prišlo mi je zadnje, se mi zdi, peto po vrsti.

Sintaksa z uporabo proxyja:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

Če ste prejeli sporočilo v vaš chat z botom — potem je vse odlično, lahko greste naprej. Če ne — nadaljujte z odpravljanjem napak.

Lahko si ogledate, v kaj se pretvori vaša vrstica $URL4SEND in jo poskusite zahtevati v brskalniku, na primer tako:

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

3.2. Pisati «nekaj» v chat smo se naučili, zdaj bomo poskusili brati

Dodali bomo še 4 vrstice in si ogledali, kaj je tam notranjosti preko | get-member

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

Najbolj zanimivo nam zagotavlja

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

Poglejmo, kaj je v njih:

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. Обработать полученное (отправлять хоть что-то мы уже умеем)

Как уже написано tukaj, самое нужное лежит в content. Посмотрим на него внимательнее.

Сначала напишем боту еще пару фраз через веб-интерфейс или с телефона

/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#>

Теперь нам надо определиться, где брать словарь (ну как где — на диске в файле) и как он будет выглядеть.

Конечно, можно набить огромный словарь прямо в тексте скрипта, но это же совершенно не дело.
Поэтому посмотрим, с чем умеет штатно работать powershell.
Вообще-то ему всё равно, с каким файлом работать, не всё равно нам.
На выбор у нас есть: txt (можно, но зачем), csv, xml.
А можно всех посмотреть. Посмотрим всех.
Создадим класс MyVocabClassExample1 и переменную $MyVocabExample1
замечу, что класс пишется без $

немного кода #5

write-host "To je del 5"
class MyVocabClassExample1 {
    [string]$Original  # beseda
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # zelo zanimiva točka. Uporaba int s svojimi omejitvami lahko včasih privede do nenormalnih posledic, na primer - nedavni primer s SSD HPE. Sprva tega elementa nisem dodal, potem sem ga vseeno dodal in komentiral.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Jabolko"
$MyVocabExample1.Example = "Jabolko je sladek, užiten sadež, ki ga prideluje jablana (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1

$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Pear"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Hruška"
$MyVocabExample2.Example = "Hruška (/C8pD5C8/ ) je vrsta rodu Pyrus"
# $MyVocabExample1.$VocWordID = 2

Poskusimo to zapisati v datoteke po vzoru.

Malo kode #5.1

Write-Host $ScriptDir # upam, da niste komentirali $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

— in dobili bomo napako v vrstici Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Noče dodati, oh, kakšna škoda.

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

Poglejmo, kaj je nastalo. Lep besedilni pogled — kako pa to izvoziti nazaj? Vnesemo kakšne ločilne znake za besedilo, na primer vejice?

In na koncu dobimo 'datoteko z ločili — vejicami, comma-separated values (CSV) A STOP, POČAKAJTE.
#

$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 

Kako lahko vidimo, MS se ni prav posebej izkazal z logiko, v enem primeru je uporabljena -FilePath, v drugem pa -Path.

Poleg tega je v tretji datoteki izginil ruščina, v četrti datoteki je pa... no, nekaj je prišlo ven. #TYPE System.Object[] 00
# „Count“,»Length»,«LongLength»,«Rank»,«SyncRoot»,«IsReadOnly»,«IsFixedSize»,«IsSynchronized»
#
Malo bomo prepisali:

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

Zdi se, da je pomagalo — a format mi še vedno ni všeč.

Še posebej mi ni všeč, da ne morem neposredno zapisati vrstice iz objekta v datoteko.
При том, раз уж начали записывать файлы — может стоит вести лог запуска? Время у нас как переменная есть, имя файла задать умеем.

Писать, правда, пока что нечего, зато можно подумать, как лучше сделать ротацию логов.
Пока попробуем 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 сплошные плюсы — читаемость, возможность экспортировать весь объект, и не надо выполнять uppend.

Попробуем прочитать файл 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 "To je del 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # prilagojeni čas
    ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # in tukar bomo dobili napako
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # ampak tukaj ne bomo, kdo ugane zakaj - tisti je dober.

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

Zelo lahko opazimo, da $MyToken in $MyChatID v funkciji kličeta prej navedene vrednosti.

Tako ne gre, in če je $MyToken enak za vsakega bota, se bo $MyChatID spreminjal glede na klepet.

Vendar pa bomo zaradi tega primera to zaenkrat ignorirali.

Ker $MyVocabExample4AsArray ni niz, čeprav zelo spominja nanj, ne moremo kar tako vzeti in zapisati njegovo dolžino.

Spet se bomo morali poslužiti nečesa, česar ne bi smeli - pristati brez kodeksa - vzeti in prešteti

Malo kode #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)
# ali v eni vrstici
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Uganite sami, kateri primer je lažje razumljiv tujcem.

Naključno zanimiva funkcija. Predpostavimo, da želimo prejemati 0 ali 1 (imamo samo dva elementa v nizu). Če določimo meje 0..1 - bomo dobili "1"?
ne - ne bomo dobili, imamo posebej prikazan primer Example 2: Get a random integer between 0 and 99 Get-Random -Maximum 100
Zato bomo morali za 0..1 nastaviti velikost 0..2, pri čemer bo največja številka elementa = 1.

7. Obdelava prejetih sporočil in največja dolžina čakalne vrste

Kje smo prej obstali? Imamo spremenljivko $MyMessageGet
in pridobljeno iz nje $Content4Pars01, od katerih nas zanimajo elementi niza Content4Pars01.result

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

Pošljimo botu /message10, /message11, /message12, /word in še enkrat /word in /živjo.
Poglejmo, kaj smo prejeli:

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

Preverili bomo vse prejete in poslali odgovor, če je bilo sporočilo /word
konstrukcija case of, kar nekateri opisujejo kot if-elseif, se v powershellu kliče prek switch. V tem primeru je v spodnjem kodi uporabljen ključ -wildcard, kar ni nujno in je celo škodljivo.

Nekaj kode #7.1

Write-Output "To je del 7"
Foreach ($Result in $Content4Pars01.result) # Da, lahko to storimo hitreje 
 { 
    switch -wildcard ($Result.message.text) 
            {
            "\/word" {MyFirstFunction($TextForExample1)}
            }
}

Izvedimo skript nekajkrat. Dobimo enako besedo za vsak poskus izvajanja, še posebej če smo naredili napako pri izvedbi random.

Ampak počakaj. Nismo poslali \/word še enkrat, zakaj torej se sporočilo obdeluje ponovo?

Čakalna vrsta za pošiljanje sporočil botu ima končno dolžino (zdi se, da 100 ali 200 sporočil), in jo je treba ročno očistiti.

V dokumentaciji je seveda to opisano, a to je treba tudi prebrati!

V tem primeru potrebujemo parameter ?chat_id, medtem ko &timeout, &limit, &parse_mode=HTML in &disable_web_page_preview=true trenutno niso potrebni.

Dokumentacija o telegram api je tukaj
V angleščini na belem tam piše:
Ugotovitelj prve posodobitve, ki naj bi bila vrnjena. Mora biti večja za eno od najvišjih med identifikatorji prej prejetih posodobitev. Privzeto se vrnejo posodobitve, ki se začnejo z najzgodnejšo
nepotrjen posodobitev. Posodobitev se šteje za potrjeno takoj, ko se klice getUpdates izvedejo s offset večjim kot je njen update_id. Negativno premik lahko določimo za pridobitev posodobitev, ki se začnejo od -offset posodobitve na koncu čakalne vrste posodobitev. Vse prejšnje posodobitve bodo pozabljene.

Poglejmo na:

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

In ponastavimo — nekoliko prepišimo funkcijo. Imamo dve možnosti — prenesti v funkcijo vse sporočilo in ga celotno obdelati v funkciji, ali pa vrniti samo ID sporočila in ga tudi ponastaviti. Za primer drugo zgleda preprosteje.

Prej je imel naš iskalni niz "vsa sporočila" obliko

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

zdaj pa bo videti takole

$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 

Nihče ne prepoveduje, da najprej pridobite vsa sporočila, jih obdelate, in šele po uspešni obdelavi zahtevate unconfirmed -> confirmed.

Zakaj ima smisel zahtevati potrditev po zaključku vseh obdelav? Obstaja možnost napake sredi izvajanja, in če za primer brezplačnega chatbota opozorite na katero koli enotno sporočilo, to še ni vse, vendar, če obdelujete nekoga plačo ali transakcijo s kartico, je lahko rezultat slabši.

Še nekaj vrstic kode

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

8. Namesto sklepa

Glavne funkcije — branje sporočil, ponastavitev čakalne vrste, branje iz datoteke in zapisovanje v datoteko so izvedene in prikazane.

Ostalo je narediti še štiri stvari:

  • poslati pravilen odgovor na poizvedbo v klepetu
  • poslati odgovor v KATERIKOLI klepet, v katerega je bil dodan bot
  • izvajanje kode v zanki
  • zagon bota iz načrtovalnika Windows.

Vse te naloge so preproste in jih je enostavno izvesti s pomočjo branja dokumentacije o takih parametrih, kot so
Set-ExecutionPolicy Unrestricted in -ExecutionPolicy Bypass
zanke vrste

$TimeToSleep = 3 # poizvedba vsakih 3 sekunde
$TimeToWork = 10 # minut
$HowManyTimes = $TimeToWork*60/$TimeToSleep # števec za zanko
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

Vsem hvala, ki ste prebrali do konca.

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster