Sjabloon voor de eenvoudigste bot voor Telegram voor leerlingen van de 7e tot de 9e klas in Powershell

Tijdens gesprekken met een vriend kwam ik er ineens achter dat kinderen in de 8e en 10e klas op hun school helemaal niet leren programmeren. Word, Excel en dat is het. Geen Logo, zelfs geen Pascal, en zelfs geen VBA voor Excel.

Ik was erg verrast, opende het internet en ging lezen —
Een van de taken van een profielschoole is het bevorderen van de opvoeding van een nieuw generatie die qua ontwikkelingsniveau en levensstijl voldoet aan de voorwaarden van de informatiesamenleving.
Deze cursus stelt studenten in staat om hun kennis van de basisconstructies van de programmeertaal Pascal in de praktijk te bevestigen. (uit een programma van een gymnasium uit 2017)

Uiteindelijk besloot ik een paar uur te besteden aan het schetsen van een voorbeeld 'hoe maak je een eenvoudige bot - voor scholieren'.

Hieronder geef ik informatie over hoe je weer een eenvoudige bot in PowerShell schrijft en deze laat werken zonder webhook, witte IP-adressen, dedicated servers, on-premise virtuele machines in de cloud en zo verder — op een gewone thuis-PC met gewone Windows.

TLDR: Weer een saaie artikel met grammatische en feitelijke fouten, het lezen niet waard, geen humor, geen afbeeldingen.

Er is niets nieuws in het artikel, bijna alles wat is geschreven, is eerder op Habr gepubliceerd, bijvoorbeeld in artikelen zoals Instructie: Hoe bots te maken in Telegram en Telegram-bot voor systeembeheerders.
Bovendien is het artikel opzettelijk overbodig om niet elke keer naar studieboeken te verwijzen. Er zijn geen verwijzingen naar de band 4, PowerShell Deep Dives of bijvoorbeeld The 5 Pillars of the AWS Well-Architected Framework in de tekst.

In plaats van een inleiding, kan het worden overgeslagen

Laten we het gerust overslaanIn 2006 bracht Microsoft PowerShell 1.0 uit voor toen nog Windows XP, Vista en 2003 server. In sommige opzichten verving het dingen zoals cmdbat-scripts, vb-scripts, Windows Script Host en JScript.

Zelfs nu kan PowerShell alleen worden gezien als de volgende stap na versies van Logo, in plaats van misschien nog steeds gebruikte Delphi (of iets oudere), ondanks de aanwezigheid van lussen, klassen, functies, MS GUI-aanroepen, integratie met Git en zo verder.

PowerShell wordt relatief zelden gebruikt, je komt het misschien tegen in de vorm van PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, PowerShell Web Access en een tiental andere zelden gebruikte programma's en functies. Misschien komt er een tweede adem voor als WSL2, maar dat is niet zeker.

PowerShell heeft drie grote voordelen:

  1. Het is relatief eenvoudig, er is veel literatuur en voorbeelden over, en zelfs in het Russisch, bijvoorbeeld een artikel over Foreach - uit een boek PowerShell in depth - over het verschil tussen () en {}
  2. Het wordt geleverd met de editor ISE, inbegrepen bij Windows. Er is zelfs een debugger aanwezig.
  3. Het roept eenvoudig op componenten voor het bouwen van een grafische interface.

0. Voorbereiding.

We hebben nodig:

  • Een pc met Windows (ik heb Windows 10)
  • Een soort van internetverbinding (bijvoorbeeld via NAT)
  • Voor degenen die beperkte toegang hebben tot Telegram - een geïnstalleerde en geconfigureerde freegate in de browser, in sommige ingewikkelde gevallen samen met Symple DNS Crypt
  • Een werkende Telegram-client op de telefoon
  • Begrip van de basisprincipes - wat een variabele, array, loop is.

Geopende en gelezen artikelen - Instructie: Hoe bots te maken in Telegram en Telegram-bot voor systeembeheerders

1. Laten we een nieuwe testbot maken.

Aangezien iedereen dit al weet en het al eerder is gedaan, kan dit ook overgeslagen wordenZoals hierboven genoemd - Ten eerste, een bot voor Telegram - is nog steeds een applicatie die aan uw kant draait en verzoeken naar de Telegram Bot API verzendt. De API is begrijpelijk - de bot doet verzoeken naar een bepaalde URL met parameters, en Telegram antwoordt met een JSON-object.

Gerelateerde problemen: als u op een of andere manier een stukje code uit een JSON-object neemt en deze per ongeluk uitvoert - de code wordt uitgevoerd op uw systeem.

Het proces om dit te maken is beschreven in de twee artikelen hierboven, maar ik herhaal: open Telegram, open contacten, zoek @botfather, zeg hem /newbot, we maken de bot Botfortest12344321, noemen hem Mynext1234bot, en ontvangen een bericht met een unieke sleutel zoals 1234544311:AbcDefNNNNNNNNNNNNN

Bewaar de sleutel en geef deze niet weg!

Daarna kan de bot ingesteld worden, bijvoorbeeld door hem toe te staan niet aan groepen toegevoegd te worden, maar in de eerste stappen is dit niet nodig.

Vraag BotFather " /mybot " en pas de instellingen aan als er iets niet klopt.

Open opnieuw contacten, zoek @Botfortest12344321 (de zoektocht moet beginnen met @), druk op "start" en schrijf de bot " /Glory to the robots ". Het teken / is verplicht, de aanhalingstekens zijn niet nodig.
De bot zal natuurlijk niet antwoorden.

Laten we controleren of de bot is gemaakt - we openen het.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNN/getMe
waar 1234544311:AbcDefNNNNNNNNNNNNN — de eerder verkregen sleutel,
en we krijgen een string zoals
{"ok":true,"result":{""}}

We hebben de eerste geheime zin (token). Nu moeten we het tweede geheime cijfer weten — de chat-ID met de bot. Elke chat, groep, enzovoorts, is uniek en heeft zijn eigen nummer (soms met een minteken — voor open groepen). Om dit nummer te achterhalen, moeten we in de browser (in feite is het absoluut niet noodzakelijk in de browser, maar voor beter begrip is het handig om daar mee te beginnen) het adres opvragen (waarbij 1234544311:NNNNNNNNN uw token is.

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

en een antwoord krijgen in de vorm van

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

We hebben specifiek chat_id nodig.

Laten we controleren of we handmatig in de chat kunnen schrijven: we roepen vanuit de browser het adres op

https://api.telegram.org/botuwtoken/sendMessage?chat_id=123456789&text="Life is directed motion"

Als er een bericht van de bot in uw chat is gekomen — oké, dan gaat u naar de volgende stap.

Zo kunt u (via de browser) altijd controleren waar de problemen zitten — of het bij u is bij het genereren van de link, of dat er ergens iets geblokkeerd is en niet werkt.

Wat u moet weten voordat u verder leest

In Telegram zijn er verschillende soorten groepschats (open, gesloten). Voor deze chats verschillen sommige functies (bijvoorbeeld id), wat soms voor problemen kan zorgen.

Laten we aannemen dat het eind 2019 is, en zelfs de held van onze tijd, de algemeen bekende Mens-Orkest (beheerder, jurist, infobeveiliging specialist, programmeur en praktisch MVP) Evgeny V. onderscheidt de variabele $i van de array, heeft de lussen onder de knie, en wie weet, in de komende paar jaar, onder de knie zal krijgen Parallel processing met PowerShell en ForEach-Object Parallel en zal het bereiken.

1. Laten we nadenken over wat onze bot zal doen

Ik had geen ideeën, moest nadenken. Ik had al een notitieboek-bot geschreven. Een bot maken "die iets ergens naartoe doorstuurt" leek me niet aantrekkelijk. Voor de verbinding met Azure is een creditcard nodig, maar waarheen kan een leerling die vinden? Het moet worden opgemerkt dat het niet zo slecht is: de belangrijkste cloudproviders bieden een bepaalde gratis testperiode (maar voor een creditcardnummer is het nog steeds nodig — en er zal blijkbaar een dollar van worden afgeschreven. Ik weet niet meer of dat later is teruggekomen.)

Zonder AI ML is het minder interessant om een bot te maken die zomaar dingen doet.

Ik besloot een bot te maken die me (of niet) Engelse woorden uit het woordenboek zou herinneren.
Het woordenboek, om het niet met een database om te hoeven werken, zal in een tekstbestand worden opgeslagen en handmatig worden aangevuld.
In dit geval is de taak om de basisprincipes van het werk te tonen, niet om zelfs maar een gedeeltelijk werkend product te maken.

2. Proberen we iets voor de eerste keer en hoe we dat doen

Laten we een map aanmaken: C:poshtranslate
Laten we eerst kijken wat powershell is; we starten ISE via start-uitvoeren
powershell ise
of we vinden Powershell ISE in de geïnstalleerde programma's.
Na het starten verschijnt er een gewone vertrouwde 'iets van een editor'; als er geen tekstveld is, kunnen we altijd op 'Bestand — nieuw maken' drukken.

Laten we de versie van powershell bekijken — we typen in het tekstveld:

get-host 

en drukken op F5.

Powershell vraagt om op te slaan — 'Het script dat je gaat uitvoeren, zal worden opgeslagen.', laten we akkoord geven en het bestand opslaan in C:poshtranslate met de naam myfirstbotBT100.

Na het uitvoeren krijgen we een gegevensoverzicht in het onderste tekstvak:

Naam             : Windows PowerShell ISE Host
Versie          : 5.1.(enzovoort)

Ik heb 5.1 met iets, dat is genoeg. Als je een oude Windows 7/8 hebt, is dat niet erg — maar PowerShell moet worden bijgewerkt naar versie 5 — bijvoorbeeld via handleiding,.

Typ in de commandoregel onderaan Get-Date, druk op Enter, kijk naar de tijd, ga naar de hoofdmap met het commando
cd
en wis het scherm met het commando cls (nee, gebruik geen rm)

Laten we nu controleren wat en hoe het werkt — we schrijven niet eens code, maar twee regels en proberen te begrijpen wat ze doen. We commentariëren de regel met get-host met het karakter # en voegen een beetje toe.

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

(Interessant. In de dropdown-lijst voor codeformattering op Habra zijn er tientallen opties — maar powershell is daar niet. Dos is er. Perl is er.)

En we voeren de code uit door op F5 of '>' uit de GUI te drukken.

We krijgen de uitvoer:

Zaterdag 8 december 2019 21:00:50 PM (of iets van die strekking)

Laten we nu deze twee regels bekijken en enkele interessante punten om ervoor te zorgen dat we hier later niet meer naar terug hoeven te keren.

In tegenstelling tot Pascal (en niet alleen dat) probeert PowerShell zelf te bepalen welk type het aan de variabele moet toekennen; hierover staat meer in het artikel Informatie over typeringen in programmeertalen
Daarom, als we de variabele $TimeNow aanmaken en deze de huidige datum en tijd (Get-Date) toekennen, hoeven we ons niet al te veel zorgen te maken over het datatype.

Echter, dit onbekende kan later pijnlijk blijken te zijn, maar daar hebben we het later over. Hieronder in de tekst komt een voorbeeld.
Laten we kijken wat we hebben verkregen. Laten we (in de commandoregel) uitvoeren

$TimeNow | Get-member

en we krijgen een pagina met onbegrijpelijke tekst

Voorbeeld van onbegrijpelijke tekst nummer 1

PS C:&gt; $TimeNow | Get-member
   TypeName: System.DateTime
Name                 MemberType     Definitie                                                                                                                                       
----                 ----------     ----------                                                                                                                                       
Add                  <b>Methode         </b>datetime Add(timespan waarde)  
..
DisplayHint          NoteProperty   DisplayHintType DisplayHint=DatumTijd                                                                                                             
Datum                 <b>Eigenschap       </b>datetime Datum {get;}                                                                                                                             
Jaar                 Eigenschap       int Jaar {get;}   
..                                                                                                                               
DatumTijd             ScriptProperty System.Object DatumTijd {get=if ((&amp; { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Datum")...                                         

Zoals te zien is, is er een variabele van het type TypeName: System.DateTime aangemaakt met een hoop methoden (in de zin dat we dingen kunnen doen met dit object/variabele) en eigenschappen.

Laten we aanroepen $TimeNow.DayOfYear — we get the day number of the year.
Laten we aanroepen $TimeNow.DayOfYear | Get-Member — we get TypeName: System.Int32 and a group of methods.
Laten we aanroepen $TimeNow.ToUniversalTime() — and we get the time in UTC

Debugger

Sometimes you may need to run a program up to a certain line and see the state of the program at that moment. For this, there is a Debug function — toggle break point in ISE.
Set a breakpoint somewhere in the middle, run these two lines for execution, and see what the breakpoint looks like.

3. Understanding interaction with the Telegram bot

Of course, there is much more literature written about interacting with the bot, with all the getpush and so on, but the theoretical question can be considered optionally.

In our case, we need to:

  • Learn to send something in the conversation
  • Learn to receive something from the conversation

3.1 We learn to send something in the conversation and receive from it

A bit of code — part 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

and in the Russian Federation at this point we get the error Unable to connect to the remote server.

Or we may not get it — it depends on the service provider and whether the proxy is configured and working.
Well, we need to add a proxy. Keep in mind that using unencrypted and generally non-reliable proxies is very dangerous for your health.

Finding a working proxy is not very difficult — most of the published HTTP proxies work. It seems the fifth one I tried worked.

The syntax using a proxy:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

If you received a message in your chat with the bot — then all is well, you can proceed. If not — continue debugging.

You can see what your string $URL4SEND turns into and try to request it in a browser, like this:

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

3.2. We have learned to write "something" in the chat, now let's try to read

Let's add four more lines and check what's inside via | 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

The most interesting information is provided to us by

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

Let's see what's in them:

Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # hier is iets interessant
Write-Host "RawContent"
$MyMessageGet.RawContent # en hier is ook iets interessant, en bovendien leesbaar.
Write-Host "Content"
$MyMessageGet.Content

Als alles werkt, krijg je een lange string van de volgende aard:

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

Gelukkig, in het eerder gepubliceerde artikel Telegram-bot voor systeembeheerders is deze regel (ja, volgens $MyMessageGet.RawContent | get-member — is dit System.String), al behandeld.

4. Verwerk wat je ontvangen hebt (we weten al hoe we iets kunnen verzenden)

Zoals al geschreven here, het belangrijkste ligt in de content. Laten we er wat beter naar kijken.

Laten we de bot eerst nog een paar zinnen vanuit de webinterface of vanaf de telefoon schrijven

/message1
/message2
/message3

en kijken via de browser naar het adres dat is gevormd in de variabele $URLGET.

We zullen iets zien als:

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

Wat is dit? Een complexe object uit arrays van objecten, die een doorlopend identificatienummer van het bericht, het chat-ID, het verzend-ID en nog veel meer informatie bevatten.

Overigens is het niet nodig om te analyseren "wat voor object dit is" — een deel van het werk is al voor ons gedaan. Laten we kijken wat er binnenin zit:

We lezen de ontvangen berichten of deel 4

Write-Host "Dit is deel 4" <# natuurlijk is deze regel niet nodig in de uiteindelijke tekst, maar het is handig om naar te zoeken. #> 

$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. Wat moeten we hiermee doen

Laten we het ontvangen bestand opslaan onder de naam myfirstbotBT105 of een naam die je leuker vindt, de titel wijzigen en de gehele eerder geschreven code van commentaar voorzien via

<#start comment 105 end comment 105#>

Nu moeten we bepalen waar we het woordenboek vandaan halen (nou ja, waar — op de schijf in een bestand) en hoe het eruit zal zien.

Natuurlijk, we kunnen een enorm woordenboek direct in de tekst van het script zetten, maar dat is helemaal niet praktisch.
Daarom kijken we naar wat PowerShell standaard aankan.
Over het algemeen maakt het niet uit met welk bestand het werkt, maar voor ons is dat wel belangrijk.
Als opties hebben we: txt (kan, maar waarom), csv, xml.
Of we kunnen alles bekijken. Laten we alles bekijken.
We creëren een klasse MyVocabClassExample1 en een variabele $MyVocabExample1
merk op dat de klasse wordt geschreven zonder $

een beetje code #5

write-host "Dit is deel 5"
class MyVocabClassExample1 {
    [string]$Original  # woord
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # heel interessant punt. Het gebruik van int met zijn beperkingen kan soms tot wilde gevolgen leiden, bijvoorbeeld - een recente zaak met SSD HPE. Aanvankelijk voegde ik dit element niet toe, maar later deed ik dat toch en maakte het opmerking.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Appel"
$MyVocabExample1.Example = "Een appel is een zoete, eetbare vrucht geproduceerd door een appelboom (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1

$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Pear"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Peer"
$MyVocabExample2.Example = "De perenboom (ˈpɛər) en struik zijn een soort van het geslacht Pyrus"
# $MyVocabExample1.$VocWordID = 2

Laten we dit proberen op te schrijven in bestanden per voorbeeld.

Een beetje code #5.1

Write-Host $ScriptDir # ik hoop dat $ScriptDir niet is gecommentarieerd 
$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

— en we krijgen een fout op de regel Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Wil niet toevoegen, oh wat jammer.

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

Laten we kijken wat eruit kwam. Prachtige tekstweergave — maar hoe exporteer je het weer terug? Moet ik tekstscheidingstekens invoeren, bijvoorbeeld komma's?

En uiteindelijk een "bestand met scheidingstekens — komma's, comma-separated values (CSV) A STOP WACHT EVEN.
#

$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 

Het is gemakkelijk te zien dat MS niet erg logisch is om dezelfde procedure te volgen; in het ene geval wordt -FilePath gebruikt, in het andere -Path.

Bovendien is het derde bestand de Russische taal kwijtgeraakt, in het vierde bestand is... nou, er is iets gebeurd. #TYPE System.Object[] 00
# „Count“,»Length»,«LongLength»,«Rank»,«SyncRoot»,«IsReadOnly»,«IsFixedSize»,«IsSynchronized»
#
Laten we het een beetje herschrijven:

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

Het leek te helpen — maar het formaat bevalt me nog steeds niet.

Vooral bevalt het me niet dat ik de regels uit het object niet rechtstreeks in een bestand kan plaatsen.
Overigens, nu we al bestanden aan het schrijven zijn, kunnen we misschien beginnen met het bijhouden van een opstartlog? We hebben de tijd als variabele en we kunnen de bestandsnaam instellen.

Er is nog niet echt iets om te schrijven, maar we kunnen nadenken over hoe we de logboeken het beste kunnen rotatieren.
Laten we voorlopig xml proberen.

Een beetje 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

Bij het exporteren naar xml zijn er alleen maar voordelen: leesbaarheid, export van het volledige object, en het is niet nodig om uppend uit te voeren.

Laten we het proberen het bestand xml lezen.

Een beetje lezen van xml

$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray 
# $MyVocabExample4AsArray[0]
# en een beetje over totaal onduidelijk nuances. Powershell gedraagt zich af en toe anders dan je zou verwachten.
# bijvoorbeeld mijn twee uitvoer zijn verschillend
# Write-Output $MyVocabExample4AsArray 
# write-host $MyVocabExample4AsArray 

Laten we teruggaan naar de taak. We hebben een testbestand geschreven, gelezen, het opslagsysteem is duidelijk, indien nodig kunnen we een aparte kleine bestandredacteur schrijven voor het toevoegen en verwijderen van regels.

Ik herinner eraan dat de taak was om een kleine leer bot te maken.

Werkwijze: ik geef de bot het commando 'voorbeeld', de bot stuurt mij een willekeurig woord en transcriptie, en na 10 seconden stuurt hij de vertaling en opmerking. We kunnen de commando's lezen, we moeten natuurlijk ook leren om automatisch proxies te vinden en te controleren, en om de berichttellertjes te resetten.

Laten we alles wat eerder gecommentarieerd was weer ontcommentarieren als onnodig, de voorbeelden met txt en csv die onnodig zijn worden gecommentarieerd, en we slaan het bestand op als versie B106.

Oh ja. Laten we nog iets naar de bot sturen.

6. Verzending vanuit functies en meer

Voordat we de ontvangst verwerken, moeten we een functie maken om 'wat dan ook' te verzenden, behalve het testbericht.

Natuurlijk hebben we in het voorbeeld slechts één verzending en slechts één verwerking, maar wat als we hetzelfde meerdere keren moeten doen?

Het is handiger om een functie te schrijven. Dus, we hebben een objectvariabele $MyVocabExample4AsArray, die vanuit het bestand is ingelezen, in de vorm van een array met maar liefst twee elementen.
Laten we beginnen met lezen.

Tegelijkertijd laten we de klok onderzoeken, we zullen dit later nodig hebben (in dit voorbeeld is het eigenlijk niet nodig 🙂

Een beetje code #6.1

Schrijf-Output "Dit is Deel 6"
$Timezone = (Get-TimeZone)
ALS($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # aangepaste tijd
    ANDERS{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
functie MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # en hier zullen we een fout krijgen
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # maar hier niet, wie het raadt is goed.

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

Zoals je gemakkelijk kunt zien, worden in de functie $MyToken en $MyChatID aangeroepen, die eerder hard zijn toegewezen.

Dit moet je niet doen, en als $MyToken voor elke bot hetzelfde is, zal $MyChatID variëren afhankelijk van de chat.

Maar aangezien dit een voorbeeld is, negeren we dit voorlopig.

Omdat $MyVocabExample4AsArray geen array is, ook al lijkt het er zeer op, kun je het niet zomaar nemen en de lengte ervan opvragen.

We zullen weer iets moeten doen dat niet zou moeten — afwijken van de richtlijnen — gewoon gaan tellen.

Een beetje code #6.2

$MaxRandomExample = 0 
foreach ($Obj in $MyVocabExample4AsArray) {
$MaxRandomExample ++
}
Schrijf-Output $MaxRandomExample
$RandomExample = Get-Random -Minimum 0 -Maximum ($MaxRandomExample)
$TextForExample1 = $MyVocabExample4AsArray[$RandomExample].Original
# MyFirstFunction($TextForExample1)
# of in één regel
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Raad zelf maar, welk voorbeeld makkelijker te lezen is voor derden.

Willekeurig interessante functie. Stel, we willen 0 of 1 krijgen (we hebben maar twee elementen in de array). Bij het instellen van de grenzen 0..1 — krijgen we dan "1"?
nee — dat krijgen we niet, want we hebben speciaal voorbeeld Example 2: Verkrijg een willekeurige gehele tussen 0 en 99 Get-Random -Maximum 100
Daarom moeten we voor 0..1 de grootte 0..2 instellen, waarbij het hoogste nummer dat we kunnen krijgen = 1 is.

7. Verwerking van binnenkomende berichten en maximale lengte van de wachtrij

Waar waren we eerder gebleven? we hebben de verkregen variabele $MyMessageGet
en de verkregen $Content4Pars01, waarvan we geïnteresseerd zijn in de array-elementen Content4Pars01.result

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

We sturen naar de bot /message10, /message11, /message12, /word en nogmaals /word en /hallo.
Laten we eens kijken wat we hebben ontvangen:

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

We zullen alles wat we hebben doorlopen en een antwoord sturen als het bericht /word was.
de case of-structuur, wat sommigen beschrijven als if-elseif, wordt in Powershell aangeroepen via switchIn de onderstaande code wordt de -wildcard sleutel gebruikt, wat helemaal niet nodig is en zelfs schadelijk kan zijn.

Een beetje code #7.1

Write-Output "Dit is deel 7"
Foreach ($Result in $Content4Pars01.result) # Ja, het kan sneller
{ 
    switch -wildcard ($Result.message.text) 
            {
            "\/word" {MyFirstFunction($TextForExample1)}
            }
}

Laten we het script een paar keer uitvoeren. We krijgen elke keer hetzelfde woord, vooral als we een fout hebben gemaakt bij het implementeren van random.

Maar stop. We hebben de \/word nog niet opnieuw verzonden, waarom wordt het bericht dan opnieuw verwerkt?

De wachtrij voor het verzenden van berichten naar de bot heeft een beperkte lengte (ongeveer 100 of 200 berichten) en moet handmatig worden gewist.

Dit staat natuurlijk in de documentatie, maar je moet het wel lezen!

In dit geval hebben we de parameter ?chat_id nodig, en &timeout, &limit, &parse_mode=HTML en &disable_web_page_preview=true zijn voorlopig niet nodig.

Documentatie over telegram api vind je hier
In duidelijke Engelse taal staat er:
Identifier van de eerste update die moet worden geretourneerd. Moet groter zijn met één dan de hoogste onder de identifiers van eerder ontvangen updates. Standaard worden updates vanaf de vroegste weergegeven.
onbevestigd update worden geretourneerd. Een update wordt als bevestigd beschouwd zodra getUpdates wordt aangeroepen met een offset hoger dan zijn update_id. De negatieve offset kan worden opgegeven om updates op te halen die beginnen vanaf -offset update aan het einde van de updates wachtrij. Alle eerdere updates zullen worden vergeten.

Laten we eens kijken naar:

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

En laten we het resetten — laten we de functie een beetje herschrijven. We hebben twee opties — ofwel het hele bericht naar de functie doorgeven en het volledig in de functie verwerken, of alleen het ID van het bericht doorgeven en dat resetten. Voor het voorbeeld lijkt de tweede optie eenvoudiger.

Eerder zag onze aanvraagstring "alle berichten" eruit als

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

en zal eruitzien als

$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 

Niemand verbiedt om eerst alle berichten op te halen, deze te verwerken, en pas na succesvolle verwerking unconfirmed -> confirmed op te vragen.

Waarom is het zinvol om bevestiging aan te roepen na afloop van alle verwerkingen? Er kan een fout optreden halverwege de uitvoering, en als het bijvoorbeeld voor een gratis chatbot niet zo heel erg is om een enkel bericht te missen, kan het resultaat veel erger zijn als je iemands salaris of een transactie met een kaart verwerkt.

Nog een paar regels code

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

8. In plaats van een conclusie

De belangrijkste functies - het lezen van berichten, het resetten van de wachtrij, het lezen uit een bestand en het schrijven naar een bestand zijn uitgevoerd en weergegeven.

Er zijn nog maar vier dingen te doen:

  • het verzenden van het juiste antwoord op de aanvraag in de chat
  • het verzenden van het antwoord naar ELKE chat waar de bot aan is toegevoegd
  • het uitvoeren van de code in een lus
  • de bot starten vanuit de Windows Taakplanner.

Al deze taken zijn eenvoudig en kunnen gemakkelijk worden uitgevoerd met behulp van de documentatie over parameters zoals
Set-ExecutionPolicy Unrestricted en -ExecutionPolicy Bypass
lus van het type

$TimeToSleep = 3 # vragen elke 3 seconden
$TimeToWork = 10 # minuten
$HowManyTimes = $TimeToWork*60/$TimeToSleep # teller voor de lus
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

Iedereen bedankt voor het doorlezen.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster