使用 Powershell 为 7-9 年级学生设计的简单电报机器人模板

在与朋友的交谈中,我突然了解到他们学校8-10年级的孩子根本不教编程。 Word、Excel 等等。 没有徽标,甚至没有 Pascal,甚至没有 Excel 的 VBA。

我很惊讶,打开网络开始阅读——
专门学校的任务之一是促进新一代在发展水平和生活方式上适应信息社会条件的教育。
本课程将使学生能够在实践中巩固 Pascal 编程语言基本结构的知识。 (摘自2017年部分体育馆节目表)

最后,我决定花几个小时勾勒出一个“如何为学童创建一个简单的机器人”的示例。

下面的内容是如何在 Powershell 中编写另一个简单的机器人,并使其在没有 Webhook、白色 IP、专用服务器、云中部署的虚拟机等的情况下在装有常规 Windows 的普通家用 PC 上运行。

TLDR:又一篇无聊的文章,有语法和事实错误,没有什么可读的,没有幽默感,没有图片。

文章中没有什么新内容,之前写的几乎所有内容都已经在 Habré 上,例如在文章中 说明:如何在 Telegram 中创建机器人 и 系统管理员的 Telegram 机器人.
而且,这篇文章故意冗长,以免每次都引用教育文献。 文本中没有提及 Gang 4、PowerShell Deep Dives 或 AWS Well-Architected Framework 的 5 个支柱。

您可以跳过前言,而不是

随意跳过2006年,微软为当时的Windows XP、Vista和Server 1.0发布了PowerShell 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 网络访问 以及十多个很少使用的程序和功能。 也许随着发布他会重获新生 WSL2,但不完全是。

Powershell还具有三大优势:

  1. 它相对简单,有很多关于它的文献和例子,甚至在俄语中,例如,一篇关于 Foreach 的文章 - 来自书中 深入了解 PowerShell - 关于 () 和 {} 的区别
  2. 他和编辑一起去 ISE,包含在 Windows 中。 那里甚至还有某种调试器。
  3. 很容易从它调用 用于构建图形界面的组件.

0。 准备。

我们将需要:

  • Windows 电脑(我有 Windows 10)
  • 至少某种 Internet 访问(例如通过 NAT)
  • 对于那些对 telegram 的访问权限有限的人 - 在浏览器中安装和配置 freegate,在某些困难的情况下,与 Symple DNS Crypt 一起使用
  • 在您的手机上安装有效的 telegram 客户端
  • 了解最基本的知识——什么是变量、数组、循环。

打开并阅读文章 - 说明:如何在 Telegram 中创建机器人 и 系统管理员的 Telegram 机器人

1. 让我们创建另一个测试机器人。

既然大家都知道了,而且已经发生了,你也可以跳过正如上面的文章所述 - 首先,一个 Telegram 机器人 - 它仍然是一个在您这边运行并向 Telegram Bot API 发出请求的应用程序。 此外,API 很明确 - 机器人使用参数访问特定 URL,Telegram 使用 JSON 对象进行响应。

相关问题:如果您以某种未知的方式从 JSON 对象中获取一些代码并以某种方式将其发送以执行(不是故意的),则该代码将为您执行。

上面的两篇文章描述了创建过程,但我重复一遍:在电报中,我们打开联系人,查找@botfather,告诉他/newbot,创建​​一个机器人Botfortest12344321,将其命名为Mynext1234bot,并接收一条带有唯一密钥的消息形式 1234544311:AbcDefNNNNNNNNNNNNNN

请保管好钥匙,不要将其遗失!

然后您可以配置机器人,例如禁止将其添加到组中,但在第一步中这不是必需的。

让我们向 BotFather 询问“/mybot”,如果我们不喜欢某些内容,请调整设置。

让我们再次打开联系人,在那里找到@Botfortest12344321(必须以@开始搜索),单击“开始”并向机器人写入“/Glory to the robots”。 / 符号是必需的,不需要引号。
当然,机器人不会回答任何问题。

让我们检查机器人是否已创建并打开它。

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNNN/getMe
其中 1234544311:AbcDefNNNNNNNNNNNNNN 是之前收到的密钥,
并得到一行像
{“确定”:true,“结果”:{“”}}

我们有第一个秘密短语(令牌)。 现在我们需要找出第二个秘密数字——与机器人聊天的 ID。 每个聊天、群组等都是单独的,并且有自己的号码(有时带有减号 - 对于开放群组)。 为了找到这个数字,我们需要在浏览器中请求(事实上,在浏览器中完全没有必要,但为了更好地理解你可以从它开始)地址(其中 1234544311:NNNNNNNNNN 是你的令牌

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

并得到类似的回应

{“确定”:true,“结果”:[{“update_id”:...,... 即时通话“:{“ID”:123456789

我们需要chat_id。

让我们检查一下是否可以手动写入聊天:从浏览器调用该地址

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

如果您在聊天中收到来自机器人的消息,那么您可以进入下一阶段。

这样(通过浏览器)您可以随时检查链接生成是否存在问题,或者是否有某些内容隐藏在某处并且不起作用。

继续阅读之前您需要了解什么

Telegram 有多种类型的群聊(开放式、封闭式)。 对于这些聊天,某些功能(例如id)是不同的,这有时会导致一些问题。

假设现在是 2019 年底,甚至我们这个时代的英雄、著名的 Man-Orchestra(管理员、律师、信息安全专家、程序员和实际上的 MVP)Evgeniy V. 也将 $i 变量与数组区分开来,已经掌握了循环,看起来在接下来的几年里将掌握巧克力,然后 使用 PowerShell 并行处理 и ForEach-对象并行 它会来。

1.我们考虑我们的机器人会做什么

我没有任何想法,我必须思考。 我已经写了一个机器人笔记本。 我不想制作一个“向某个地方发送东西”的机器人。 要连接到 Azure,您需要一张信用卡,但学生从哪里获得信用卡呢? 应该指出的是,一切都还不错:主要的云免费提供某种测试期(但你仍然需要信用卡号 - 似乎会从中扣除一美元。我不记得是否后来又被退回了。)

如果没有 AI ML,制作一个贫穷的诗人编织者机器人就没那么有趣了。

我决定制作一个机器人来提醒我(或不提醒我)字典中的英语单词。
为了避免摆弄数据库,字典将存储在文本文件中并手动更新。
在这种情况下,任务是展示作品的基础知识,而不是至少制作部分成品。

2. 第一次尝试什么以及如何尝试

让我们创建一个文件夹 C:poshtranslate
首先,让我们看看我们有什么样的powershell,让我们通过start-run启动ISE
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,回车,看一下时间,用命令进入根文件夹
cd
并使用 cls 命令清除屏幕(不,您不需要使用 rm)

现在让我们检查一下什么有效以及如何工作 - 我们甚至不写代码,而是写两行,并尝试理解它们的作用。 让我们用 # 符号注释掉 get-host 行并添加一些内容。

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

(有趣的是,在 Habré 的代码格式下拉列表中,有两打选项 - 但 Powershell 不在那里。Dos 在那里。Perl 在那里。)

让我们通过在 GUI 中按 F5 或“>”来运行代码。

我们得到以下输出:

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 时间

调试器

有时需要将程序执行到某一行并查看该时刻程序的状态。 为此,ISE有一个调试功能——切换断点
在中间某处放置一个断点,运行这两行,看看断点是什么样的。

3. 了解与 Telegram 机器人的交互

当然,关于与机器人交互的文献还有更多,包括 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

如果您在与机器人的聊天中收到一条消息,那么一切都很好,您可以继续。 如果没有,继续调试。

您可以查看 $URL4SEND 字符串变成什么,并尝试在浏览器中请求它,如下所示:

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

3.2. 我们学习了如何在聊天中写“某事”,现在让我们尝试阅读它

让我们再添加 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"

幸运的是,在之前发表的文章《系统管理员的电报机器人》中这一行(是的,根据 $MyMessageGet.RawContent | get-member 是 System.String),已经被拆开了。

4. 处理您收到的内容(我们已经知道如何发送内容)

正如已经写过的 这里,最需要的还是内容。 让我们仔细看看它。

首先,我们将从网络界面或电话中向机器人写入更多短语

/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 系统对象[] 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 有很多优点 - 可读性、导出整个对象以及无需执行 uppend。

让我们尝试 读取xml文件.

从 xml 读取一点内容

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

让我们回到任务上来。 我们写了一个测试文件,读了一下,存储格式很清楚,如果需要的话可以写一个单独的小文件编辑器来添加和删除行。

让我提醒您,任务是制作一个小型训练机器人。

工作格式:我向机器人发送“示例”命令,机器人向我发送随机选择的单词和转录,10 秒后向我发送翻译和评论。 我们知道如何阅读命令,我们还想学习如何自动选择和检查代理,并将消息计数器重置为遗忘。

让我们取消之前注释掉的所有不必要的注释,用 txt 和 csv 注释掉现在不必要的示例,并将文件另存为版本 B106

哦是的。 让我们再次向机器人发送一些东西。

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 对于每个机器人来说都是一个,那么 $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 之间的随机整数 Get-Random -Maximum 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

让我们向机器人发送 /message10、/message11、/message12、/word,然后再次发送 /word 和 /hello。
让我们看看我们得到了什么:

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

让我们检查一下收到的所有内容,如果消息是 /word 则发送响应
构造的情况,有些人称之为 if-elseif,在 powershell 中被称为 通过开关。 同时,下面的代码使用了-wildcard键,这是完全没有必要的,甚至是有害的。

一些代码#7.1

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

让我们运行该脚本几次。 每次执行尝试时,我们都会得到相同的单词两次,特别是如果我们在随机实现中犯了错误。

但停下来。 我们没有再次发送/word,那么为什么消息又被处理了呢?

用于向机器人发送消息的队列的长度有限(我认为是 100 或 200 条消息),必须手动清除。

这当然在文档中有描述,但你必须阅读它!

在这种情况下,我们需要 ?chat_id 参数,并且还不需要 &timeout、&limit、&parse_mode=HTML 和 &disable_web_page_preview=true。

文档用于 电报 API 在这里
上面用白色和英文写着:
要返回的第一个更新的标识符。 必须比先前收到的更新的标识符中的最高标识符大一。 默认情况下,从最早的开始更新
未经证实 更新被返回。 一旦使用 getUpdates 调用,更新就被视为已确认 抵消 更高 比它的 update_id。 可以指定负偏移量以检索从更新队列末尾的 -offset update 开始的更新。 所有以前的更新都将被忘记。

让我们看看:

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

是的,我们将重置它并稍微重写该函数。 我们有两个选择 - 将整个消息传递给函数并在函数中完全处理它,或者仅给出消息 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 

没有人禁止您首先接收所有消息并处理它们,并且只有在成功处理请求未确认 -> 确认后。

为什么在所有处理完成后调用确认才有意义? 执行过程中可能会出现失败,如果以免费聊天机器人为例,丢失一条消息没什么特别的,那么如果您正在处理某人的工资或卡交易,结果可能会更糟。

多几行代码

$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. 代替结论

基本功能 - 读取消息、重置队列、从文件读取和写入文件已完成并显示。

只剩下四件事要做:

  • 在聊天中发送请求的正确答案
  • 向添加机器人的任何聊天发送响应
  • 在循环中执行代码
  • 从 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 ++

感谢所有阅读的人。

来源: habr.com

添加评论