Szablon prostego bota telegramowego dla uczniów klas 7-9 przy użyciu programu Powershell

Podczas rozmów ze znajomym dowiedziałem się nagle, że dzieci w klasach 8-10 w ich szkole w ogóle nie uczy się programowania. Word, Excel i wszystko. Żadnego logo, nawet Pascala, nawet VBA dla Excela.

Byłem bardzo zaskoczony, otworzyłem Internet i zacząłem czytać -
Jednym z zadań szkoły specjalistycznej jest promowanie edukacji nowego pokolenia, spełniającego warunki społeczeństwa informacyjnego pod względem poziomu rozwoju i stylu życia.
Kurs pozwoli studentom utrwalić w praktyce wiedzę na temat podstawowych konstrukcji języka programowania Pascal. (z programu jakiegoś gimnazjum na rok 2017)

W końcu zdecydowałem się spędzić kilka godzin i naszkicować przykład „jak stworzyć prostego bota dla uczniów”.

Poniżej opisano, jak napisać kolejnego prostego bota w Powershell i sprawić, by działał bez webhooka, białych adresów IP, serwerów dedykowanych, wdrożonych maszyn wirtualnych w chmurze i tak dalej - na zwykłym domowym komputerze PC ze zwykłym systemem Windows.

TLDR: Kolejny nudny artykuł z błędami gramatycznymi i merytorycznymi, nie ma nic do czytania, nie ma humoru, nie ma zdjęć.

W artykule nie ma nic nowego, prawie wszystko, co napisano wcześniej, było już na temat Habré, na przykład w artykułach Instrukcje: Jak tworzyć boty w Telegramie и Bot telegramowy dla administratora systemu.
Ponadto artykuł jest celowo zbędny, aby nie za każdym razem odwoływać się do literatury edukacyjnej. W tekście nie ma żadnych odniesień do Gang 4, PowerShell Deep Dives czy, powiedzmy, The 5 Pillars of the AWS Well-Architected Framework.

Zamiast wstępu możesz pominąć

Możesz pominąćW 2006 roku Microsoft wypuścił PowerShell 1.0 dla ówczesnych systemów Windows XP, Vista i Server 2003. W pewnym sensie zastąpił takie rzeczy, jak skrypty cmdbat, skrypty vb, Host skryptów systemu Windows i JScript.

Nawet teraz PowerShell można uznać jedynie za kolejny krok po opcjach Logo, zamiast prawdopodobnie wciąż używanego Delphi (lub czegoś starszego), pomimo obecności pętli, klas, funkcji, wywołań MS GUI, Integracja z Gitem i tak dalej.

Powershell jest używany stosunkowo rzadko, można go spotkać jedynie w postaci PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, Dostęp do sieci PowerShell oraz kilkanaście rzadziej używanych programów i funkcji. Być może po premierze złapie drugi oddech WSL2, ale to nie do końca.

Powershell ma również trzy duże zalety:

  1. Jest to stosunkowo proste, jest na ten temat sporo literatury i przykładów, a nawet po rosyjsku np. artykuł o Foreach - z książki Szczegółowo PowerShell - o różnicy () i {}
  2. Idzie z redaktorem ISE, dołączony do systemu Windows. Jest tam nawet jakiś debugger.
  3. Łatwo z niego zadzwonić komponenty do budowy interfejsu graficznego.

0. Przygotowanie.

Będziemy potrzebować:

  • Komputer z systemem Windows (mam system Windows 10)
  • Przynajmniej jakiś dostęp do Internetu (na przykład przez NAT)
  • Dla tych, którzy mają ograniczony dostęp do telegramu - zainstaluj i skonfiguruj freegate w przeglądarce, w niektórych trudnych przypadkach razem z Symple DNS Crypt
  • Posiadanie działającego klienta telegramu na swoim telefonie
  • Zrozumienie samych podstaw - czym jest zmienna, tablica, pętla.

Otwarte i przeczytane artykuły - Instrukcje: Jak tworzyć boty w Telegramie и Bot telegramowy dla administratora systemu

1. Stwórzmy kolejnego bota testowego.

Ponieważ wszyscy już o tym wiedzą i już się wydarzyło, możesz to również pominąćJak stwierdzono w powyższym artykule - Przede wszystkim bot dla Telegramu - jest to nadal aplikacja działająca po Twojej stronie i wysyłająca żądania do interfejsu API Telegram Bot. Co więcej, API jest przejrzyste – bot uzyskuje dostęp do konkretnego adresu URL z parametrami, a Telegram odpowiada obiektem JSON.

Powiązane problemy: jeśli w jakiś nieznany sposób pobierzesz kod z obiektu JSON i w jakiś sposób wyślesz go do wykonania (nie celowo), kod zostanie wykonany za Ciebie.

Proces tworzenia opisano w dwóch artykułach powyżej, ale powtarzam: w telegramie otwieramy kontakty, szukamy @botfather, mówimy mu /newbot, tworzymy bota Botfortest12344321, nazywamy go Mynext1234bot i otrzymujemy wiadomość z unikalnym kluczem formularz 1234544311:AbcDefNNNNNNNNNNNNNN

Dbaj o klucz i nie oddawaj go!

Następnie możesz skonfigurować bota, np. zabronić dodawania go do grup, ale w pierwszych krokach nie jest to konieczne.

Zapytajmy BotFathera o „/mybot” i dostosujmy ustawienia, jeśli coś nam się nie podoba.

Otwórzmy ponownie kontakty, znajdź tam @Botfortest12344321 (obowiązkowo zacznij wyszukiwanie od @), kliknij „start” i napisz do bota „/Chwała robotom”. Znak / jest wymagany, cudzysłowy nie są potrzebne.
Bot oczywiście nic nie odpowie.

Sprawdźmy, czy bot został utworzony i otwórz go.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNNN/getMe
gdzie 1234544311:AbcDefNNNNNNNNNNNNNN to otrzymany wcześniej klucz,
i uzyskaj linię podobną do
{"ok": prawda, "wynik":{""}}

Mamy pierwszą tajną frazę (token). Teraz musimy znaleźć drugi tajny numer - identyfikator czatu z botem. Każdy czat, grupa itp. jest indywidualna i ma swój własny numer (czasami z minusem - w przypadku grup otwartych). Aby znaleźć ten numer, musimy poprosić w przeglądarce (w rzeczywistości nie jest to wcale konieczne w przeglądarce, ale dla lepszego zrozumienia możesz od niego zacząć) adres (gdzie 1234544311:NNNNNNNNNN to Twój token

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

i uzyskaj odpowiedź typu

{"ok":true,"result":[{"update_id":...,... pogawędzić":{"ID":123456789

Potrzebujemy chat_id.

Sprawdźmy, czy możemy pisać na czacie ręcznie: wywołaj adres z przeglądarki

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

Jeśli na czacie otrzymasz wiadomość od bota, OK, przechodzisz do kolejnego etapu.

W ten sposób (przez przeglądarkę) zawsze możesz sprawdzić, czy nie ma problemów z generowaniem linku, czy też coś jest gdzieś ukryte i nie działa.

Co musisz wiedzieć przed kontynuowaniem czytania

Telegram ma kilka rodzajów czatów grupowych (otwarte, zamknięte). W przypadku tych czatów niektóre funkcje (na przykład identyfikator) są inne, co czasami powoduje pewne problemy.

Załóżmy, że jest koniec 2019 roku, a nawet bohater naszych czasów, znany Man-Orkiestra (administrator, prawnik, specjalista ds. bezpieczeństwa informacji, programista i praktycznie MVP) Evgeniy V. odróżnia zmienną $i od tablicy, opanował pętle, spójrz, w ciągu najbliższych kilku lat opanuje Chocolatey, a potem Przetwarzanie równoległe za pomocą programu PowerShell и ForEach-Object Parallel to przyjdzie.

1. Myślimy o tym, co zrobi nasz bot

Nie miałam żadnego pomysłu, musiałam pomyśleć. Napisałem już bota-notatnik. Nie chciałem tworzyć bota, „który coś gdzieś wysyła”. Aby połączyć się z Azure, potrzebujesz karty kredytowej, ale skąd student ją bierze? Należy zauważyć, że wszystko nie jest takie złe: główne chmury dają jakiś okres testowy za darmo (ale nadal potrzebujesz numeru karty kredytowej - i wygląda na to, że zostanie z niej pobrany dolar. Nie pamiętam, czy został zwrócony później.)

Bez AI ML tworzenie tkacza-biednego-bota-poety nie jest już tak interesujące.

Postanowiłem zrobić bota, który będzie mi (lub nie) przypominał mi (lub nie) angielskie słowa ze słownika.
Aby uniknąć grzebania w bazie danych, słownik będzie przechowywany w pliku tekstowym i aktualizowany ręcznie.
W tym przypadku zadaniem jest pokazanie podstaw pracy, a nie wykonanie choćby częściowo gotowego produktu.

2. Próbuję co i jak po raz pierwszy

Utwórzmy folder C:poshtranslate
Najpierw zobaczmy, jaki mamy rodzaj PowerShell, uruchommy ISE poprzez start-run
powershell
lub znajdź Powershell ISE w zainstalowanych programach.
Po uruchomieniu otworzy się zwykły, znany „jakiś edytor”, jeśli nie ma pola tekstowego, zawsze możesz kliknąć „Plik - utwórz nowy”.

Spójrzmy na wersję PowerShell - wpisz w polu tekstowym:

get-host 

i naciśnij klawisz F5.

Powershell zaproponuje zapisanie - „Skrypt, który za chwilę uruchomisz, zostanie zapisany.”, zgadzamy się i zapisujemy plik z PowerShell pod nazwą w C: poshtranslate myfirstbotBT100.

Po uruchomieniu w dolnym oknie tekstowym otrzymujemy tabelę danych:

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

Mam coś 5.1 i wystarczy. Jeśli masz stary system Windows 7/8, to nic wielkiego – chociaż PowerShell będzie musiał zostać zaktualizowany do wersji 5 – np. instrukcje.

Wpisz Get-Date w wierszu poleceń poniżej, naciśnij Enter, spójrz na godzinę, przejdź do folderu głównego za pomocą polecenia
cd
i wyczyść ekran za pomocą polecenia cls (nie, nie musisz używać rm)

Sprawdźmy teraz, co i jak działa - napiszmy nawet nie kod, ale dwie linijki i spróbujmy zrozumieć, co robią. Skomentujmy linię get-host symbolem # i dodajmy trochę.

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

(Co ciekawe, na liście rozwijanej formatowania kodu w Habré znajdują się dwa tuziny opcji - ale nie ma Powershell. Jest Dos. Jest Perl.)

I uruchommy kod, naciskając F5 lub „>” z GUI.

Otrzymujemy następujące dane wyjściowe:

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

Przyjrzyjmy się teraz tym dwóm liniom i kilku interesującym punktom, aby nie wracać do tego w przyszłości.

W przeciwieństwie do Pascala (i nie tylko) PowerShell sam próbuje określić, jaki typ przypisać do zmiennej; więcej szczegółów na ten temat opisano w artykule Program edukacyjny dotyczący pisania w językach programowania
Dlatego tworząc zmienną $TimeNow i przypisując jej wartość aktualnej daty i czasu (Get-Date), nie musimy się zbytnio martwić, jakiego rodzaju dane będą się tam znajdować.

To prawda, że ​​ta niewiedza może później zaboleć, ale to później. Poniżej w tekście będzie przykład.
Zobaczmy, co mamy. Wykonajmy (w linii poleceń)

$TimeNow | Get-member

i otrzymaj stronę niezrozumiałego tekstu

Przykład niezrozumiałego tekstu nr 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")...                                         

Jak widać, zmienna typu TypeName: System.DateTime została utworzona za pomocą szeregu metod (w sensie tego, co możemy zrobić z tym obiektem zmiennej) i właściwości.

Zadzwońmy $TimeNow.DayOfYear — otrzymujemy numer dnia w roku.
Zadzwońmy $TimeNow.DayOfYear | Get-Member - Dostawać TypeName: System.Int32 i grupa metod.
Zadzwońmy $TimeNow.ToUniversalTime() - i uzyskaj czas w formacie UTC

Debugger

Czasami zdarza się, że konieczne jest wykonanie programu do określonej linii i sprawdzenie stanu programu w tym momencie. W tym celu ISE posiada funkcję Debug - przełączanie punktu przerwania
Umieść punkt przerwania gdzieś pośrodku, uruchom te dwie linie i zobacz, jak wygląda przerwa.

3. Zrozumienie interakcji z botem Telegramu

Oczywiście jeszcze więcej literatury napisano na temat interakcji z botem, ze wszystkimi getpushami i tak dalej, ale kwestię teorii można rozpatrywać opcjonalnie.

W naszym przypadku konieczne jest:

  • Naucz się wysyłać coś korespondencyjnie
  • Naucz się zdobywać coś z korespondencji

3.1 Nauka wysyłania czegoś w korespondencji i otrzymywania od niej

Mały kod – część 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

aw Federacji Rosyjskiej w tym momencie pojawia się błąd Nie można połączyć się ze zdalnym serwerem.

Lub nie otrzymamy - zależy od operatora telekomunikacyjnego oraz tego, czy serwer proxy jest skonfigurowany i działa
Cóż, pozostaje tylko dodać serwer proxy. Należy pamiętać, że korzystanie z niezaszyfrowanego i ogólnie fałszywego serwera proxy jest niezwykle niebezpieczne dla zdrowia.

Zadanie znalezienia działającego proxy nie jest bardzo trudne - większość opublikowanych proxy HTTP działa. Myślę, że piąty zadziałał dla mnie.

Składnia przy użyciu proxy:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

Jeśli na czacie z botem otrzymasz wiadomość, wszystko jest w porządku, możesz przejść dalej. Jeśli nie, kontynuuj debugowanie.

Możesz zobaczyć, w co zamienia się Twój ciąg $URL4SEND i spróbować zażądać go w przeglądarce w następujący sposób:

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

3.2. Nauczyliśmy się pisać „coś” na czacie, teraz spróbujmy to przeczytać

Dodajmy jeszcze 4 linie i zobaczmy, co jest w środku poprzez | uzyskać członkostwo

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

To, co najciekawsze, jest nam dostarczane

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

Zobaczmy, co w nich jest:

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

Jeśli wszystko zadziała, otrzymasz długą linię, taką jak:

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

Na szczęście w opublikowanym wcześniej artykule Bot Telegramu dla administratora systemu ta linia (tak, według $MyMessageGet.RawContent | get-member to System.String), został już zdemontowany.

4. Przetwarzaj to, co otrzymujesz (już wiemy, jak coś wysłać)

Jak już napisano tutajnajważniejsze rzeczy leżą w treści. Przyjrzyjmy się temu bliżej.

Najpierw napiszemy do bota jeszcze kilka fraz z interfejsu WWW lub z telefonu

/message1
/message2
/message3

i spójrz w przeglądarce na adres utworzony w zmiennej $URLGET.

Zobaczymy coś takiego:

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

Co to jest? Jakiś złożony obiekt z tablic obiektów zawierających kompleksowy identyfikator wiadomości, identyfikator czatu, identyfikator wysyłania i wiele innych informacji.

Nie musimy jednak zastanawiać się, „co to za obiekt” - część pracy została już za nas wykonana. Zobaczmy, co jest w środku:

Czytanie otrzymanych wiadomości lub część 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. Co powinniśmy teraz z tym zrobić?

Zapiszmy wynikowy plik pod nazwą myfirstbotBT105 lub jak najbardziej ci się podoba, zmień tytuł i skomentuj cały już napisany kod poprzez

<#start comment 105 end comment 105#>

Teraz musimy zdecydować, skąd wziąć słownik (no właśnie, gdzie - na dysku w pliku) i jak będzie on wyglądał.

Oczywiście możesz napisać ogromny słownik bezpośrednio w tekście scenariusza, ale to zupełnie nie ma sensu.
Zobaczmy więc, z czym PowerShell może normalnie współpracować.
Ogólnie rzecz biorąc, nie dba o to, z którym plikiem będzie pracować, dla nas nie ma to znaczenia.
Mamy do wyboru: txt (można, ale po co), csv, xml.
Czy możemy obejrzeć wszystkich? Zobaczmy wszystkich.
Utwórzmy klasę MyVocabClassExample1 i zmienną $MyVocabExample1
Zauważam, że klasa jest napisana bez $

jakiś kod nr 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

Spróbujmy zapisać to do plików za pomocą przykładowy.

Trochę kodu #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

- i pojawia się błąd w linii Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Nie chce dodać: aha, co za szkoda.

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

Zobaczmy co się stanie. Świetny widok tekstu - ale jak go wyeksportować z powrotem? Czy powinienem wprowadzić jakiś rodzaj separatorów tekstu, na przykład przecinki?

Na koniec otrzymujesz „plik wartości rozdzielanych przecinkami (CSV) A PRZESTAŃ CZEKAĆ.
#

$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 

Jak łatwo zauważyć, MS nie wyróżnia się szczególnie logiką, w przypadku podobnej procedury w jednym przypadku stosuje się -FilePath, w innym -Path.

Poza tym w trzecim pliku zniknął język rosyjski, w czwartym okazało się... no cóż, coś się stało. #TYP System.Obiekt[] 00
# „Count”, „Length”, „LongLength”, „Rank”, „SyncRoot”, „IsReadOnly”, „IsFixedSize”, „IsSynchronized”
#
Przepiszmy to trochę:

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

Wydaje się, że pomogło, ale nadal nie podoba mi się ten format.

Szczególnie nie podoba mi się to, że nie mogę umieścić linii z obiektu bezpośrednio w pliku.
Swoją drogą, skoro zaczęliśmy pisać do plików, czy możemy zacząć prowadzić dziennik uruchamiania? Jako zmienną mamy czas, możemy ustawić nazwę pliku.

To prawda, nie ma jeszcze nic do pisania, ale możesz pomyśleć o tym, jak najlepiej obrócić kłody.
Spróbujmy na razie xml.

Trochę xml'a

$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

Eksport do xml ma wiele zalet - czytelność, eksport całego obiektu i brak konieczności dodawania.

Spróbujmy przeczytaj plik xml.

Trochę czytania z xml

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

Wróćmy do zadania. Napisaliśmy plik testowy, przeczytaliśmy go, format przechowywania jest jasny, w razie potrzeby można napisać osobny edytor małych plików, aby dodawać i usuwać linie.

Przypominam, że zadaniem było wykonanie małego bota szkoleniowego.

Format pracy: wysyłam do bota polecenie „przykład”, bot wysyła mi losowo wybrane słowo i transkrypcję, a po 10 sekundach przesyła mi tłumaczenie i komentarz. Potrafimy czytać polecenia, chcielibyśmy także nauczyć się automatycznego wybierania i sprawdzania serwerów proxy oraz kasowania liczników wiadomości.

Odkomentujmy wszystko, co wcześniej uznaliśmy za niepotrzebne, skomentujmy teraz niepotrzebne przykłady za pomocą txt i csv i zapiszmy plik w wersji B106

O tak. Wyślijmy jeszcze coś do bota.

6. Wysyłka z funkcji i nie tylko

Przed przetworzeniem odbioru należy utworzyć funkcję wysłania „przynajmniej czegoś” innego niż wiadomość testowa.

Oczywiście w przykładzie będziemy mieli tylko jedno wysłanie i tylko jedno przetwarzanie, ale co jeśli będziemy musieli zrobić to samo kilka razy?

Łatwiej jest napisać funkcję. Mamy więc zmienną typu object $MyVocabExample4AsArray odczytywaną z pliku w postaci tablicy aż dwóch elementów.
Chodźmy przeczytać.

Jednocześnie zajmiemy się zegarem, będzie nam on potrzebny później (w tym przykładzie właściwie nie będzie nam potrzebny :)

Trochę kodu #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
}

Jak łatwo zauważyć, funkcja wywołuje $MyToken i $MyChatID, które zostały wcześniej zakodowane na stałe.

Nie ma potrzeby tego robić, a jeśli $MyToken to jeden dla każdego bota, to $MyChatID będzie się zmieniać w zależności od czatu.

Ponieważ jednak jest to przykład, na razie go zignorujemy.

Ponieważ $MyVocabExample4AsArray nie jest tablicą, chociaż jest do niej bardzo podobna, to nie możesz tego tak po prostu wziąć poproś o jego długość.

Po raz kolejny będziemy musieli zrobić coś, czego nie da się zrobić - spadochron niezgodny z kodem - weź go i policz

Trochę kodu #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)
# Угадайте сами, какой пример легче читается посторонними людьми.

Losowy interesująca funkcja. Powiedzmy, że chcemy otrzymać 0 lub 1 (w tablicy mamy tylko dwa elementy). Czy ustawiając granice 0..1 otrzymamy „1”?
nie - nie dostaniemy, mamy specjalny przykład Przykład 2: Uzyskaj losową liczbę całkowitą z zakresu od 0 do 99 Get-Random -Maximum 100
Dlatego dla 0..1 musimy ustawić rozmiar 0..2, przy maksymalnej liczbie elementów = 1.

7. Przetwarzanie wiadomości przychodzących i maksymalna długość kolejki

Gdzie zatrzymaliśmy się wcześniej? otrzymaliśmy zmienną $MyMessageGet
i otrzymane z niego $Content4Pars01, z których interesują nas elementy tablicy Content4Pars01.result

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

Wyślijmy botowi /message10, /message11, /message12, /word i jeszcze raz /word i /hello.
Zobaczmy, co mamy:

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

Przejrzyjmy wszystko, co otrzymaliśmy i wyślijmy odpowiedź, jeśli wiadomość była /word
przypadek konstrukcji, który niektórzy określają jako if-elseif, nazywany jest w PowerShell poprzez przełącznik. Jednocześnie w poniższym kodzie zastosowano klucz -wildcard, który jest całkowicie niepotrzebny, a nawet szkodliwy.

Trochę kodu #7.1

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

Uruchommy skrypt kilka razy. Za każdą próbę wykonania otrzymamy dwa razy to samo słowo, szczególnie jeśli popełniliśmy błąd w implementacji random.

Ale przestań. Nie wysłaliśmy ponownie /word, więc dlaczego wiadomość jest przetwarzana ponownie?

Kolejka do wysyłania wiadomości do bota ma skończoną długość (chyba 100 lub 200 wiadomości) i należy ją wyczyścić ręcznie.

Jest to oczywiście opisane w dokumentacji, ale trzeba to przeczytać!

W tym przypadku potrzebujemy parametru ?chat_id, a &timeout, &limit, &parse_mode=HTML i &disable_web_page_preview=true nie są jeszcze potrzebne.

Dokumentacja dla API telegramu jest tutaj
Jest napisane w języku białym i angielskim:
Identyfikator pierwszej aktualizacji, która ma zostać zwrócona. Musi być większy o jeden od najwyższego spośród identyfikatorów wcześniej otrzymanych aktualizacji. Domyślnie aktualizacje rozpoczynają się od najwcześniejszej
niepotwierdzone aktualizacja zostanie zwrócona. Aktualizację uznaje się za potwierdzoną w momencie wywołania metody getUpdates z komunikatem offset wyższy niż jego update_id. Można określić ujemne przesunięcie, aby pobierać aktualizacje, zaczynając od -offset update od końca kolejki aktualizacji. Wszystkie poprzednie aktualizacje zostaną zapomniane.

Spójrzmy na:

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

Tak, zresetujemy go i przepiszemy trochę funkcję. Mamy dwie możliwości - przekazać całą wiadomość do funkcji i przetworzyć ją w całości w funkcji, lub podać tylko ID wiadomości i ją zresetować. Na przykład to drugie wygląda na prostsze.

Poprzednio wyglądał nasz ciąg zapytania „wszystkie wiadomości”.

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

i tak będzie wyglądać

$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 

Nikt nie zabrania Ci najpierw odbierać wszystkich wiadomości, przetwarzać je, a dopiero po pomyślnym przetworzeniu żądania niepotwierdzonego -> potwierdzonego.

Dlaczego ma sens wywoływanie potwierdzenia po zakończeniu całego przetwarzania? W trakcie realizacji możliwa jest awaria i jeśli dla przykładu darmowego chatbota brak pojedynczej wiadomości nie jest niczym specjalnym, to jeśli przetwarzasz czyjąś pensję lub transakcję kartą, wynik może być gorszy.

Jeszcze kilka linijek kodu

$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. Zamiast podsumowania

Wykonywane i pokazywane są podstawowe funkcje - odczytywanie wiadomości, resetowanie kolejki, odczytywanie z pliku i zapisywanie do pliku.

Pozostały już tylko cztery rzeczy do zrobienia:

  • wysłanie poprawnej odpowiedzi na zapytanie na czacie
  • wysłanie odpowiedzi na KAŻDY czat, do którego bot został dodany
  • wykonanie kodu w pętli
  • uruchomienie bota z poziomu harmonogramu systemu Windows.

Wszystkie te zadania są proste i można je łatwo wykonać, czytając dokumentację dotyczącą parametrów takich jak
Ustaw-ExecutionPolicy Unrestricted i -ExecutionPolicy Bypass
cykl formy

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

Dziękuję wszystkim, którzy przeczytali.

Źródło: www.habr.com

Dodaj komentarz