Πρότυπο για ένα απλό bot τηλεγραφήματος για μαθητές των τάξεων 7-9 χρησιμοποιώντας το Powershell

Κατά τη διάρκεια συνομιλιών με έναν φίλο, ξαφνικά έμαθα ότι τα παιδιά των τάξεων 8-10 στο σχολείο τους δεν διδάσκονται καθόλου προγραμματισμό. Word, Excel και τα πάντα. Ούτε λογότυπο, ούτε Pascal, ούτε καν VBA για Excel.

Ήμουν πολύ έκπληκτος, άνοιξα το Διαδίκτυο και άρχισα να διαβάζω -
Ένα από τα καθήκοντα ενός εξειδικευμένου σχολείου είναι η προώθηση της εκπαίδευσης μιας νέας γενιάς που πληροί τις συνθήκες της κοινωνίας της πληροφορίας στο επίπεδο ανάπτυξης και του τρόπου ζωής της.
Αυτό το μάθημα θα επιτρέψει στους φοιτητές να εμπεδώσουν στην πράξη τις γνώσεις τους για τις βασικές δομές της γλώσσας προγραμματισμού Pascal. (από το πρόγραμμα κάποιου γυμνασίου για το 2017)

Στο τέλος, αποφάσισα να περάσω μερικές ώρες και να σκιαγραφήσω ένα παράδειγμα «πώς να δημιουργήσω ένα απλό bot για μαθητές».

Κάτω από την περικοπή είναι πώς να γράψετε ένα άλλο απλό bot στο Powershell και να το κάνετε να λειτουργεί χωρίς webhook, λευκές IP, αποκλειστικούς διακομιστές, αναπτυγμένες εικονικές μηχανές στο cloud και ούτω καθεξής - σε έναν κανονικό οικιακό υπολογιστή με κανονικά Windows.

TLDR: Άλλο ένα βαρετό άρθρο με γραμματικά και πραγματολογικά λάθη, τίποτα να διαβάσετε, χωρίς χιούμορ, χωρίς εικόνες.

Δεν υπάρχει τίποτα καινούργιο στο άρθρο, σχεδόν ό,τι γράφτηκε πριν έχει ήδη κυκλοφορήσει στο Habré, για παράδειγμα σε άρθρα Οδηγίες: Πώς να δημιουργήσετε bots στο Telegram и Telegram bot για διαχειριστή συστήματος.
Επιπλέον, το άρθρο είναι σκόπιμα περιττό για να μην αναφέρεται κάθε φορά στην εκπαιδευτική βιβλιογραφία. Δεν υπάρχουν αναφορές στο Gang 4, στο PowerShell Deep Dives ή, ας πούμε, στο The 5 Pillars of the AWS Well-Architected Framework.

Αντί για πρόλογο, μπορείτε να παραλείψετε

Μη διστάσετε να παραλείψετεΤο 2006, η Microsoft κυκλοφόρησε το PowerShell 1.0 για τα τότε Windows XP, Vista και Server 2003. Κατά κάποιο τρόπο, αντικατέστησε πράγματα όπως σενάρια cmdbat, σενάρια vb, Windows Script Host και JScript.

Ακόμη και τώρα, το PowerShell μπορεί να θεωρηθεί μόνο ως το επόμενο βήμα μετά τις επιλογές Logo, αντί του πιθανώς ακόμα χρησιμοποιούμενου Delphi (ή κάτι παλαιότερο), παρά την παρουσία βρόχων, κλάσεων, συναρτήσεων, κλήσεων MS GUI, Ενσωμάτωση Git και ούτω καθεξής.

Το Powershell χρησιμοποιείται σχετικά σπάνια· μπορείτε να το συναντήσετε μόνο με τη μορφή PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, PowerShell Web Access και καμιά δεκαριά προγράμματα και λειτουργίες που χρησιμοποιούνται σπάνια. Ίσως αποκτήσει δεύτερο άνεμο με την απελευθέρωση WSL2, αλλά δεν είναι ακριβώς.

Το Powershell έχει επίσης τρία μεγάλα πλεονεκτήματα:

  1. Είναι σχετικά απλό, υπάρχει πολλή λογοτεχνία και παραδείγματα γι 'αυτό, ακόμη και στα ρωσικά, για παράδειγμα, ένα άρθρο για το Foreach - από το βιβλίο PowerShell σε βάθος - σχετικά με τη διαφορά () και {}
  2. Πηγαίνει με τον αρχισυντάκτη ISE, περιλαμβάνεται στα Windows. Υπάρχει ακόμη και κάποιο είδος εντοπισμού σφαλμάτων εκεί.
  3. Είναι εύκολο να καλέσετε από αυτό στοιχεία για τη δημιουργία μιας γραφικής διεπαφής.

0. Προετοιμασία.

Θα χρειαστούμε:

  • Υπολογιστής με Windows (έχω Windows 10)
  • Τουλάχιστον κάποιου είδους πρόσβαση στο Διαδίκτυο (μέσω NAT για παράδειγμα)
  • Για όσους έχουν περιορισμένη πρόσβαση στο telegram - εγκατεστημένο και ρυθμισμένο freegate στο πρόγραμμα περιήγησης, σε ορισμένες δύσκολες περιπτώσεις, μαζί με το Symple DNS Crypt
  • Έχοντας έναν πελάτη τηλεγραφήματος που λειτουργεί στο τηλέφωνό σας
  • Κατανόηση των πολύ βασικών - τι είναι μια μεταβλητή, πίνακας, βρόχος.

Άνοιξε και διάβασε άρθρα - Οδηγίες: Πώς να δημιουργήσετε bots στο Telegram и Telegram bot για διαχειριστή συστήματος

1. Ας δημιουργήσουμε ένα άλλο δοκιμαστικό bot.

Εφόσον όλοι το γνωρίζουν ήδη αυτό και έχει ήδη συμβεί, μπορείτε επίσης να το παραλείψετεΌπως αναφέρεται στο παραπάνω άρθρο - Πρώτα απ 'όλα, ένα bot για το Telegram - εξακολουθεί να είναι μια εφαρμογή που εκτελείται από την πλευρά σας και κάνει αιτήματα στο Telegram Bot API. Επιπλέον, το API είναι σαφές - το bot έχει πρόσβαση σε μια συγκεκριμένη διεύθυνση URL με παραμέτρους και το Telegram αποκρίνεται με ένα αντικείμενο JSON.

Σχετικά προβλήματα: εάν με κάποιο άγνωστο τρόπο πάρετε κάποιο κώδικα από ένα αντικείμενο JSON και τον στείλετε με κάποιο τρόπο για εκτέλεση (όχι επίτηδες), ο κώδικας θα εκτελεστεί για εσάς.

Η διαδικασία δημιουργίας περιγράφεται σε δύο παραπάνω άρθρα, αλλά επαναλαμβάνω: σε ένα τηλεγράφημα ανοίγουμε επαφές, αναζητούμε τον @botfather, του λέμε /newbot, δημιουργούμε ένα bot Botfortest12344321, το ονομάζουμε Mynext1234bot και λαμβάνουμε ένα μήνυμα με ένα μοναδικό κλειδί του έντυπο 1234544311:AbcDefNNNNNNNNNNNNNN

Φροντίστε το κλειδί και μην το δώσετε!

Στη συνέχεια, μπορείτε να διαμορφώσετε το bot, για παράδειγμα, να απαγορεύσετε την προσθήκη του σε ομάδες, αλλά στα πρώτα βήματα αυτό δεν είναι απαραίτητο.

Ας ζητήσουμε από τον BotFather το “/mybot” και ας προσαρμόσουμε τις ρυθμίσεις αν κάτι δεν μας αρέσει.

Ας ανοίξουμε ξανά τις επαφές, βρούμε το @Botfortest12344321 εκεί (είναι υποχρεωτικό να ξεκινήσετε την αναζήτηση με @), κάντε κλικ στο "start" και γράψτε στο bot "/Glory to the robots". Το σύμβολο / απαιτείται, δεν χρειάζονται εισαγωγικά.
Το bot, φυσικά, δεν θα απαντήσει τίποτα.

Ας ελέγξουμε ότι το bot έχει δημιουργηθεί και ας το ανοίξουμε.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNNN/getMe
όπου 1234544311:AbcDefNNNNNNNNNNNNNN είναι το κλειδί που ελήφθη προηγουμένως,
και πάρτε μια γραμμή όπως
{"ok":true,"result":{""}}

Έχουμε την πρώτη μυστική φράση (κουπόνι). Τώρα πρέπει να μάθουμε τον δεύτερο μυστικό αριθμό - το αναγνωριστικό της συνομιλίας με το bot. Κάθε συνομιλία, ομάδα κ.λπ. είναι ατομική και έχει τον δικό της αριθμό (μερικές φορές με ένα μείον - για ανοιχτές ομάδες). Για να μάθουμε αυτόν τον αριθμό, πρέπει να ζητήσουμε στο πρόγραμμα περιήγησης (στην πραγματικότητα, δεν είναι καθόλου απαραίτητο στο πρόγραμμα περιήγησης, αλλά για καλύτερη κατανόηση μπορείτε να ξεκινήσετε με αυτόν) τη διεύθυνση (όπου 1234544311:NNNNNNNNNN είναι το διακριτικό σας

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

και λάβετε μια απάντηση όπως

{"ok":true,"result":[{"update_id":...,... chat":{"ταυτότητα":123456789

Χρειαζόμαστε chat_id.

Ας ελέγξουμε ότι μπορούμε να γράφουμε στη συνομιλία με μη αυτόματο τρόπο: καλέστε τη διεύθυνση από το πρόγραμμα περιήγησης

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

Εάν λάβετε ένα μήνυμα από ένα bot στη συνομιλία σας, εντάξει, προχωράτε στο επόμενο στάδιο.

Με αυτόν τον τρόπο (μέσω του προγράμματος περιήγησης) μπορείτε πάντα να ελέγχετε αν υπάρχουν προβλήματα με τη δημιουργία συνδέσμων ή αν κάτι είναι κρυμμένο κάπου και δεν λειτουργεί.

Τι πρέπει να γνωρίζετε πριν συνεχίσετε να διαβάζετε

Το Telegram έχει διάφορους τύπους ομαδικών συνομιλιών (ανοιχτές, κλειστές). Για αυτές τις συνομιλίες, ορισμένες από τις λειτουργίες (για παράδειγμα, id) είναι διαφορετικές, γεγονός που μερικές φορές προκαλεί ορισμένα προβλήματα.

Ας υποθέσουμε ότι είναι τέλος του 2019 και ακόμη και ο ήρωας της εποχής μας, ο γνωστός Man-Orchestra (διαχειριστής, δικηγόρος, ειδικός σε θέματα ασφάλειας πληροφοριών, προγραμματιστής και πρακτικά MVP) Evgeniy V. ξεχωρίζει τη μεταβλητή $i από έναν πίνακα, έχει κατακτήσει βρόχους, κοιτάξτε τα επόμενα δύο χρόνια θα κυριαρχήσει Chocolatey, και στη συνέχεια Παράλληλη επεξεργασία με PowerShell и ForEach-Object Parallel Θα έρθει.

1. Σκεφτόμαστε τι θα κάνει το bot μας

Δεν είχα καμία ιδέα, έπρεπε να σκεφτώ. Έχω ήδη γράψει ένα bot-notebook. Δεν ήθελα να φτιάξω ένα ρομπότ "που στέλνει κάτι κάπου". Για να συνδεθείτε στο Azure χρειάζεστε πιστωτική κάρτα, αλλά από πού την παίρνει ο μαθητής; Θα πρέπει να σημειωθεί ότι όλα δεν είναι τόσο άσχημα: τα κύρια σύννεφα δίνουν κάποιο είδος δοκιμαστικής περιόδου δωρεάν (αλλά χρειάζεστε έναν αριθμό πιστωτικής κάρτας - και φαίνεται ότι θα χρεωθεί ένα δολάριο. Δεν θυμάμαι αν επιστράφηκε αργότερα.)

Χωρίς AI ML δεν είναι τόσο ενδιαφέρον να φτιάξεις ένα bot-poor-poet-weaver.

Αποφάσισα να φτιάξω ένα bot που θα μου θυμίζει (ή όχι) αγγλικές λέξεις από το λεξικό.
Για να αποφευχθεί η ενασχόληση με τη βάση δεδομένων, το λεξικό θα αποθηκευτεί σε ένα αρχείο κειμένου και θα ενημερωθεί χειροκίνητα.
Σε αυτή την περίπτωση, το καθήκον είναι να δείξουμε τα βασικά της εργασίας και όχι να φτιάξουμε τουλάχιστον ένα μερικώς έτοιμο προϊόν.

2. Δοκιμάζοντας τι και πώς για πρώτη φορά

Ας δημιουργήσουμε έναν φάκελο C:poshtranslate
Αρχικά, ας δούμε τι είδους powershell έχουμε, ας ξεκινήσουμε το ISE μέσω start-run
powershell ise
ή βρείτε το Powershell ISE σε εγκατεστημένα προγράμματα.
Μετά την εκκίνηση, θα ανοίξει το συνηθισμένο γνωστό "κάποιο είδος επεξεργασίας", εάν δεν υπάρχει πεδίο κειμένου, μπορείτε πάντα να κάνετε κλικ στο "Αρχείο - δημιουργία νέου".

Ας δούμε την έκδοση του powershell - γράψτε στο πεδίο κειμένου:

get-host 

και πατήστε F5.

Το Powershell θα προσφέρει αποθήκευση - "Το σενάριο που πρόκειται να εκτελέσετε θα αποθηκευτεί.", συμφωνούμε και αποθηκεύστε το αρχείο από το powershell με το όνομα σε C: poshtranslate myfirstbotBT100.

Μετά την εκκίνηση, στο κάτω παράθυρο κειμένου έχουμε έναν πίνακα δεδομένων:

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

Έχω 5.1 κάτι, φτάνει. Εάν διαθέτετε ένα παλιό Windows 7/8, τότε δεν υπάρχει μεγάλη υπόθεση - αν και το PowerShell θα χρειαστεί να ενημερωθεί στην έκδοση 5 - π.χ. οδηγίες.

Πληκτρολογήστε Get-Date στην παρακάτω γραμμή εντολών, πατήστε Enter, δείτε την ώρα, μεταβείτε στον ριζικό φάκελο με την εντολή
cd
και καθαρίστε την οθόνη με την εντολή cls (όχι, δεν χρειάζεται να χρησιμοποιήσετε το rm)

Τώρα ας ελέγξουμε τι λειτουργεί και πώς - ας μην γράψουμε καν τον κώδικα, αλλά δύο γραμμές και ας προσπαθήσουμε να καταλάβουμε τι κάνουν. Ας σχολιάσουμε τη γραμμή με το get-host με το σύμβολο # και ας προσθέσουμε λίγο.

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

(Αυτό που είναι ενδιαφέρον είναι ότι στην αναπτυσσόμενη λίστα μορφοποίησης κώδικα στο Habré υπάρχουν δύο δωδεκάδες επιλογές - αλλά το Powershell δεν είναι εκεί. Το Dos είναι εκεί. Η Perl είναι εκεί.)

Και ας εκτελέσουμε τον κώδικα πατώντας F5 ή ">" από το GUI.

Παίρνουμε την έξοδο:

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

Τώρα ας δούμε αυτές τις δύο γραμμές και μερικά ενδιαφέροντα σημεία, ώστε να μην επιστρέψουμε σε αυτό στο μέλλον.

Σε αντίθεση με τον Pascal (και όχι μόνο), το ίδιο το PowerShell προσπαθεί να καθορίσει τον τύπο που θα εκχωρήσει σε μια μεταβλητή· περισσότερες λεπτομέρειες σχετικά με αυτό γράφονται στο άρθρο Εκπαιδευτικό πρόγραμμα πληκτρολόγησης σε γλώσσες προγραμματισμού
Επομένως, δημιουργώντας μια μεταβλητή $TimeNow και εκχωρώντας της την τιμή της τρέχουσας ημερομηνίας και ώρας (Get-Date), δεν χρειάζεται να ανησυχούμε πολύ για το είδος των δεδομένων που θα υπάρχουν εκεί.

Είναι αλήθεια ότι αυτή η άγνοια μπορεί να βλάψει αργότερα, αλλά αυτό είναι για αργότερα. Παρακάτω στο κείμενο θα υπάρχει ένα παράδειγμα.
Ας δούμε τι έχουμε. Ας εκτελέσουμε (στη γραμμή εντολών)

$TimeNow | Get-member

και λάβετε μια σελίδα με ακατανόητο κείμενο

Παράδειγμα ακατανόητου κειμένου με αριθμό 1

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

Όπως μπορείτε να δείτε, μια μεταβλητή τύπου TypeName: System.DateTime έχει δημιουργηθεί με μια δέσμη μεθόδων (με την έννοια του τι μπορούμε να κάνουμε με αυτό το αντικείμενο μεταβλητής) και ιδιότητες.

Ας καλέσουμε $TimeNow.DayOfYear — παίρνουμε τον αριθμό της ημέρας του έτους.
Ας καλέσουμε $TimeNow.DayOfYear | Get-Member - παίρνουμε TypeName: System.Int32 και μια ομάδα μεθόδων.
Ας καλέσουμε $TimeNow.ToUniversalTime() - και λάβετε χρόνο σε UTC

Debugger

Μερικές φορές συμβαίνει ότι είναι απαραίτητο να εκτελέσετε ένα πρόγραμμα μέχρι μια συγκεκριμένη γραμμή και να δείτε την κατάσταση του προγράμματος εκείνη τη στιγμή. Για το σκοπό αυτό, το ISE διαθέτει μια λειτουργία εντοπισμού σφαλμάτων - εναλλαγή σημείου διακοπής
Βάλτε ένα σημείο διακοπής κάπου στη μέση, τρέξτε αυτές τις δύο γραμμές και δείτε πώς φαίνεται το διάλειμμα.

3. Κατανόηση της αλληλεπίδρασης με το bot Telegram

Φυσικά, έχει γραφτεί ακόμα περισσότερη βιβλιογραφία για την αλληλεπίδραση με το bot, με όλα τα getpush και ούτω καθεξής, αλλά το θέμα της θεωρίας μπορεί να εξεταστεί προαιρετικά.

Στην περίπτωσή μας είναι απαραίτητο:

  • Μάθετε να στέλνετε κάτι στην αλληλογραφία
  • Μάθε να παίρνεις κάτι από αλληλογραφία

3.1 Μαθαίνοντας να στέλνετε κάτι σε αλληλογραφία και να λαμβάνετε από αυτό

Ένας μικρός κώδικας - μέρος 3

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

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

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

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

Invoke-WebRequest -Uri $URL4SEND

και στη Ρωσική Ομοσπονδία σε αυτό το σημείο λαμβάνουμε το σφάλμα Δεν είναι δυνατή η σύνδεση στον απομακρυσμένο διακομιστή.

Ή δεν το λαμβάνουμε - εξαρτάται από τον πάροχο τηλεπικοινωνιών και από το εάν ο διακομιστής μεσολάβησης έχει ρυθμιστεί και λειτουργεί
Λοιπόν, το μόνο που μένει είναι να προσθέσετε έναν διακομιστή μεσολάβησης. Λάβετε υπόψη ότι η χρήση ενός μη κρυπτογραφημένου και γενικά δόλιου διακομιστή μεσολάβησης είναι εξαιρετικά επικίνδυνη για την υγεία σας.

Το έργο της εύρεσης ενός λειτουργικού διακομιστή μεσολάβησης δεν είναι πολύ δύσκολο - τα περισσότερα από τα δημοσιευμένα http πληρεξούσια λειτουργούν. Νομίζω ότι το πέμπτο μου λειτούργησε.

Σύνταξη με χρήση διακομιστή μεσολάβησης:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

Εάν λάβετε ένα μήνυμα στη συνομιλία σας με ένα bot, τότε όλα είναι καλά, μπορείτε να προχωρήσετε. Εάν όχι, συνεχίστε τον εντοπισμό σφαλμάτων.

Μπορείτε να δείτε σε τι μετατρέπεται η συμβολοσειρά $URL4SEND και να δοκιμάσετε να την ζητήσετε στο πρόγραμμα περιήγησης, ως εξής:

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

3.2. Μάθαμε πώς να γράφουμε "κάτι" στο chat, τώρα ας προσπαθήσουμε να το διαβάσουμε

Ας προσθέσουμε άλλες 4 γραμμές και ας δούμε τι υπάρχει μέσα από το | γίνετε μέλος

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

Το πιο ενδιαφέρον πράγμα μας παρέχεται

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

Ας δούμε τι έχουν μέσα τους:

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

Εάν όλα λειτουργούν για εσάς, θα έχετε μια μεγάλη ουρά όπως:

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

Ευτυχώς, στο άρθρο που δημοσιεύτηκε προηγουμένως Telegram bot για διαχειριστή συστήματος αυτή η γραμμή (ναι, σύμφωνα με το $MyMessageGet.RawContent | get-member είναι System.String), έχει ήδη αποσυναρμολογηθεί.

4. Επεξεργαστείτε αυτό που λαμβάνετε (ξέρουμε ήδη πώς να στείλουμε κάτι)

Όπως ήδη γράφτηκε εδώ, τα πιο απαραίτητα βρίσκονται στο περιεχόμενο. Ας το ρίξουμε μια πιο προσεκτική ματιά.

Αρχικά, θα γράψουμε μερικές ακόμη φράσεις στο bot από τη διεπαφή ιστού ή από το τηλέφωνο

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

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

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

Ας προσπαθήσουμε να το γράψουμε σε αρχεία χρησιμοποιώντας παραδειγματικός.

Κάποιος κωδικός #5.1

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

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

- και λαμβάνουμε ένα σφάλμα στη γραμμή Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Δεν θέλει να προσθέσει, αχ-αχ, τι κρίμα.

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

Ας δούμε τι θα γίνει. Εξαιρετική προβολή κειμένου - αλλά πώς να το εξαγάγετε πίσω; Πρέπει να εισαγάγω κάποιου είδους διαχωριστικά κειμένου, όπως κόμματα;

Και στο τέλος λαμβάνετε ένα αρχείο "αξίες διαχωρισμένες με κόμματα (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 

Όπως γίνεται εύκολα αντιληπτό, το MS δεν διακρίνεται ιδιαίτερα από τη λογική του· για μια παρόμοια διαδικασία, σε μια περίπτωση χρησιμοποιείται -FilePath, σε άλλη -Path.

Επιπλέον, στον τρίτο φάκελο εξαφανίστηκε η ρωσική γλώσσα, στον τέταρτο αρχείο αποδείχθηκε... ε, κάτι έγινε. #TYPE System.Object[] 00
# "Count", "Length", "LongLength", "Rank", "SyncRoot", "IsReadOnly", "IsFixedSize", "IsSynchronized"
#
Ας το ξαναγράψουμε λίγο:

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

Φαίνεται ότι βοήθησε, αλλά ακόμα δεν μου αρέσει η μορφή.

Δεν μου αρέσει ιδιαίτερα που δεν μπορώ να βάλω γραμμές από ένα αντικείμενο σε ένα αρχείο απευθείας.
Παρεμπιπτόντως, από τότε που ξεκινήσαμε να γράφουμε σε αρχεία, μπορούμε να αρχίσουμε να κρατάμε ένα αρχείο καταγραφής εκκίνησης; Έχουμε χρόνο ως μεταβλητή, μπορούμε να ορίσουμε το όνομα του αρχείου.

Είναι αλήθεια ότι δεν υπάρχει τίποτα να γράψετε ακόμα, αλλά μπορείτε να σκεφτείτε πώς να περιστρέψετε καλύτερα τα αρχεία καταγραφής.
Ας δοκιμάσουμε το xml προς το παρόν.

Μερικά xml

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

Η εξαγωγή σε xml έχει πολλά πλεονεκτήματα - αναγνωσιμότητα, εξαγωγή ολόκληρου του αντικειμένου και δεν χρειάζεται να κάνετε upend.

Ας προσπαθήσουμε διαβάστε το αρχείο xml.

Μια μικρή ανάγνωση από το xml

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

Ας επιστρέψουμε στο έργο. Γράψαμε ένα δοκιμαστικό αρχείο, διαβάστε το, η μορφή αποθήκευσης είναι σαφής, εάν είναι απαραίτητο, μπορείτε να γράψετε ένα ξεχωριστό μικρό πρόγραμμα επεξεργασίας αρχείων για να προσθέσετε και να διαγράψετε γραμμές.

Να σας υπενθυμίσω ότι το καθήκον ήταν να φτιάξω ένα μικρό εκπαιδευτικό bot.

Μορφή εργασίας: Στέλνω την εντολή «παράδειγμα» στο bot, το bot μου στέλνει μια τυχαία επιλεγμένη λέξη και μεταγραφή και μετά από 10 δευτερόλεπτα μου στέλνει μια μετάφραση και ένα σχόλιο. Γνωρίζουμε πώς να διαβάζουμε εντολές, θα θέλαμε επίσης να μάθουμε πώς να επιλέγουμε και να ελέγχουμε αυτόματα τους διακομιστές μεσολάβησης και να επαναφέρουμε τους μετρητές μηνυμάτων στη λήθη.

Ας αφαιρέσουμε σχολιασμό ό,τι σχολιάστηκε προηγουμένως ως περιττό, σχολιάστε τα πλέον περιττά παραδείγματα με txt και csv και ας αποθηκεύσουμε το αρχείο ως έκδοση B106

Ω ναι. Ας στείλουμε ξανά κάτι στο bot.

6. Αποστολή από λειτουργίες και πολλά άλλα

Πριν επεξεργαστείτε τη λήψη, πρέπει να δημιουργήσετε μια λειτουργία για την αποστολή "τουλάχιστον κάτι" εκτός από ένα δοκιμαστικό μήνυμα.

Φυσικά, στο παράδειγμα θα έχουμε μόνο μία αποστολή και μόνο μία επεξεργασία, αλλά τι γίνεται αν χρειαστεί να κάνουμε το ίδιο πράγμα πολλές φορές;

Είναι πιο εύκολο να γράψετε μια συνάρτηση. Έτσι, έχουμε μια μεταβλητή αντικειμένου τύπου $MyVocabExample4AsArray, που διαβάζεται από το αρχείο, με τη μορφή ενός πίνακα έως και δύο στοιχείων.
Πάμε να διαβάσουμε.

Ταυτόχρονα, θα ασχοληθούμε με το ρολόι, θα το χρειαστούμε αργότερα (στην πραγματικότητα, σε αυτό το παράδειγμα δεν θα το χρειαστούμε :)

Κάποιος κωδικός #6.1

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

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

Όπως μπορείτε εύκολα να δείτε, η συνάρτηση καλεί $MyToken και $MyChatID, τα οποία είχαν κωδικοποιηθεί νωρίτερα.

Δεν χρειάζεται να το κάνετε αυτό και αν το $MyToken είναι ένα για κάθε bot, τότε το $MyChatID θα αλλάξει ανάλογα με τη συνομιλία.

Ωστόσο, δεδομένου ότι αυτό είναι ένα παράδειγμα, θα το αγνοήσουμε προς το παρόν.

Εφόσον το $MyVocabExample4AsArray δεν είναι πίνακας, αν και μοιάζει πολύ με έναν, τότε δεν μπορείς απλά να το πάρεις ζητήστε το μήκος του.

Για άλλη μια φορά θα πρέπει να κάνουμε κάτι που δεν γίνεται - αλεξίπτωτο όχι σύμφωνα με τον κωδικό - πάρτε το και μετρήστε

Κάποιος κωδικός #6.2

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

Τυχαίος ενδιαφέρον χαρακτηριστικό. Ας υποθέσουμε ότι θέλουμε να λάβουμε 0 ή 1 (έχουμε μόνο δύο στοιχεία στον πίνακα). Όταν θέτουμε όρια 0..1, θα έχουμε "1";
όχι - δεν θα το λάβουμε, έχουμε ένα ειδικό παράδειγμα Παράδειγμα 2: Λάβετε έναν τυχαίο ακέραιο μεταξύ 0 και 99 Λήψη-Τυχαίο -Μέγιστο 100
Επομένως, για το 0..1 πρέπει να ορίσουμε το μέγεθος 0..2, με μέγιστο αριθμό στοιχείου = 1.

7. Επεξεργασία εισερχόμενων μηνυμάτων και μέγιστο μήκος ουράς

Πού σταματήσαμε νωρίτερα; έχουμε την ληφθείσα μεταβλητή $MyMessageGet
και $Content4Pars01 αποκτήθηκαν από αυτό, από τα οποία μας ενδιαφέρουν τα στοιχεία του πίνακα Content4Pars01.result

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

Ας στείλουμε το bot /message10, /message11, /message12, /word και ξανά /word και /hello.
Ας δούμε τι έχουμε:

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

Ας εξετάσουμε όλα όσα λάβαμε και ας στείλουμε μια απάντηση εάν το μήνυμα ήταν /word
η περίπτωση της κατασκευής, αυτό που ορισμένοι περιγράφουν ως if-elseif, ονομάζεται στο powershell μέσω διακόπτη. Ταυτόχρονα, ο παρακάτω κώδικας χρησιμοποιεί το κλειδί -μπαλαντέρ, το οποίο είναι εντελώς περιττό και μάλιστα επιβλαβές.

Κάποιος κωδικός #7.1

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

Ας τρέξουμε το σενάριο μερικές φορές. Θα λαμβάνουμε την ίδια λέξη δύο φορές για κάθε προσπάθεια εκτέλεσης, ειδικά αν κάναμε λάθος στην υλοποίηση του τυχαίου.

Σταμάτα όμως. Δεν στείλαμε ξανά το /word, οπότε γιατί το μήνυμα υποβάλλεται ξανά σε επεξεργασία;

Η ουρά για την αποστολή μηνυμάτων στο bot έχει πεπερασμένο μήκος (100 ή 200 μηνύματα, νομίζω) και πρέπει να διαγραφεί χειροκίνητα.

Αυτό φυσικά περιγράφεται στην τεκμηρίωση, αλλά πρέπει να το διαβάσετε!

Σε αυτήν την περίπτωση, χρειαζόμαστε την παράμετρο ?chat_id και τα &timeout, &limit, &parse_mode=HTML και &disable_web_page_preview=true δεν χρειάζονται ακόμα.

Τεκμηρίωση για Το telegram api είναι εδώ
Λέει στα λευκά και στα αγγλικά:
Αναγνωριστικό της πρώτης ενημέρωσης που θα επιστραφεί. Πρέπει να είναι μεγαλύτερο κατά ένα από το υψηλότερο μεταξύ των αναγνωριστικών των ενημερώσεων που ελήφθησαν προηγουμένως. Από προεπιλογή, οι ενημερώσεις ξεκινούν από τις παλαιότερες
ανεξακρίβωτος επιστρέφονται οι ενημερώσεις. Μια ενημέρωση θεωρείται επιβεβαιωμένη μόλις γίνει κλήση του getUpdates με ένα όφσετ υψηλότερο από το update_id του. Η αρνητική μετατόπιση μπορεί να καθοριστεί για την ανάκτηση ενημερώσεων ξεκινώντας από την ενημέρωση -offset από το τέλος της ουράς ενημερώσεων. Όλες οι προηγούμενες ενημερώσεις θα ξεχαστούν.

Ας δούμε:

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

Ναι, και θα το επαναφέρουμε και θα ξαναγράψουμε λίγο τη συνάρτηση. Έχουμε δύο επιλογές - να περάσετε ολόκληρο το μήνυμα στη συνάρτηση και να το επεξεργαστείτε εξ ολοκλήρου στη συνάρτηση ή να δώσετε μόνο το αναγνωριστικό του μηνύματος και να το επαναφέρετε. Για παράδειγμα, το δεύτερο φαίνεται πιο απλό.

Προηγουμένως, η συμβολοσειρά ερωτημάτων "όλα τα μηνύματα" έμοιαζε

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

και θα μοιάζει

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

Κανείς δεν σας απαγορεύει να λαμβάνετε πρώτα όλα τα μηνύματα, να τα επεξεργάζεστε και μόνο μετά την επιτυχή επεξεργασία του αιτήματος μη επιβεβαιωμένο -> επιβεβαιωμένο.

Γιατί έχει νόημα να καλέσετε την επιβεβαίωση αφού ολοκληρωθεί όλη η επεξεργασία; Μια αποτυχία είναι πιθανή στη μέση της εκτέλεσης και αν για παράδειγμα ενός δωρεάν chatbot, η απώλεια ενός μόνο μηνύματος δεν είναι κάτι ιδιαίτερο, τότε εάν επεξεργάζεστε τον μισθό ή τη συναλλαγή με κάρτα κάποιου, το αποτέλεσμα μπορεί να είναι χειρότερο.

Μερικές ακόμη γραμμές κώδικα

$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. Αντί για συμπέρασμα

Βασικές λειτουργίες - η ανάγνωση μηνυμάτων, η επαναφορά της ουράς, η ανάγνωση από αρχείο και η εγγραφή σε αρχείο γίνονται και εμφανίζονται.

Μένουν μόνο τέσσερα πράγματα να κάνετε:

  • αποστολή της σωστής απάντησης σε ένα αίτημα στο chat
  • αποστολή απάντησης σε ΟΠΟΙΑΔΗΠΟΤΕ συνομιλία στην οποία προστέθηκε το bot
  • εκτέλεση κώδικα σε βρόχο
  • εκκίνηση ενός bot από τον προγραμματιστή των Windows.

Όλες αυτές οι εργασίες είναι απλές και μπορούν εύκολα να πραγματοποιηθούν διαβάζοντας την τεκμηρίωση σχετικά με παραμέτρους όπως π.χ
Set-ExecutionPolicy Unrestricted και -ExecutionPolicy Bypass
κύκλο της φόρμας

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

Ευχαριστώ όλους όσους διάβασαν.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο