Během rozhovoru s kamarádem jsem náhle zjistil, že děti ve 8.–10. třídě na jejich škole vůbec nemají výuku programování. Pouze Word, Excel a to je vše. Žádné logo, dokonce ani Pascal, ani VBA pro Excel.
Byl jsem velmi překvapen, otevřel jsem internet a začal číst —
Jedním z úkolů profilové školy je podporovat výchovu nové generace odpovídající svým rozvojovým úrovním a životnímu stylu podmínkám informační společnosti.
Tento kurz umožní upevnit znalosti žáků o základních konstrukcích programovacího jazyka Pascal v praxi. (z nějakého programu gymnázia za rok 2017)
Nakonec jsem se rozhodl věnovat pár hodin a napsat příklad 'jak vytvořit jednoduchého bota — pro školáky'.
Pod mým článkem se dozvíte, jak napsat dalšího jednoduchého bota na PowerShell a donutit ho pracovat bez webhooku, veřejných IP adres, dedikovaných serverů, nasazovaných virtuálek v cloudu a podobně — na běžném domácím PC s běžným Windows.
TLDR: Ještě jeden nudný článek s gramatickými a faktickými chybami, není co číst, žádný humor, žádné obrázky.
V článku není nic nového, téměř všechno, co je napsáno, bylo už dříve na Habru, například v článcích a .
Kromě toho je článek záměrně nadbytečný, aby se každý okamžik neodkazovalo na učební literaturu. Žádné odkazy na banda 4, PowerShell Deep Dives nebo například The 5 Pillars of the AWS Well-Architected Framework v textu nejsou.
Místo předmluvy, může být vynecháno
S odvahou vynechávámeV roce 2006 Microsoft vydal PowerShell 1.0 pro tehdy ještě Windows XP, Vista a Server 2003. V něčem nahradil například skripty cmdbat, vb skripty, Windows Script Host a JScript.
I dnes lze PowerShell považovat pouze za další krok po variantách Logo, na rozdíl od stále používaných Delphi (nebo nějaké starší technologie), i přes jeho cykly, třídy, funkce, volání MS GUI, a tak dále.
PowerShell se používá relativně zřídka, setkat se s ním lze pouze jako s PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, a ještě se desítkou dalších zřídka používaných programů a funkcí. Možná, že jeho druhý dech přijde s vydáním , ale to není jisté.
PowerShell má také tři velké výhody:
- Je to relativně jednoduché, existuje spousta literatury a příkladů, dokonce i v češtině, například článek o Foreach - z knihy — o rozdílu () a {}
- Dodává se spolu s editorem , součástí Windows. Dokonce je tam nějaký debugger.
- Snadno se vyvolávají .
0. Příprava.
Budeme potřebovat:
- PC s Windows (mám Windows 10)
- Nějaký přístup k internetu (například přes NAT)
- Pro ty, kteří mají omezený přístup k Telegramu — nainstalovaný a nastavený Freegate v prohlížeči, v některých složitějších případech společně se Symple DNS Crypt
- Funkční klient Telegram na telefonu
- Základní znalosti — co je proměnná, pole, cyklus.
Otevřené a přečtené články — a
1. Vytvoříme další testovací bota.
Jelikož to už všichni vědí a bylo to již zmíněno, můžete to také přeskočitJak je uvedeno v článku výše — především, bot pro Telegram — je to stále aplikace spuštěná na vaší straně, která provádí požadavky na Telegram Bot API. API je srozumitelné — bot se obrací na určitý URL s parametry a Telegram odpovídá JSON objektem.
S tím související problém: pokud nějakým nepřehledným způsobem vezmete nějaký kód z JSON objektu a nějak ho odešlete na vykonání (neúmyslně) — kód se u vás vykoná.
Proces vytvoření je popsán ve dvou článcích výše, ale opakuji: v Telegramu otevřeme kontakty, hledáme @botfather, říkáme mu /newbot, vytvoříme bota Botfortest12344321, nazveme ho Mynext1234bot a dostáváme zprávu s unikátním klíčem ve formátu 1234544311:AbcDefNNNNNNNNNNNNN
Klíč si chraňte a nedávejte ho!
Dále by se dal bot nastavit, například zakázat jeho přidání do skupin, ale na začátku to není potřeba.
Zeptáme se BotFather na „/mybot“ a opravíme nastavení, pokud nám něco nevyhovuje.
Opět otevřeme kontakty, najdeme tam @Botfortest12344321 (začínáme hledání s @ nutně), stiskneme „začít“ a napíšeme botovi „/Sláva robotům“. Znak / je povinný, uvozovky nejsou nutné.
Bot samozřejmě nic neodpoví.
Zkontrolujeme, že bot byl vytvořen - otevřeme ho.
:AbcDefNNNNNNNNNNNNN/getMe
kde 1234544311:AbcDefNNNNNNNNNNNNN — dříve získaný klíč,
a dostaneme řetězec ve formátu
{“ok”:true,“result”:{“”}}
První tajná fráze (token) už máme. Nyní musíme zjistit druhé tajné číslo — ID chatu s botem. Každý chat, skupina atd. jsou individuální a mají své vlastní číslo (někdy s mínusem — pro otevřené skupiny). Abychom zjistili toto číslo, musíme v prohlížeči vyžádat adresu (ve skutečnosti vůbec není nutné v prohlížeči, ale pro lepší porozumění je dobré začít odtud) adresu (kde 1234544311:NNNNNNNNN — to je váš token
https://api.telegram.org/bot1234544311:NNNNNNNNN/getUpdates
a dostat odpověď typu
{"ok":true,"result":[{"update_id":…,… chat":{"id":123456789
Potřebujeme právě chat_id.
Zkontrolujeme, že do chatu můžeme psát ručně: vyvoláme z prohlížeče adresu
https://api.telegram.org/botváš_token/sendMessage?chat_id=123456789&text="Life is directed motion"Pokud vám do chatu přišla zpráva od bota — v pořádku, přecházíte na další krok.
Tímto způsobem (přes prohlížeč) vždy můžete zkontrolovat, kde jsou problémy — zda u vás při generaci odkazu, nebo jestli je něco, co je zakryté a nefunguje.
Co potřebujete vědět před pokračováním v čtení
V Telegramu existuje několik typů skupinových chatů (otevřené, uzavřené). Pro tyto chaty se některé funkce (například id) liší, což někdy vyvolává určité problémy.
Představme si, že je konec roku 2019, a i hrdina naší doby, široce známý Člověk-Orchestr (administrátor, právník, odborník na informační bezpečnost, programátor a prakticky MVP) Evgenij V. odlišuje proměnnou $i od pole, ovládl cykly, a kdo ví, možná během následujících pár let zvládne Chocolatey, a pak do a dojde.
1. Přemýšlíme, co bude náš bot dělat
Neměl jsem žádné nápady, musel jsem přemýšlet. Bot, který by sloužil jako zápisník, jsem již psal. Nechtěl jsem dělat bota „který něco přeposílá někam“. Pro připojení Azure je potřeba kreditní karta, ale odkud ji vezme školák? Je třeba poznamenat, že to není tak zlé: hlavní cloudové služby nabízejí nějaké zkušební období zdarma (ale číslo kreditky je i tak potřeba — a z něj bude stržen, zdá se, jeden dolar. Nevím, jestli se vrátil později.)
Bez AI a ML není tak zábavné dělat bota-berňáka-versa přeposílatele.
Rozhodl jsem se udělat bota, který mi (nebo mi) bude připomínat anglická slova podle slovníku.
Slovník, abych se nemusel zabývat DB, bude uložen v textovém souboru a bude doplňován ručně.
V tomto případě je cílem ukázat základy práce, nikoli vytvořit alespoň částečně hotný produkt.
2. Zkoušíme, jak a co poprvé
Vytvoříme složku C:poshtranslate
Nejdříve se podíváme, co máme za PowerShell, spustíme ISE přes Start-Spustit
powershell ise
nebo najdeme PowerShell ISE v nainstalovaných programech.
Po spuštění se otevře běžný známý "nějaký editor", pokud tam nebude textové pole, vždy můžeme stisknout "Soubor – vytvořit nový".
Podíváme se na verzi PowerShell – napíšeme do textového pole:
get-host
a stiskneme F5.
PowerShell nabídne uložení – „Skript, který hodláte spustit, bude uložen.“, souhlasíme a uložíme do C:poshtranslate soubor z PowerShell s názvem myfirstbotBT100.
Po spuštění získáme v dolním textovém okně tabulku dat:
Jméno : Windows PowerShell ISE Host
Verze : 5.1.(a tak dále)
Mám 5.1 s něčím, to stačí. Pokud máte starý Windows 7/8, nevadí – i když je třeba PowerShell aktualizovat na verzi 5 – například podle .
Napíšeme do příkazového řádku dole Get-Date, stiskneme Enter, podíváme se na čas, přejdeme do root složky příkazem
cd
a vyčistíme obrazovku příkazem cls (ne, nemusíte používat rm)
Teď zkontrolujeme, co a jak funguje – napíšeme dokonce ne kód, ale dvě řádky, a pokusíme se pochopit, co dělají. Řádek s get-host zakomentujeme symbolem # a trochu dopíšeme.
# Пример шаблона бота
# get-host
<# это пример многострочного комментария #>
$TimeNow = Get-Date
$TimeNow
(Co je zajímavé. V rozbalovacím seznamu formátování kódu na Habru je dvacet variant – ale PowerShell tam není. Dos je. Perl je.)
A spustíme kód, stisknutím F5 nebo „>“ z GUI.
Získáme výstup:
Sobota, 8. prosince 2019 21:00:50 PM (nebo něco podobného)
Teď se podíváme na tyto dvě řádky a na některé zajímavé momenty, abychom se k tomu v budoucnu nemuseli vracet.
Na rozdíl od Pascalu (a nejen toho), PowerShell se sám snaží určit, jaký typ přiřadit proměnné, podrobněji o tom se píše v článku
Proto při vytváření proměnné $TimeNow a přiřazení aktuálního data a času (Get-Date) se nemusíme obávat, jaký typ dat tam bude.
Pravda, neznalost může později bolet, ale to je později. Níže v textu bude příklad.
Podíváme se, co jsme dostali. Provedeme (v příkazovém řádku)
$TimeNow | Get-membera získáme stránku nesrozumitelného textu
Příklad nesrozumitelného textu číslo 1
PS C:> $TimeNow | Get-member
TypeName: System.DateTime
Name MemberType Definition
---- ---------- ----------
Přidat <b>Metoda </b>datetime Přidat(timespan value)
..
ZobrazitNápověda NoteProperty DisplayHintType DisplayHint=DateTime
Datum <b>Vlastnost </b>datetime Datum {get;}
Rok Vlastnost int Rok {get;}
..
DateTime ScriptProperty System.Object DateTime {get=if ((& { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq "Datum")...
Jak vidno, byla vytvořena proměnná typu TypeName: System.DateTime s množstvím metod (tj. co můžeme dělat s tímto objektem/proměnnou) a vlastností.
Zavoláme $TimeNow.DayOfYear — získáme číslo dne v roce.
Zavoláme $TimeNow.DayOfYear | Get-Member — získáme TypeName: System.Int32 a skupinu metod.
Zavoláme $TimeNow.ToUniversalTime() — a získáme čas ve formátu UTC
Ladicí nástroj
Někdy je potřeba provést program do určitého řádku a podívat se na stav programu v tuto chvíli. K tomu má ISE funkci Debug — toggle break point.
Umístěte breakpoint někde uprostřed, spusťte tyto dva řádky k provedení a podívejte se, jak vypadá zastavení.
3. Zkoumáme interakci s Telegram botem
Samozřejmě, že o interakci s botem, se všemi getpush atd. bylo napsáno ještě více literatury, avšak otázku teorie můžeme považovat za fakultativní.
V našem případě je potřeba:
- Naučit se něco posílat do konverzace
- Naučit se něco získávat z konverzace
3.1 Učíme se posílat něco do konverzace a získávat z ní
Trochu kódu — část 3
Write-output "Toto je část 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 = "Život je řízený pohyb - " + $TimeNow
$URL4SEND = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText01"
Invoke-WebRequest -Uri $URL4SEND
a v RF na tomto místě dostáváme chybu Unable to connect to the remote server.
Nebo nedostáváme — záleží na operátorovi sítě a na tom, zda je proxy nastavena a funguje.
Což — zbývá přidat proxy. Berte na vědomí — používání nešifrované a vůbec cizí proxy je velmi nebezpečné pro vaše zdraví.
Úkol hledání funkční proxy není příliš obtížný — většina publikovaných http proxy funguje. Mělo to úspěch myslím až na pátý pokus.
Syntaxe s použitím proxy:
Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy
Pokud jste dostali zprávu do svého chatu s botem — pak je vše skvělé, můžete pokračovat. Pokud ne — pokračujte v ladění.
Můžete se podívat, v co se vaše řetězec $URL4SEND proměňuje a vyzkoušet jej vyžádat v prohlížeči, například takto:
$URL4SEND2 = '"'+$URL4SEND+'"'
start chrome $URL4SEND2
3.2. Psát „něco“ do chatu jsme se naučili, nyní zkusíme číst
Přidáme ještě 4 řádky a podíváme se, co tam uvnitř je přes | 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
Nejzajímavější nám poskytuje
Content Property string Content {get;}
ParsedHtml Property mshtml.IHTMLDocument2 ParsedHtml {get;}
RawContent Property string RawContent {get;set;}Podíváme se, co v nich je:
Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # zde je zajímavé
Write-Host "RawContent"
$MyMessageGet.RawContent # a zde je to také zajímavé, ale navíc také čitelné.
Write-Host "Content"
$MyMessageGet.Content
Pokud vše funguje, dostanete dlouhý řetězec ve tvaru:
{"ok":true,"result":[{"update_id":12345678,
"message":{"message_id":3,"from":{"id"Naštěstí, v dříve vydaném článku o Telegram-botu pro systémové administrátory byl tento řetězec (ano, podle $MyMessageGet.RawContent | get-member — je to System.String), již byl rozebrán.
4. Zpracovat získané (posílat něco už umíme)
Jak už bylo napsáno , to nejdůležitější leží v obsahu. Podíváme se na to blíže.
Nejprve napíšeme botovi ještě pár frází z webového rozhraní nebo z telefonu
/message1
/message2
/message3a podíváme se přes prohlížeč na adresu, která se vytvořila v proměnné $URLGET.
Uvidíme něco jako:
{"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 je? Nějaký složitý objekt z polí objektů, obsahující průběžný identifikátor zprávy, identifikátor chatu, identifikátor odeslání a spoustu dalších informací.
Nicméně, nemusíme zkoumat "co to za objekt je" — část práce už byla odvedena za nás. Podívejme se, co je uvnitř:
Čteme přijaté zprávy nebo část 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 s tím nyní dělat
Uložíme získaný soubor pod názvem myfirstbotBT105 nebo jak se vám líbí, změníme název a zakomentujeme celý dosavadní kód pomocí
<#start comment 105 end comment 105#>
Nyní si musíme ujasnit, kde vzít slovník (no jak, na disku v souboru) a jak bude vypadat.
Samozřejmě, že můžete narvat obrovský slovník přímo do textu skriptu, ale to prostě není v pořádku.
Tak se podíváme, s čím standardně pracuje PowerShell.
Vlastně je mu jedno, s jakým souborem pracuje, nám to ale jedno není.
Na výběr máme: txt (můžeme, ale proč), csv, xml.
Nebo můžeme podívat na všechny. Podíváme se na všechny.
Vytvoříme třídu MyVocabClassExample1 a proměnnou $MyVocabExample1
poznamenám, že třída se píše bez $
trochu kódu #5
write-host "Toto je část 5"
class MyVocabClassExample1 {
[string]$Original # slovo
[string]$Transcript
[string]$Translate
[string]$Example
[int]$VocWordID # velmi zajímavý moment. Použití int s jeho omezeními může občas vést k podivným následkům, například nedávný případ s SSD HPE. Původně jsem tento prvek nepřidal, ale nakonec jsem ho doplnil a okomentoval.
}
$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Jablko"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Jablko"
$MyVocabExample1.Example = "Jablko je sladké, jedlé ovoce produkované jabloňovým stromem (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1
$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Hruška"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Hruška"
$MyVocabExample2.Example = "Hruška (/20ˈpɛər20/) strom a keř jsou druhem rodu Pyrus"
# $MyVocabExample1.$VocWordID = 2
Zkusíme to zapsat do souborů podle .
Trochu kódu #5.1
Write-Host $ScriptDir # doufám, že $ScriptDir jste neokomentovali
$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
— a dostaneme chybu na řádku Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.
Nechce přidávat, ach jaká škoda.
$MyVocabExample3AsArray = @($MyVocabExample1,$MyVocabExample2)
Out-File -FilePath $MyFilenameExample02 -InputObject $MyVocabExample3AsArray
notepad $MyFilenameExample02
Podíváme se, co z toho vyšlo. Krásný textový výstup — ale jak ho exportovat zpět? Zavést nějaké textové oddělovače, například čárky?
A nakonec získat „soubor s oddělovači — čárkami, values separated by commas (CSV) A .
#
$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 snadno vidět, MS se příliš neliší logikou, pro podobný postup v jednom případě používá -FilePath, pro druhý -Path.
Kromě toho v třetím souboru zmizel ruský jazyk, ve čtvrtém souboru to vyšlo… no něco vyšlo. #TYPE System.Object[] 00
# „Count“,»Length»,«LongLength»,«Rank»,«SyncRoot»,«IsReadOnly»,«IsFixedSize»,«IsSynchronized»
#
Trochu to přepracujeme:
Export-Csv -Path $MyFilenameExample03 -InputObject $MyVocabExample1 -Encoding Unicode
Export-Csv -Path $MyFilenameExample03 -InputObject $MyVocabExample2 -Append -Encoding Unicode
notepad $MyFilenameExample03
notepad $MyFilenameExample04
Vypadá to, že to pomohlo — ale formát se mi stejně nelíbí.
Obzvlášť se mi nelíbí, že nemohu uložit řádky z objektu přímo do souboru.
Mimochodem, když jsme začali psát do souborů, mohli bychom začít vést log spuštění? Čas jako proměnnou máme, jméno souboru jsme schopni nastavit.
Psaní, pravda, zatím moc nemáme, ale můžeme přemýšlet, jak nejlépe provést rotaci logů.
Zatím zkusíme xml.
Trochu 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
Export do xml má samé výhody — čitelnost, export celého objektu, a není potřeba provádět uppend.
Zkusíme .
Trochu čtení z xml
$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray
# $MyVocabExample4AsArray[0]
# a k některým úplně nejasným nuancím. Powershell se občas chová jinak, než bychom očekávali.
# například, tyto dva výstupy se liší
# Write-Output $MyVocabExample4AsArray
# write-host $MyVocabExample4AsArray
Vraťme se k úkolu. Zkušební soubor jsme zapsali, přečetli, formát uložení je jasný, v případě potřeby můžeme napsat samostatného malého editora souboru pro přidávání a odstraňování řádků.
Připomínám, že úkol byl vytvořit malého vzdělávacího bota.
Formát práce: posílám botovi příkaz "příklad", bot mi pošle náhodně vybrané slovo a transkripci, a po 10 sekundách pošle překlad a komentář. Číst příkazy už umíme, bylo by hezké také se naučit automaticky vybírat a kontrolovat proxy, a resetovat počítadla zpráv do zapomnění.
Odkomentujeme vše dříve zakomentované jako zbytečné, zakomentujeme příklady s txt a csv, které se staly zbytečnými, a uložíme soubor jako verzi B106.
A, ano. Pošleme něco botovi ještě jednou.
6. Odesílání z funkcí a nejen to
Než začneme zpracovávat příjem, musíme vytvořit funkci pro odesílání "něčeho", kromě testovací zprávy.
Samozřejmě, v příkladu máme pouze jedno odeslání a pouze z jednoho zpracování, a co když budeme potřebovat udělat to samé několikrát?
Snazší je napsat funkci. Takže máme proměnnou typu objekt $MyVocabExample4AsArray, přečtenou ze souboru, ve formě pole se dvěma prvky.
Zároveň se podíváme na hodiny, to se nám pak bude hodit (ve skutečnosti v tomto příkladu — nebude to potřeba 🙂
Trochu kódu #6.1
Write-Output "This is Part 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # přepočítaný čas
ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds)
}
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # a tady dostaneme chybu
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # a tady ne, kdo hádá proč - ten je šikovný.
$URL4SendFromFunction = "https://api.telegram.org/bot$MyToken/sendMessage?chat_id=$MyChatID&text=$MyText02"
Invoke-WebRequest -Uri $URL4SendFromFunction -Proxy $MyProxy
}
Jak snadno vidět, že ve funkci se volá $MyToken a $MyChatID, které byly dříve zafixovány.
Takto se to dělat nemá, a pokud je $MyToken stejný pro každého bota, $MyChatID se bude měnit v závislosti na chatu.
Nicméně, protože je to příklad, zatím to ignorujeme.
Protože $MyVocabExample4AsArray není pole, ačkoliv je mu velmi podobné, nelze prostě vzít a zjistit jeho délku.
Bude nutné udělat znovu to, co se dělat nemá — seskočit mimo kodex — vzít a spočítat
Trocha kódu #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)
# nebo v jednom řádku
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Hádejte sami, který příklad se lépe čte cizími lidmi.
Random . Řekněme, že chceme získat 0 nebo 1 (máme jen dva prvky v poli). Při zadání rozsahu 0..1 — dostaneme "1"?
ne — nedostaneme, máme speciálně připravený příklad Example 2: Získání náhodného celého čísla mezi 0 a 99 Get-Random -Maximum 100
Proto pro 0..1 musíme zadat velikost 0..2, přičemž maximální číslo prvku = 1.
7. Zpracování přijatých zpráv a maximální délka fronty
Na čem jsme se dříve zastavili? máme proměnnou $MyMessageGet
a z ní získanou $Content4Pars01, z níž nás zajímají prvky pole Content4Pars01.result
$Content4Pars01.result[0].update_id
$Content4Pars01.result[0].message
$Content4Pars01.result[0].message.text Pošleme botovi /message10, /message11, /message12, /word a ještě jednou /word a /ahoj.
Podíváme se, co jsme dostali:
$Content4Pars01.result[0].message.text
$Content4Pars01.result[2].message.text Projdeme všechny přijaté a odešleme odpověď, pokud byla zpráva /word
konstuktce case of, to co někteří popisují jako if-elseif, v powershellu se volá Přitom v níže uvedeném kódu byl použit klíč -wildcard, což není zcela nutné a dokonce i škodlivé.
Trocha kódu #7.1
Write-Output "Toto je část 7"
Foreach ($Result in $Content4Pars01.result) # Ano, lze to udělat rychleji
{
switch -wildcard ($Result.message.text)
{
"\/word" {MyFirstFunction($TextForExample1)}
}
}
Skript provedeme několikrát. Obdržíme dvakrát stejné slovo při každém pokusu o provedení, zejména pokud jsme udělali chybu v implementaci random.
Ale počkej. My jsme ještě neposlali \/word znovu, proč se tedy zpráva zpracovává znovu?
Fronta pro posílání zpráv botovi má konečnou délku (zdá se, 100 nebo 200 zpráv), a je třeba ji vyčistit ručně.
V dokumentaci je to samozřejmě popsáno, ale tu je třeba číst!
V tomto případě potřebujeme parametr ?chat_id, a &timeout, &limit, &parse_mode=HTML a &disable_web_page_preview=true zatím nejsou potřeba.
Dokumentace k Anglicky je tam napsáno:
Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates. By default, updates starting with the earliest
unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id. The negative offset can be specified to retrieve updates starting from -offset update from the end of the updates queue. All previous updates will forgotten.
Podívejme se na:
$Content4Pars01.result[0].update_id
$Content4Pars01.result[1].update_id
$Content4Pars01.result | select -last 1
($Content4Pars01.result | select -last 1).update_idA resetneme to — trochu přepíšeme funkci. Máme dvě možnosti — předat funkci celou zprávu a zpracovat ji celou ve funkci, nebo pouze vrátit ID zprávy a její vymazání. Pro příklad druhé vypadá jednodušeji.
Dříve vypadala naše dotazovací řetězec "veškerých zpráv" jako
$URLGET = "https:\/\/api.telegram.org\/bot$MyToken\/getUpdates"a vypadat bude jako
$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
Nikdo nezakazuje nejprve získat všechny zprávy, zpracovat je a teprve po úspěšném zpracování požádat unconfirmed -> confirmed.
Proč dává smysl vyžadovat potvrzení po dokončení všech zpracování? Může dojít k selhání uprostřed provádění, a pokud pro příklad bezplatného chatbotu přeskočení nějaké jednotlivé zprávy není ještě tak důležité, tak pokud zpracováváte něčí plat nebo transakci kartou, výsledek může být horší.
Ještě pár řádků kódu
$LastMessageId = ($Content4Pars01.result | select -last 1).update_id #chybu v tomto místě je třeba opravit samostatně.
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100"
Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy
8. Místo závěru
Hlavní funkce — čtení zpráv, vyprázdnění fronty, čtení ze souboru a zápis do souboru byly vykonány a ukázány.
Zbývá udělat pouze čtyři věci:
- odeslání správné odpovědi na dotaz v chatu
- odeslání odpovědi do JAKÉHOKOLI chatu, do kterého byl přidán bot
- provádění kódu v cyklu
- spuštění bota z plánovače Windows.
Všechny tyto úkoly jsou jednoduché a snadno realizovatelné pomocí dokumentace k takovým parametrům, jako jsou
Set-ExecutionPolicy Unrestricted a -ExecutionPolicy Bypass
cyklu typu
$TimeToSleep = 3 # dotazování každé 3 sekundy
$TimeToWork = 10 # minut
$HowManyTimes = $TimeToWork*60/$TimeToSleep # čítač pro cyklus
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++
Děkuji všem, kdo dočetli.
Zdroj: habr.com
