Modelo de um bot simples para Telegram para alunos do 7º ao 9º ano em Powershell

Durante uma conversa com um amigo, fiquei surpreso ao descobrir que as crianças do 8º ao 10º ano na escola deles não aprendem programação. Apenas Word, Excel e mais nada. Nem Logo, nem mesmo Pascal, nem VBA para Excel.

Fiquei muito surpreso, abri a internet e comecei a ler —
Uma das missões da escola especializada é promover a formação de uma nova geração que corresponda ao seu nível de desenvolvimento e estilo de vida nas condições da sociedade da informação.
Este curso permitirá consolidar na prática o conhecimento dos alunos sobre as principais estruturas da linguagem de programação Pascal. (do programa de alguma escola em 2017)

Assim, decidi gastar algumas horas para esboçar um exemplo de "como criar um robô simples — para estudantes".

Abaixo, sobre como escrever mais um robô simples em PowerShell e fazê-lo funcionar sem webhook, IPs públicos, servidores dedicados, máquinas virtuais em nuvem e assim por diante — em um PC doméstico normal com Windows comum.

TLDR: Mais um artigo chato com erros gramaticais e factuais, não há nada a ler, sem humor, sem imagens.

Não há nada de novo no artigo, quase tudo que está escrito já foi publicado antes em Habr, por exemplo, nos artigos Instrução: Como criar robôs no Telegram e Bot do Telegram para o administrador de sistemas.
Além disso, o artigo é propositalmente redundante para não precisar citar toda vez a literatura de referência. Não há menções a banda 4, PowerShell Deep Dives ou, digamos, The 5 Pillars of the AWS Well-Architected Framework no texto.

Em vez de uma introdução, pode-se pular

Vamos pular sem medoEm 2006, a Microsoft lançou o PowerShell 1.0 para o então Windows XP, Vista e servidor 2003. De certa forma, ele substituiu elementos como scripts cmdbat, scripts vb, Windows Script Host e JScript.

Mesmo agora, o PowerShell pode ser visto apenas como o próximo passo após as versões do Logo, em vez dos Delphi utilizados ainda em alguns lugares (ou algo mais antigo), apesar de ter ciclos, classes, funções, chamadas de MS GUI, integração com Git e assim por diante.

O uso do PowerShell é relativamente raro, você pode encontrá-lo talvez apenas na forma do PowerShell Core, VMware vSphere PowerCLI, Azure PowerShell, MS Exchange, Desired State Configuration, PowerShell Web Access e mais uma dúzia de programas e funções raramente utilizados. É possível que ele ganhe uma nova vida com o lançamento WSL2, mas isso não é certo.

O PowerShell tem três grandes vantagens:

  1. É relativamente simples, há muita literatura e exemplos sobre isso, e até em russo, como por exemplo, um artigo sobre Foreach — do livro PowerShell em profundidade — sobre a diferença () e {}
  2. Ele vem junto com o editor ISE, incluído no Windows. Até mesmo um depurador está disponível.
  3. É fácil chamar componentes para construir interfaces gráficas.

0. Preparação.

Precisaremos de:

  • um PC com Windows (eu uso Windows 10)
  • Alguma conexão com a internet (através de NAT, por exemplo)
  • Para aqueles com acesso limitado ao Telegram — o freegate instalado e configurado no navegador, em alguns casos complicados junto com Symple DNS Crypt
  • Ter um cliente Telegram funcional no telefone
  • Conhecimento básico — o que são variáveis, arrays, loops.

Artigos abertos e lidos — Instrução: Como criar robôs no Telegram e Bot do Telegram para o administrador de sistemas

1. Vamos criar mais um bot de teste.

Como todo mundo já sabe disso e já foi feito, isso também pode ser puladoComo mencionado no artigo acima — Antes de tudo, um bot para Telegram — é ainda um aplicativo executado do seu lado, fazendo solicitações à API do Bot do Telegram. A API é clara — o bot faz uma solicitação a uma URL específica com parâmetros, e o Telegram responde com um objeto JSON.

Problemas relacionados: se de alguma forma desconhecida você pegar algum código de um objeto JSON e enviar para execução (não intencionalmente) — o código será executado.

O processo de criação está descrito em dois artigos acima, mas vou repetir: no Telegram, abrimos os contatos, procuramos @botfather, dizemos a ele /newbot, criaremos o bot Botfortest12344321, chamaremos de Mynext1234bot e receberemos uma mensagem com uma chave única do tipo 1234544311:AbcDefNNNNNNNNNNNNN

Guarde a chave e não a compartilhe!

Depois, podemos configurar o bot, como proibir a adição dele a grupos, mas nos primeiros passos isso não é necessário.

Perguntaremos ao BotFather «/mybot» e ajustaremos as configurações, se algo não estiver certo.

Novamente abriremos os contatos, encontraremos @Botfortest12344321 (começar a busca com @ é obrigatório), clicaremos em «começar» e escreveremos para o bot «/Glória aos robôs». O sinal / é obrigatório, as aspas não são necessárias.
Claro, o bot não responderá.

Vamos verificar se o bot foi criado — abriremos.

api.telegram.org/bot1234544311:AbcDefNNNNNNNNNNNNN/getMe
onde 1234544311:AbcDefNNNNNNNNNNNNN — a chave obtida anteriormente,
e receberemos uma string como
{«ok»:true,«result»:{«»}}

A primeira frase secreta (token) já temos. Agora precisamos descobrir o segundo número secreto — o ID do chat com o bot. Cada chat, grupo e assim por diante — são individuais e têm seu próprio número (às vezes com um traço — para grupos abertos). Para descobrir esse número, precisamos solicitar no navegador (na verdade, não é absolutamente necessário usar um navegador, mas para melhor compreensão, podemos começar por ele) o endereço (onde 1234544311:NNNNNNNNN — é o seu token

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

e receber uma resposta do tipo

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

Precisamos exatamente do chat_id.

Verificamos se podemos escrever no chat manualmente: chamaremos do navegador o endereço

https://api.telegram.org/botseutoken/sendMessage?chat_id=123456789&text="A vida é um movimento direcionado"

Se uma mensagem do bot chegou ao seu chat — tudo certo, você prossegue para a próxima etapa.

Dessa forma (pelo navegador) você sempre pode verificar onde estão os problemas — se na geração do link, ou se algo está bloqueado e não funcionando.

O que você precisa saber antes de continuar a leitura

No Telegram, existem vários tipos de chats em grupo (abertos, fechados). Para esses chats, algumas funcionalidades (como o id) variam, o que às vezes causa alguns problemas.

Vamos considerar que estamos no final de 2019, e mesmo o herói de nosso tempo, amplamente conhecido como Homem-Orquestra (administrador, advogado, especialista em segurança da informação, programador e praticamente MVP) Eugênio V. distingue uma variável $i de um array, dominou loops, quem sabe nos próximos dois anos dominará o Chocolatey, e então chegará a Processamento paralelo com PowerShell e ForEach-Object Paralelo outra coisa.

1. Pensamos, o que nosso bot vai fazer

Não tinha ideias, tive que pensar. Já escrevi um bot de anotações. Não queria fazer um bot "que envia algo para algum lugar". Para conectar ao Azure é necessário um cartão de crédito, e de onde vai sair isso para um estudante? É necessário notar que não está tão ruim: as principais nuvens oferecem algum período de teste gratuito (mas o número do cartão ainda é necessário — e, pelo que parece, será debitado um dólar. Não me lembro se ele voltou depois).

Sem AI, fazer um bot-simpático-de-poema não é tão interessante.

Decidi fazer um bot que irá me (ou não me) lembrar palavras em inglês do dicionário.
O dicionário, para não ter que lidar com um BD, estará em um arquivo de texto e será atualizado manualmente.
Neste caso, o objetivo é mostrar os fundamentos do trabalho, e não criar um produto que esteja pelo menos parcialmente pronto.

2. Vamos tentar algo pela primeira vez

Vamos criar a pasta C:poshtranslate
Para começar, vamos verificar o que temos em powershell, vamos abrir o ISE através do executar
powershell ise
ou vamos encontrar o Powershell ISE nos programas instalados.
Após a abertura, aparecerá um ‘editor qualquer’, se não houver campo de texto, sempre podemos clicar em 'Arquivo — criar novo'.

Vamos ver a versão do powershell — vamos digitar no campo de texto:

get-host 

e pressionar F5.

O Powershell vai perguntar se queremos salvar — ‘O script que você está prestes a executar será salvo.’, vamos concordar e salvar no C:poshtranslate um arquivo do powershell com o nome myfirstbotBT100.

Após a execução, na janela de texto inferior receberemos uma tabela de dados:

Nome             : Windows PowerShell ISE Host
Versão          : 5.1.(e assim por diante)

Eu tenho a versão 5.1 com algo a mais, isso é suficiente. Se você tiver um Windows 7/8 antigo, não se preocupe — embora seja necessário atualizar o PowerShell para a versão 5 — por exemplo, no documentação.

Digitemos na linha de comando embaixo Get-Date, pressionemos Enter, vejamos a hora, vamos para a pasta raiz com o comando
cd
e limpar a tela com o comando cls (não, não precisamos usar rm)

Agora vamos verificar o que e como funciona — vamos escrever não um código, mas duas linhas, e tentar entender o que elas fazem. Vamos comentar a linha com get-host com o símbolo # e escrever um pouco mais.

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

(O que é interessante. Na lista suspensa de formatação de código no Habr, há duas dezenas de opções — mas powershell não está lá. Dos está. Perl está.)

E vamos executar o código pressionando F5 ou ‘>’ da interface gráfica.

Vamos obter a saída:

Sábado, 8 de dezembro de 2019 21:00:50 PM (ou algo parecido)

Agora vamos analisar essas duas linhas, e alguns momentos interessantes, para não termos que voltar a isso mais tarde.

Diferente do Pascal (e não só), o PowerShell tenta determinar automaticamente qual tipo atribuir à variável, mais detalhes sobre isso estão escritos no artigo Introdução à tipagem em linguagens de programação
Portanto, ao criar a variável $TimeNow e atribuir a ela o valor da data e hora atuais (Get-Date), não precisamos nos preocupar com qual tipo de dado vai estar lá.

Claro, a falta de conhecimento pode ser dolorosa mais tarde, mas isso é um problema para depois. Abaixo no texto haverá um exemplo.
Vejamos o que obtivemos. Vamos executar (na linha de comando)

$TimeNow | Get-member

e vamos obter uma página de texto confuso

Exemplo de texto confuso número 1

PS C:&gt; $TimeNow | Get-member
   TypeName: System.DateTime
Name                 MemberType     Definition                                                                                                                                       
----                 ----------     ----------                                                                                                                                       
Adicionar                  <b>Método         </b>datetime Adicionar(timespan valor)  
..
ExibirDica          NotaPropriedade   TipoExibirDica ExibirDica=DataHora                                                                                                             
Data                 <b>Propriedade       </b>datetime Data {get;}                                                                                                                             
Ano                 Propriedade       int Ano {get;}   
..                                                                                                                               
DataHora             PropriedadeScript Sistema.Object DataHora {get=if ((&amp; { DefinirModoEstrito -Versão 1; $this.ExibirDica }) -ieq  "Data")...                                         

Como é visível, foi criada uma variável do tipo TypeName: System.DateTime com um monte de métodos (no sentido de que podemos fazer com esse objeto variável) e propriedades.

Chamaremos $TimeNow.DayOfYear — obteremos o número do dia no ano.
Chamaremos $TimeNow.DayOfYear | Get-Member — obteremos TypeName: System.Int32 e um grupo de métodos.
Chamaremos $TimeNow.ToUniversalTime() — e obteremos a hora em UTC

Depurador

Às vezes, é necessário executar um programa até uma certa linha e ver o estado do programa nesse momento. Para isso, o ISE tem a função Debug — toggle break point
Coloque um ponto de interrupção em algum lugar do meio, execute essas duas linhas e veja como fica a parada.

3. Entendendo a interação com o bot do Telegram

Claro que há uma grande quantidade de literatura sobre a interação com o bot, todos os getpush, etc., mas a questão da teoria pode ser abordada de forma facultativa.

No nosso caso, precisamos:

  • Aprender a enviar algo na conversa
  • Aprender a receber algo da conversa

3.1 Aprendendo a enviar algo na conversa e receber de volta

Um pouco de código — parte 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

e na Rússia, nesse ponto, recebemos o erro Unable to connect to the remote server.

Ou talvez não recebamos — depende do operador de rede e se o proxy está configurado e funcionando
Bem, resta adicionar o proxy. Lembre-se – usar proxies não criptografados e desconhecidos é extremamente perigoso para sua saúde.

A tarefa de encontrar um proxy funcional não é muito complicada — a maior parte dos proxies http publicados funciona. O que utilizei parece ter sido o quinto na lista.

A sintaxe para usar o proxy:

Invoke-WebRequest -Uri $URL4SEND -Proxy $MyProxy

Se você recebeu uma mensagem no seu chat com o bot — tudo ótimo, podemos prosseguir. Se não — continue com a depuração.

Você pode ver como sua string $URL4SEND se transforma e tentar solicitá-la no navegador, por exemplo assim:

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

3.2 Aprendemos a escrever "algo" no chat, agora vamos tentar ler

Vamos adicionar mais 4 linhas e ver o que há lá dentro através de | 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

O mais interessante nos é fornecido

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

Vamos ver o que há neles:

Write-Host "ParsedHtml"
$MyMessageGet.ParsedHtml # aqui está algo interessante
Write-Host "RawContent"
$MyMessageGet.RawContent # e aqui também está algo interessante, mas além disso, é legível.
Write-Host "Content"
$MyMessageGet.Content

Se tudo estiver funcionando, você receberá uma longa string como:

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

Felizmente, na artigo anterior sobre o bot do Telegram para administradores de sistema, esta linha (sim, de acordo com $MyMessageGet.RawContent | get-member — é um System.String), já foi analisada.

4. Processar o recebido (já sabemos como enviar algo)

Como já foi mencionado aqui, o mais necessário está em content. Vamos analisá-lo mais de perto.

Primeiro, vamos escrever mais algumas frases para o bot a partir da interface web ou do telefone

/message1
/message2
/message3

e vamos observar pelo navegador o endereço que foi gerado na variável $URLGET.

Nós veremos algo como:

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

O que é isso? Um objeto complexo de arrays de objetos, contendo um identificador de mensagem fluido, um identificador de chat, um identificador de envio e uma infinidade de informações.

No entanto, não precisamos analisar "o que é esse objeto" — parte do trabalho já foi feito por nós. Vamos ver o que há dentro:

Lendo as mensagens recebidas ou parte 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. O que devemos fazer agora com isso

Vamos salvar o arquivo recebido com o nome myfirstbotBT105 ou como você preferir, mudar o título e comentar todo o código já escrito através de

<#start comment 105 end comment 105#>

Agora precisamos definir onde pegar o dicionário (como onde — no disco em um arquivo) e como ele será estruturado.

Claro, é possível preencher um enorme dicionário diretamente no texto do script, mas isso não é adequado.
Portanto, vamos ver com o que o PowerShell lida normalmente.
Na verdade, não importa com qual arquivo ele trabalha, mas importa para nós.
Temos a opção de: txt (pode, mas por que), csv, xml.
Ou podemos ver todos vamos examinar todos.
Vamos criar a classe MyVocabClassExample1 e a variável $MyVocabExample1
notarei que a classe é escrita sem $

um pouco de código #5

write-host "Este é o trecho 5"
class MyVocabClassExample1 {
    [string]$Original  # palavra
    [string]$Transcript
    [string]$Translate
    [string]$Example
    [int]$VocWordID # um detalhe muito interessante. O uso de int com suas limitações pode às vezes levar a consequências inesperadas, como o recente caso com SSD HPE. Inicialmente, não adicionei esse elemento, mas depois acabei incluindo e comentando.
    }

$MyVocabExample1 = [MyVocabClassExample1]::new()
$MyVocabExample1.Original = "Apple"
$MyVocabExample1.Transcript = "[ ˈapəl ]"
$MyVocabExample1.Translate = "Maçã"
$MyVocabExample1.Example = "Uma maçã é um fruto doce e comestível produzido por uma macieira (Malus domestica)"
# $MyVocabExample1.$VocWordID = 1

$MyVocabExample2 = [MyVocabClassExample1]::new()
$MyVocabExample2.Original = "Pear"
$MyVocabExample2.Transcript = "[ pe(ə)r ]"
$MyVocabExample2.Translate = "Pera"
$MyVocabExample2.Example = "A pera (\/ˈpɛər\/) é uma espécie do gênero Pyrus"
# $MyVocabExample1.$VocWordID = 2

Vamos tentar gravar isso em arquivos de acordo com o modelo.

Um pouco de código #5.1

Write-Host $ScriptDir # espero que você não tenha comentado $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

— e teremos um erro na linha Out-File -FilePath $MyFilenameExample01 -InputObject -Append $MyVocabExample2.

Ele não quer adicionar, que pena.

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

Vamos ver o que saiu. Uma bela visualização de texto — e como exportar isso novamente? Precisamos inserir algum delimitador, como vírgulas?

E no final obter um "arquivo com delimitadores — vírgulas, valores separados por vírgulas (CSV) A PARE, ESPERE.
#

$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 

É fácil ver que a Microsoft não se destacou muito na lógica; para um procedimento semelhante, em um caso é usado -FilePath e no outro -Path.

Além disso, no terceiro arquivo o russo desapareceu, e no quarto arquivo saiu... bem, algo saiu. #TYPE System.Object[] 00
# „Count“,»Length»,«LongLength»,«Rank»,«SyncRoot»,«IsReadOnly»,«IsFixedSize»,«IsSynchronized»
#
Vamos reescrever um pouco:

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

Parece que ajudou — mas o formato ainda não me agrada.

Particularmente, não gosto que não posso colocar as linhas do objeto diretamente em um arquivo.
Aliás, já que começamos a escrever em arquivos - talvez seja hora de começar a registrar logs de execução? Temos o tempo como variável e sabemos como definir o nome do arquivo.

Escrever, na verdade, ainda não temos nada, mas podemos pensar em como fazer a rotação dos logs da melhor forma.
Por enquanto, vamos testar o xml.

Um pouco de 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

A exportação para xml tem apenas vantagens - legibilidade, exportação de todo o objeto e não é necessário realizar append.

Vamos tentar ler o arquivo xml.

Um pouco de leitura do xml

$MyFilenameExample06 = $ScriptDir + "Example06.xml"
$MyVocabExample4AsArray = Import-Clixml -Path $MyFilenameExample06
# $MyVocabExample4AsArray 
# $MyVocabExample4AsArray[0]
# e um pouco sobre nuances que não são tão óbvias. O Powershell às vezes se comporta de maneira diferente do que se esperaria.
# por exemplo, essas duas saídas diferem
# Write-Output $MyVocabExample4AsArray 
# write-host $MyVocabExample4AsArray 

Vamos voltar à tarefa. O arquivo de teste foi gravado, lido, o formato de armazenamento é compreensível, se necessário, podemos escrever um pequeno editor de arquivos separado para adicionar e remover linhas.

Lembro que a tarefa era fazer um pequeno bot de treinamento.

Formato de operação: eu envio um comando ao bot dizendo "exemplo", o bot me envia uma palavra escolhida aleatoriamente e a transcrição, e após 10 segundos envia a tradução e comentário. Podemos ler comandos, só precisamos aprender a selecionar e verificar proxies automaticamente e resetar contadores de mensagens.

Vamos descomentar tudo que foi comentado anteriormente como desnecessário, comentar os exemplos com txt e csv que se tornaram desnecessários e salvar o arquivo como versão B106.

Ah, sim. Vamos enviar algo para o bot novamente.

6. Envio de funções e não só

Antes de processar a recepção, precisamos fazer uma função de envio de "qualquer coisa", além de uma mensagem de teste.

Claro, em nosso exemplo, haverá apenas um envio e apenas um processamento, e se precisarmos fazer a mesma coisa várias vezes?

Mais fácil escrever uma função. Assim, temos uma variável do tipo objeto $MyVocabExample4AsArray, lida do arquivo, em forma de um array com dois elementos.
Vamos lá ler.

Ao mesmo tempo, vamos entender sobre os relógios, isso será necessário depois (na verdade, neste exemplo - não será 🙂

Um pouco de código #6.1

Write-Output "Este é o Parte 6"
$Timezone = (Get-TimeZone)
IF($Timezone.SupportsDaylightSavingTime -eq $True){
    $TimeAdjust =  ($Timezone.BaseUtcOffset.TotalSeconds + 3600) } # horário ajustado
    ELSE{$TimeAdjust = ($Timezone.BaseUtcOffset.TotalSeconds) 
    }
    
function MyFirstFunction($SomeExampleForFunction1){
$TimeNow = Get-Date
$TimeNow.ToUniversalTime()
# $MyText02 = $TimeNow + " " + $SomeExampleForFunction1 # e aqui teremos um erro
$MyText02 = $SomeExampleForFunction1 + " " + $TimeNow # mas aqui não teremos, quem adivinhar por que - está de parabéns.

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

Como é fácil ver, a função chama $MyToken e $MyChatID, que foram atribuídos anteriormente de forma rígida.

Isso não deve ser feito, e, se $MyToken for o mesmo para cada bot, então $MyChatID irá variar dependendo do chat.

No entanto, como este é um exemplo, vamos ignorar isso por enquanto.

Como $MyVocabExample4AsArray não é um array, embora pareça muito com um, não podemos simplesmente pegar e solicitar seu comprimento.

Teremos que fazer mais uma vez o que não se deve fazer — descambar fora do código — pegar e contar

Um pouco de código #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)
# ou em uma linha
# MyFirstFunction($MyVocabExample4AsArray[Get-Random -Minimum 0 -Maximum ($MaxRandomExample -1)].Example)
# Adivinhe você mesmo, qual exemplo é mais legível para pessoas externas.

Aleatório função interessante. Suponha que queremos receber 0 ou 1 (temos apenas dois elementos no array). Ao definir os limites como 0..1 — vamos obter "1"?
não — não vamos, temos um exemplo específico: Example 2: Obter um número inteiro aleatório entre 0 e 99 Get-Random -Maximum 100
Portanto, para 0..1 teremos que definir o tamanho como 0..2, sendo que o número máximo de elementos = 1.

7. Processamento das mensagens recebidas e comprimento máximo da fila

Onde paramos anteriormente? temos a variável recebida $MyMessageGet
e a obtida dela $Content4Pars01, dos quais nos interessam os elementos do array Content4Pars01.result

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

Vamos enviar para o bot /message10, /message11, /message12, /word e mais uma vez /word e /olá.
Vamos ver o que recebemos:

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

Vamos percorrer tudo o que recebemos e enviar uma resposta, se a mensagem foi /word
a construção case of, o que alguns descrevem como if-elseif, no PowerShell é chamado através do switch. O código abaixo utiliza a chave -wildcard, o que não é absolutamente necessário e até mesmo prejudicial.

Um pouco de código #7.1

Write-Output "Esta é a parte 7"
Foreach ($Result in $Content4Pars01.result) # Sim, pode-se fazer mais rápido
 { 
    switch -wildcard ($Result.message.text) 
            {
            "\/word" {MyFirstFunction($TextForExample1)}
            }
}

Executaremos o script algumas vezes. Iremos obter a mesma palavra em cada tentativa de execução, especialmente se errarmos na implementação do random.

Mas espera. Não enviamos \/word novamente, por que a mensagem está sendo processada novamente?

A fila para enviar mensagens ao bot tem um comprimento finito (parece ser 100 ou 200 mensagens), e precisa ser limpa manualmente.

Na documentação isso está obviamente descrito, mas é preciso ler!

Neste caso, precisamos do parâmetro ?chat_id, e &timeout, &limit, &parse_mode=HTML e &disable_web_page_preview=true ainda não são necessários.

Documentação sobre telegram api está aqui
Em inglês, está escrito claramente:
Identificador da primeira atualização a ser retornada. Deve ser maior em um do que o maior entre os identificadores das atualizações recebidas anteriormente. Por padrão, as atualizações começam a partir da mais antiga
não confirmada atualização é retornada. Uma atualização é considerada confirmada assim que getUpdates é chamada com um offset maior do que seu update_id. O deslocamento negativo pode ser especificado para recuperar atualizações começando a partir da -offset atualização do final da fila de atualizações. Todas as atualizações anteriores serão esquecidas.

Vamos olhar para:

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

E vamos redefinir — vamos reescrever a função um pouco. Temos duas opções — passar toda a mensagem para a função e processá-la completamente nela, ou apenas devolver o ID da mensagem e também redefini-lo. Para o exemplo, a segunda opção parece mais simples.

Antes, nossa string de consulta "todas as mensagens" era assim:

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

e ficará assim:

$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 

Ninguém proíbe obter primeiro todas as mensagens, processá-las, e só depois solicitar unconfirmed -> confirmed.

Por que vale a pena chamar a confirmação após concluir todos os processamentos? Pode ocorrer uma falha no meio da execução, e, se para um chatbot gratuito perder alguma mensagem única não é tão grave, ao processar o salário de alguém ou uma transação de cartão, o resultado pode ser ainda pior.

Mais algumas linhas de código

$LastMessageId = ($Content4Pars01.result | select -last 1).update_id  #presume que o erro aqui deve ser corrigido manualmente. 
$URLGET1 = "https://api.telegram.org/bot$mytoken/getUpdates?offset=$LastMessageId&limit=100" 
Invoke-WebRequest -Uri $URLGET1 -Method Get -Proxy $MyProxy

8. Em vez de conclusão

As funções principais — leitura de mensagens, redefinição de fila, leitura de arquivo e gravação em arquivo foram realizadas e mostradas.

Restam apenas quatro coisas a fazer:

  • enviar a resposta correta à consulta no chat
  • enviar a resposta para QUALQUER chat onde o bot foi adicionado
  • executar o código em um loop
  • iniciar o bot a partir do agendador do Windows.

Todas essas tarefas são simples e podem ser facilmente realizadas ao ler a documentação sobre parâmetros como
Set-ExecutionPolicy Unrestricted e -ExecutionPolicy Bypass
loop do tipo

$TimeToSleep = 3 # verificação a cada 3 segundos
$TimeToWork = 10 # minutos
$HowManyTimes = $TimeToWork*60/$TimeToSleep # contador para o loop
$MainCounter = 0
for ($MainCounter=0; $MainCounter -le $HowManyTimes) {
sleep $TimeToSleep
$MainCounter ++

Agradeço a todos que leram até aqui.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster