A template for a basic Telegram bot for 7-9 grade students in PowerShell

During a conversation with a friend, I was surprised to learn that children in grades 8-10 at their school are not taught programming at all. Just Word, Excel, and that's it. No Logo, not even Pascal, and not even VBA for Excel.

I was very surprised, opened the internet, and started reading —
One of the tasks of a specialized school is to foster a new generation that meets the conditions of an information society in terms of their level of development and lifestyle.
This course will allow students to practice their knowledge of the basic constructs of the Pascal programming language. (from the curriculum of some gymnasium for 2017)

In the end, I decided to spend a couple of hours drafting an example of 'how to create a simple bot — for schoolchildren.'

Below is how to write yet another simple bot in PowerShell and make it work without webhooks, white IPs, dedicated servers, or cloud virtual machines — on a regular home PC with ordinary Windows.

TLDR: Another boring article with grammatical and factual errors, nothing to read, no humor, no images.

There's nothing new in the article, almost everything written has already been covered on Habr, for example in articles like Instructions: How to create bots in Telegram and Telegram Bot for System Administrators.
Moreover, the article is deliberately redundant to avoid constantly referencing educational literature. There are no references to the 4th edition, PowerShell Deep Dives, or The 5 Pillars of the AWS Well-Architected Framework in the text.

Instead of a preface, we can skip it.

Let's skip it boldly.In 2006, Microsoft released PowerShell 1.0 for what was then Windows XP, Vista, and Server 2003. In some ways, it replaced things like batch scripts, vb scripts, Windows Script Host, and JScript.

Even now, PowerShell can only be viewed as the next step after Logo variants, instead of the Delphi (or even older) options that might still be in use, despite having loops, classes, functions, and MS GUI calls. Integration with Git and so on.

PowerShell is used relatively rarely; you might encounter it in the form of PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, and Desired State Configuration. PowerShell Web Access and a dozen other rarely used programs and functions. Perhaps it will experience a resurgence with the release of WSL2, but that's not certain.

PowerShell has three big advantages:

  1. It is relatively simple, there is a lot of literature and examples about it, and even in Russian, for example, an article about Foreach—from a book. PowerShell in depth — about the difference () and {}
  2. It comes with the editor ISE, included with Windows. There’s even some kind of debugger.
  3. It easily calls components for building graphical interfaces.

0. Preparation.

We will need:

  • A PC with Windows (I have Windows 10)
  • Some kind of internet access (through NAT, for example)
  • For those who have limited access to Telegram—a installed and configured Freegate in the browser, in some complex cases in conjunction with Symple DNS Crypt
  • Availability of a working Telegram client on the phone
  • Understanding the very basics—what a variable, array, and loop are.

Opened and read articles— Instructions: How to create bots in Telegram and Telegram Bot for System Administrators

1. Let's create another test bot.

Since everyone already knows this and it has already been done, it can also be skipped.As mentioned in the article above—First of all, a bot for Telegram— it is still an application running on your side that makes requests to the Telegram Bot API. Moreover, the API is straightforward—a bot calls a specific URL with parameters, and Telegram responds with a JSON object.

Associated problems: if by some unknown way you take some code from the JSON object and somehow send it for execution (not intentionally)—the code will execute on your end.

The creation process is described in the two articles above, but to repeat: in Telegram, open contacts, search for @botfather, tell him /newbot, we will create a bot Botfortest12344321, name it Mynext1234bot, and receive a message with a unique key like 1234544311:AbcDefNNNNNNNNNNNNN.

Keep the key safe and do not share it!

Next, you can configure the bot, for example, to prohibit adding it to groups, but this is not necessary at the initial steps.

We will ask BotFather '/mybot' and adjust the settings if something is not right.

Once again, we will open contacts, find @Botfortest12344321 (start searching with @), press ‘start’ and write the bot ‘/Glory to robots’. The '/' is mandatory, quotes are not needed.
Of course, the bot will not respond.

Let's check if the bot was created—let's open.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNN/getMe
where 1234544311:AbcDefNNNNNNNNNNNNN is the previously obtained key,
and we will receive a string like
{"ok":true,"result":{""}}

We have the first secret phrase (token). Now we need to find out the second secret number — the chat ID with the bot. Each chat, group, and so on are unique and have their own number (sometimes with a minus sign — for open groups). To find out this number, we need to request in a browser (it’s not strictly necessary to use a browser, but for better understanding, it makes sense to start with it) the address (where 1234544311:NNNNNNNNN is your token

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

and get a response like

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

We specifically need chat_id.

Let’s check that we can manually send messages to the chat: we’ll call the following address from the browser

https://api.telegram.org/bot[your_token]/sendMessage?chat_id=123456789&text="Life is directed motion"

If a message from the bot arrives in your chat — okay, you move on to the next stage.

Thus (via the browser), you can always check where the issues are — in generating the link or if something is blocked and not functioning.

What you need to know before continuing to read

In Telegram, there are several types of group chats (open, closed). For these chats, some functions (like id) vary, which sometimes causes certain problems.

Let’s assume it’s late 2019, and even our contemporary, the well-known One-Man-Band (administrator, lawyer, information security specialist, programmer, and practically MVP) Evgeny V. can differentiate variable $i from an array, has mastered loops, and hopefully in the next couple of years will learn Chocolatey, and then Parallel processing with PowerShell and ForEach-Object Parallel he’ll get there.

1. We think about what our bot will do

I had no ideas, so I had to think. I already wrote a note-taking bot. I didn’t want to create a bot that ‘forwards something somewhere.’ Connecting Azure requires a credit card, but where will a schoolboy get one? It’s worth noting that it’s not all bad: major clouds offer a kind of free trial period (but a credit card number is still required — and it seems a dollar will be charged, I don’t remember if it was refunded later).

Without AI ML, making a bot that’s a complete nuisance or poetry spammer isn’t very interesting.

I decided to make a bot that would remind me (or not me) of English words from the dictionary.
The dictionary, to avoid dealing with a database, will be in a text file and updated manually.
In this case, the goal is to demonstrate the fundamentals at work, not to produce a partially finished product.

2. Trying out what and how for the first time

Let's create a folder C:poshtranslate
To start, let's see what we have with PowerShell, let's launch ISE via Run.
powershell ise
or find PowerShell ISE in the installed programs.
After launching, the usual familiar 'some sort of editor' will open; if there is no text field, you can always click 'File - create new'.

Let's check the version of PowerShell — we will type in the text field:

get-host 

and press F5.

PowerShell will suggest saving — 'The script you are about to run will be saved.', let's agree and save the file from PowerShell in C:poshtranslate with the name myfirstbotBT100.

After running, the bottom text window will display a data table:

Name             : Windows PowerShell ISE Host
Version          : 5.1.(and so on)

I have 5.1 something, which is enough. If you have an old Windows 7/8, it’s not a problem — although PowerShell needs to be updated to version 5 — for example, by the instructions.

Let's type in the command line below Get-Date, press Enter, check the time, and go to the root folder with the command
cd
and clear the screen with the command cls (no, don't use rm)

Now let's check what and how it works — we will write not even code, but two lines, and try to understand what they do. We will comment out the line with get-host using the # symbol and add a little.

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

(Interestingly, in the dropdown list of code formatting on Habr, there are two dozen options — but PowerShell is not among them. Dos is there. Perl is there.)

And we will run the code by pressing F5 or '>' from the GUI.

We will get the output:

Saturday, December 8, 2019 21:00:50 PM (or something like that)

Now let's analyze these two lines and some interesting points so that we don't have to return to this later.

Unlike Pascal (and not only), PowerShell tries to determine what type to assign to a variable itself; more details about this are written in the article Intro to Typing in Programming Languages
Therefore, when creating the variable $TimeNow and assigning it the current date and time (Get-Date), we don't need to worry much about what type of data will be there.

True, this ignorance can cause pain later, but that’s later. An example will be provided later in the text.
Let's see what we've got. Execute (in the command line)

$TimeNow | Get-member

and we will get a page of unclear text

Example of unclear text number 1

PS C:&gt; $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 ((&amp; { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Date")...                                         

As we can see, a variable of type TypeName: System.DateTime has been created with a bunch of methods (meaning, what we can do with this object variable) and properties.

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

Debugger

Sometimes it happens that it's necessary to run a program up to a certain line and see the program's state at that moment. For this, ISE has the Debug function — toggle break point.
Set a breakpoint somewhere in the middle, run these two lines for execution, and see what the breakpoint looks like.

3. Understanding interaction with a Telegram bot

Of course, much more literature has been written about interaction with the bot, with all the get and push, and so on, however, the theoretical question can be considered optionally.

In our case, it is necessary:

  • To learn to send something in the chat
  • To learn to receive something from the chat

3.1 Learning to send something in the chat 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 Russia at this point we get the error Unable to connect to the remote server.

Or we don't get it — it depends on the service provider and whether the proxy is configured and working.
Well — we need to add a proxy. Note that using unencrypted and generally dubious proxies is extremely dangerous for your health.

Finding a working proxy is not very difficult — most of the published HTTP proxies work. The fifth one I tried seemed to work.

The syntax using a proxy:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

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

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

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

3.2 Now that we have learned to 'write something' in the chat, let's try to read

Let's add 4 more lines and see what's inside through | 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 is provided to us

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

Let's see what's inside them:

Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # here's something interesting
Write-Host "RawContent"
$MyMessageGet.RawContent # and here's something interesting too, and it's also readable.
Write-Host "Content"
$MyMessageGet.Content

If everything is working for you, you will get a long string like this:

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

Fortunately, this line was already covered in a previously published article, Telegram Bot for System Administrators (yes, according to $MyMessageGet.RawContent | get-member — this is System.String), it has already been analyzed.

4. Process the received data (we already know how to send something)

As previously mentioned here, the most relevant data is in content. Let's take a closer look at it.

First, let's write a couple more phrases to the bot from the web interface or from the phone

/message1
/message2
/message3

and check the address that has formed in the variable $URLGET through the browser.

We will see something like:

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

What is this? Some complex object made up of arrays of objects, containing a message ID, chat ID, sender ID, and a lot of additional information.

However, we do not need to analyze "what kind of object this is" — part of the work has already been done for us. Let's see what's inside:

Reading received messages or part 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. What are we going to do with this now

Let's save the received file under the name myfirstbotBT105 or whatever you prefer, change the header and comment out all the code we've already written using

<#start comment 105 end comment 105#>

Now we need to determine where to get the dictionary (well, where — on the disk in a file) and how it will look.

Of course, we could stuff a huge dictionary directly into the script text, but that's not practical at all.
So let's check what PowerShell can natively work with.
In fact, it doesn't matter what kind of file to work with, but it does matter to us.
We have the following options: txt (can be done, but why?), csv, xml.
Or we can look at them all. Let's check them all.
Let's create a class MyVocabClassExample1 and a variable $MyVocabExample1
note that the class is written without $

a bit of code #5

write-host "This is part 5"
class MyVocabClassExample1 {
    [string]$Original  # word
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # a very interesting point. Using int with its limitations can sometimes lead to wild consequences, for example - a recent case with HPE SSD. Initially, I didn't add this element, but later I did and commented on it.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Apple"
$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 = "Pear"
$MyVocabExample2.Example = "The pear (ˈpɛər) tree and shrub are a species of genus Pyrus"
# $MyVocabExample1.$VocWordID = 2

Let's try saving this to files according to the template.

A little code #5.1

Write-Host $ScriptDir # I hope you haven't commented out $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

— and we will get an error on the line Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

It doesn't want to add, oh what a pity.

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

Let's see what we got. A wonderful text format — but how to export it back? Should we enter some text delimiters, such as commas?

And in the end, get a "file with delimiters — commas, comma-separated values (CSV)" STOP WAIT.
#

$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 

It’s easy to see that MS didn't do particularly well with logic; for a similar procedure, one case uses -FilePath, while the other uses -Path.

Moreover, the Russian language disappeared from the third file, and the fourth file... well, something came out. #TYPE System.Object[] 00
# „Count“,»Length»,«LongLength»,«Rank»,«SyncRoot»,«IsReadOnly»,«IsFixedSize»,«IsSynchronized»
#
Let's rewrite a bit:

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

It seems to have helped — but I still don't like the format.

Especially, I don't like that I can't put object strings directly into a file.
By the way, since we started writing to files — maybe we should begin logging the startup? We already have time as a variable, and we know how to set the file name.

There isn't much to write yet, but we can think about how to best handle log rotation.
For now, let's try XML.

A bit of 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

Exporting to XML has several advantages — readability, exporting the entire object, and no need for appending.

Let's try to read the XML file.

A bit of reading from XML

$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray 
# $MyVocabExample4AsArray[0]
# and a bit about some not-so-obvious nuances. Powershell behaves unexpectedly from time to time.
# for example, my two outputs differ
# Write-Output $MyVocabExample4AsArray 
# write-host $MyVocabExample4AsArray 

Let's get back to the task. We wrote a sample file, read it, the storage format is clear, and if necessary, we can write a small separate file editor for adding and removing lines.

I remind you that the task was to create a small educational bot.

Operating format: I send the bot the command "example", the bot sends me a randomly chosen word and transcription, and after 10 seconds, it sends the translation and comments. We know how to read commands; it would be great to also learn to automatically select and verify proxies and reset message counters into oblivion.

Let's uncomment everything that was previously commented out as unnecessary, comment out the now unnecessary examples with txt and csv, and save the file as version B106.

Oh, yes. Let's send something to the bot again.

6. Sending from functions and more

Before processing the reception, we need to create a function to send "something", other than a test message.

Of course, in our example there will be only one send and from one processing, but what if we need to do the same thing multiple times?

It's easier to write a function. So, we have a variable of object type $MyVocabExample4AsArray, read from the file, in the form of an array with exactly two elements.
Let's read.

At the same time, let's deal with the clock; we will need this later (actually, in this example — we won't need it 🙂

A bit of code #6.1

Write-Output "This is Part 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # adjusted time
    ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # and here we would get an error
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # but here we won't, those who can guess why are clever.

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

As you can easily see, the function calls $MyToken and $MyChatID, which were hardcoded earlier.

This is not advisable, and if $MyToken is the same for each bot, then $MyChatID will change depending on the chat.

However, since this is an example, we will ignore this for now.

Since $MyVocabExample4AsArray is not an array, although it looks very much like it, you can't just take it and query its length.

You'll have to do what shouldn't be done once again — parachute in without following the code — take it and count

A bit of code #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)
# or in one line
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Guess for yourself which example is easier to read for outsiders.

Random an interesting function. Let's say we want to get 0 or 1 (we only have two elements in the array). When setting the boundaries 0..1 — will we get "1"?
no — we won't, we have specifically provided an example Example 2: Get a random integer between 0 and 99 Get-Random -Maximum 100
So, for 0..1 we will have to set the size 0..2, while the maximum element number = 1.

7. Processing incoming messages and maximum queue length

What were we discussing earlier? We have the retrieved variable $MyMessageGet
and the one derived from it $Content4Pars01, from which we are interested in the elements of the array Content4Pars01.result

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

Let's send to the bot /message10, /message11, /message12, /word and once again /word and /hello.
Let's see what we received:

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

We will iterate through all received and send a response if the message was /word
the case of structure, what some describe as if-elseif, in PowerShell is called via switchIn the code below, the -wildcard key is used, which is not necessary and can even be harmful.

A bit of code #7.1

Write-Output "This is part 7"
Foreach ($Result in $Content4Pars01.result) # Yes, it can be done faster 
 { 
    switch -wildcard ($Result.message.text) 
            {
            "\/word" {MyFirstFunction($TextForExample1)}
            }
}

Let’s run the script a couple of times. We will get the same word twice for each execution attempt, especially if we made a mistake in implementing random.

But wait. We didn't send \/word again, so why is the message being processed again?

The queue for sending messages to the bot has a finite length (seems to be 100 or 200 messages), and it needs to be cleared manually.

Of course, this is described in the documentation, but you need to read it!

In this case, we need the parameter ?chat_id, while &timeout, &limit, &parse_mode=HTML, and &disable_web_page_preview=true are not needed yet.

Documentation for telegram api is located here
It is written in plain English there:
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 be forgotten.

Let’s look at:

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

And we will reset it — let’s rewrite the function a bit. We have two options — either pass the entire message to the function and process it fully in the function, or just give the message ID and reset it. For example, the second option seems simpler.

Previously, our request string for "all messages" looked like

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

and will look like

$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 

No one forbids first retrieving all messages, processing them, and only after successful processing requesting unconfirmed -> confirmed.

Why does it make sense to call confirmation after all processing is done? A failure can occur in the middle of execution, and if for example, missing a single message is not a big deal for a free chatbot, then if you are processing someone's salary or card transaction, the outcome can be worse.

A couple more lines of code

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id  #this error is expected to be fixed manually. 
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy

8. Instead of a conclusion

The main functions — reading messages, clearing the queue, reading from a file, and writing to a file have been implemented and demonstrated.

Only four things remain to be done:

  • sending the correct response to the request in the chat
  • sending a response to ANY chat where the bot has been added
  • executing code in a loop
  • starting the bot from the Windows scheduler.

All these tasks are simple and can be easily implemented by reading the documentation on parameters such as
Set-ExecutionPolicy Unrestricted and -ExecutionPolicy Bypass
a loop of the form

$TimeToSleep = 3 # polling every 3 seconds
$TimeToWork = 10 # minutes
$HowManyTimes = $TimeToWork*60/$TimeToSleep # counter for the loop
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

Thank you to everyone who read to the end.

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster