Manage IT infrastructure using Telegram bot or infrabot.io

infrabot.io
14 min readJan 8, 2021
infrabot.io

Friday. The working day is over. Joyful, on the eve of two days of rest, namely Saturday and Sunday, just like my colleagues I took my belongings and went home. Due to the strong growth of COVID-19 cases, government decided to introduce various kinds of restrictions, including limiting the temporary stop of the subway, respectively, everyone was poured into public transport — buses, so getting home became a real challenge. This in turn caused much more overcrowding on buses and increased congestion on already congested roads. Therefore, if earlier it took 30–40 minutes for the road, now it is at least an hour and a half. For obvious reasons, you can’t walk freely on the bus either, you stand barely squeezed in the corner, trying to barely hold on. During my “great trip” to home on a bus, suddenly a message arrives in the general IT group in WhatsApp, asking to unblock the user. After a quick “Ping” of colleagues, with several “Request timed out”, it became clear that relatively only me, who was on the bus, barely standing in the corner, had the opportunity to connect and unblock the user. Cursing everything in the world, I connected via VPN from my phone, barely, somehow unblocked the user within 10–15 minutes and immediately reported on unblocking in the group.

On the same day, closer to 11 o’clock in the evening at home, during the absorption of musical content, at the very peak of the chorus of the song, a message came to the chat again about a request to unblock another user. There was no choice — I had to connect and unblock, but the listening experience deteriorated.

It would seem that this is definitely all. Now I could calmly not think about anything, have a rest and come fresh to work on Monday.

Well, guess what? The next day, Saturday, again a message into the group was sent, about another user — “unlock pleeeaaaasssseeeee!!1!1!1”. But I saw this message an hour and a half later, because the phone was far away and I did not hear the notification sound, but thankfully my colleagues intervened and unblocked the user, but 40 minutes after the request was received. A quick “SSH” of colleagues showed that the message was considered by them immediately, but for certain valid reasons they could not unblock it at the moment when requested.

So I decided that this cannot continue anymore! After all, there must be some quick way to solve such spontaneous tasks outside working hours, and so that the helpdesk support staff can do it too!

T̶h̶i̶n̶k̶i̶n̶g̶ ̶h̶a̶r̶d̶. Googling

A diligent search was carried out in the deepest places of the mind, and complex mathematical calculations were carried out on an astronomical scale. As a result of the process, there was even a couple of BSODs, Seg fault and Memory overflow of the brain. The whole process took 10 seconds, after which I gave up and turned to Google for help.

A small search on Google did not give sane results, maybe I was looking badly, but it led me to a couple of repositories on GitHub (1, 2).

Then I came to the conclusion that the best and relatively simple way to quickly solve any small tasks outside of working hours is to use a Telegram bot. Just send him a command, after completion of which, bot reports the result, and the problem solved, and it took a couple of seconds of it, and without much fuss.

At first I tried to use scripts from the mentioned above repositories, but after a while I came to the conclusion that they are not very suitable for the following reasons:

  • Although the Telegram API is simple, you have to play a lot in the PowerShell code with passing string values to variable. I don`t say that messing with variables is difficult, but it is not very convenient, when the code becomes cluttered and you can get confused, especially when you see something like:
$($URL_get)?offset=$($($data.update_id)+1)?date=$((Get-Date).ToString("yyyy:MM:dd"))something
  • The script itself will not work in the background all the time, so you need to either put all the functionality into while($true) loop or run it with the Windows task scheduler every few seconds, which is not a very good solution. An increase in the launch time will mean that the bot will not respond to our requests immediately, namely, the response time will be at least equal to the launch interval time, and maybe more;
  • An increase in the commands understood by the bot automatically leads to an increase in the size of the script code, where the subsequent troubleshooting becomes more complicated. In addition, not all colleagues have the same scripting abilities. Someone is familiar with scripts, while others have difficulty understanding the while($true) record, and a banal if-else check in the code will lead to incomprehensible errors. There must be some easier way to add functionality into the bot;
  • Not everyone has the same idea of how code should be styled. This point is not very important, but for me it is essential. It becomes difficult to read different pieces of code when they are clumsy, in my opinion, but perfectly readable for others;

After some brainstorming, I came up to the conclusion that I can’t do without creating an application and just simple scripting will not help here.

Having weighed all the possible options, I decided to write an application on .NET Core 5.0, which will allow it to run on both Windows and Linux, and in the future, it will be possible to put it into a Docker container (I don’t know how to do this correctly yet, I will very grateful for hints in this direction). There was no desire to install heavy Visual Studio, so all development was carried out in Visual Studio Code with the installation of plugins for C# development, which was quite enough for everything.

Defining a plan

A goal without a plan is just a desire! (Antoine de Saint-Exupery)

Therefore, I wrote down the following plan:

  • The application should be able to work both from launching from the console and as a Windows service. The ability to run as a Windows service will allow to run it using a limited, non administrative account or even by using an Active Directory Managed Service Account;
  • To ensure the addition of an unlimited number of commands for the bot to understand without changing the application source code, there must be a place where they can be added and the application must be able to read and understand it, which means we need a configuration file. I chose to store data in JSON format;
  • The application should provide the ability to configure accesses to all commands, as well as to each command separately. For example, the bot will respond to commands only from the specified Telegram users — the organization’s system administrators, but let’s say only the manager in a team will have conditional access to the server restart command;
  • The application must be able to execute necessary PowerShell script with arguments, receive the result of the execution (output) and send it to chat;
  • There should be a GUI utility that will allow to change, delete or add settings in the config.json file without messing up with it in a text editor, since not everyone wants to go into the jungle of the configuration file. To create such an application, I chose the Windows Presentation Foundation (WPF) technology (I hate Electron), which will make it easy to create an adaptive interface (hello XAML);

Development

If builders worked in the same way as programmers, code, then any bird that sat down to rest on the roof of a house could cause the death of civilization.

Creating a C# project in Visual Studio Code is quite simple. In the terminal, I navigated to an empty folder and wrote the command:

dotnet new console

All necessary files will be created including Program.cs, which is a minimal Hello World console application, that is, the main entry point for our application.

In order for it to be able to support running as a windows service, I installed the Nuget package System.ServiceProcess.ServiceController using the command:

dotnet add package System.ServiceProcess.ServiceController — version 5.0.0

and then added the following minimal construct to Program.cs:

Windows Service code snippet

As you can see from the example, the amount of code is small, but it allows to achieve a lot.

Then I installed Nuget packages Newtonsoft.Json and Telegram.Bot:

dotnet add package Newtonsoft.Json - version 12.0.3 
dotnet add package Telegram.Bot - version 15.7.1

For configuration file deserialization, I created three classes:

  • Config.cs — describes all the global settings for our bot and contains an array of available commands;
  • Command.cs — describes all the command parameters that the bot can execute and contains an array of standard responses displayed to the Telegram chat;
  • ExecuteResult.cs — describes all standard responses, one of which will be sent to the Telegram chat, based on the result obtained from the executed script;

I took the minimum code required for the bot to work from here, which looks like:

Telegram Bot minimal example code

As you can see from the code, all received messages from the bot are processed in the Bot_OnMessage function. At first I wrote all the command processing code in it, but then I realized that the Program.cs file was getting too cluttered, and for future development it would be best to create a separate CommandCenter class and handle everything in it.

It is pointless to add this entire class to the article, since it is quite cumbersome, those who wish can look at it on GitHub, but nevertheless, at the level of pseudocode, I will describe how it works:

After creating such functionality, the idea came up that this is still not enough.

But what if I have no arguments passed to the script and I need the bot to send back the entire result, for example, the result of the ipconfig command? But what if I do not want PowerShell scripts, but I want my own custom application instead and so that either it can work both with arguments with custom answers or without them at all giving the output of the entire result?

Therefore, the command_execute_type parameter was added to the command settings, which determines the type of command. If its value is:

  • 1 — custom application with its own answers, which can accept arguments;
  • 2 — custom application with no answers and no arguments, where all the output is sent to the user;
  • 3 — PowerShell script with its own responses, which can accept arguments;
  • 4 — PowerShell script with no answers and no arguments, where all output is sent to the user;

Additional commands

The idea for additional commands came during development. Below is a short information about them:

  • /emergency — termination of the application in case of emergency. You can configure access to this command;
  • /getcommands — shows the entire list of available commands with theirs short description, which is specified in the “command_help_short” parameter. If the command has the value “command_show_in_get_commands_list” true, then the command will not be displayed in the list. It is possible to configure access to this command;
  • /reloadconfig — reads the configuration file again. Allows to apply updated configuration without restarting the application. You can configure access to this command;
  • /remindme — Shows the specified reminder text at the specified time. Access to this command is configurable;

Examples of commands with PowerShell script

Sysadmins love to pop bubble wrap because every bump is a user’s eye!

Depending on the type of command, the configuration script may look different.

Example 1

Let’s suppose that we want to create a command which restarts the server and we want to use a PowerShell script for this. Obviously, our command (including the script) must take one argument, which indicates the DNS name or IP of the server. Example command:

/restartserver server01

or

/restartserver 10.120.20.15

Depending on the result of the script execution, the bot should show us an appropriate message. Thus, the configuration in the config.json file will look like this:

Example 1 JSON configuration

As you can see from the configuration, when the bot receives a command starting with “/restartserver(command_starts_with), it will send our script (command_execute_file) for execution to PowerShell, where the second part of the command (after a space) (command_data_id) will be the argument. Depending on the result from the script, the bot will show the desired text (command_execute_results). If the expected case is not found in the results, then the bot will show a standard error (command_default_error). When calling the command “/restartserver ?” the manual for the command (command_help_manual) will be shown. When the command “/getcommands” is called, this command will be displayed in the list of available commands along with a short description (command_help_short), as this command is enabled to be shown in the general list of commands (command_show_in_get_commands_list).

The script itself will have the following form:

Example 1 PowerShell script

Example 2

In the second example, we want to create a command that does not receive any arguments, but simply shows the user the entire ipconfig result from the script.

Then the configuration in the config.json file will look like this:

Example 2 JSON configuration

As you can see from the example, the list of standard responses (command_execute_results) is empty. There is no point to define anything here as we need the entire result of script execution. For the fourth type of commands (command_execute_type), the bot will ignore entries in the standard results (command_execute_results).

The script for this case will be simple:

Example 2 PowerShell script

Example 3

In this example, we will consider the case when our command can accept not one, but even several arguments, but the result from the execution needs to be displayed as it is (as in the second example). In this case, the configuration will be as follows:

Example 3 JSON configuration

Since the bot checks the responses in the order specified in the list (command_execute_results), the verification steps will be as follows:

  • “result_value”: “0” — Due to the fact that result_checktype is specified as 1 (Equal to value), the output from the script will be checked with the value “0” for equality and, if successful, the text from result_output will be displayed;
  • “result_value”: “2” — Due to the fact that result_checktype is specified as 1 (Equal to value), the output from the script will be checked with the value “2” for equality and, if successful, the text from result_output will be displayed;
  • “result_value”: “” — Because result_checktype is specified as 2 (Contains), the output from the script will be checked with the value “” for content, which will always be true. Since the result_output is {RESULT}, the entire output of the script after execution will be shown as it is. It is important here to always write this entry at the end of the answer options, since due to the fact that the result of the check will always be positive, it will not allow other checks to be performed after itself;

The script for this case will be as follows:

1
Example 3 PowerShell script

Notes

It may be that your organization has strict PowerShell scripts execution policies. By default, the Bot launches PowerShell using ExecutionPolicy Unrestricted (telegram_powershell_executionpolicy parameter) for the current session. I recommend changing this setting to the safer ExecutionPolicy AllSigned, but you will have to sign all your scripts with a certificate in advance, otherwise they will not work! To comply with the security policy of your organization, you can change this setting to the one you need in the configuration file.

All of the above is also true for your custom application. In this case, you must enter the path to your executable file in the command_execute_file parameter.

GUI Configurator

GUI Configurator

I think it makes no sense to present the source code in the article, especially since it is quite banal and cumbersome. Although the implementation of the application suffers and is not devoid of bugs, it does its job. Among the difficulties that I encountered during the creation of this application is the logic of how to correctly write back the information received from the form back to the right part of the config, because the information can be a dynamic array and sometimes in which there can also be another dynamic array (and everything using ListBox-es).

infrabot.io

After the work done, I decided to create my open source startup project based on all of the above created. Obviously, the idea is not new and there are many other options and alternatives. But nevertheless it seemed to me that it would not be superfluous to share the work done, and I hope someone will need it and will help out more than once.

I have been choosing the name for the startup for a long time, then spent twice as much time searching for a domain for a very limited budget. A couple of times I had to give up the chosen name because, domain with that name had been already chosen, or the price for a domain might reach a couple of thousand dollars.

In the end, I settled on infrabot.io, rented a VPS server, wrote a website using Java Servlets and did a bunch of different actions to set up everything in the ready state. A couple of times I had to completely redo everything because I did not like the gotten results. At some moments, optimistic thoughts came, “Why am I doing all this?”, “Who needs this, except me?”, “So much work, but the return can be negative and most likely it will be so ..”, “Now I really understand what a startup is and when you do everything alone ”, “OMG I still need to think about how to promote it, write an article, maybe drop it all!?!? ”. But nevertheless, I managed to cope with optimistic thoughts and focus simply on the fact that, I just need to do it.

At this moment, the site contains complete documentation for all functions with examples and manuals for a successful configuration of the application.

At this moment the “Add-ons Store” section on the site is under development. In this section, everyone will be able to share their scripts and configs. Currently adding scripts there is done manually, by me. If you have any addons of your own that you would like to share, you can send them to me at addons@infrabot.io, so that I can post them on the site.

The plans for the future are big, but at the moment the roadmap looks like this:

  • The ability to install plugins by simply copying the plugin file to the plugins directory. At the moment, the installation of scripts and configs must be done manually;
  • Ability to create a task to execute any available command from the config at a specified time;
  • Increase of available standard commands;
  • Improving the design and code of the GUI Configurator application;
  • Ability to add a plugin from Addons Store to the configuration file with settings directly from the GUI Configurator;
  • The ability to create a plugin with your own settings right in the GUI Configurator;
  • Finding possible bugs and improving the logic of the main application (code refactoring);
  • Remove the blocking of the main application thread if some script is delayed with a response. At the moment, the bot will not respond to the next command until the previous one has completed.

“What about the problem at the beginning of the article? Did you solve it?” you may ask? Well, at least I (and not only me) can unlock/disable/enable/reset the user’s password on demand using the Telegram bot. One second and problem solved. Of course, over time, the bot “began to understand” more commands. Restarting some critical services when they are stuck (including in Linux), restarting Windows virtual machines (using WinRM) and Linux (using SSH), restarting virtual machines and VmWare physical hosts (using VmWare PowerCLI), restarting some problematic PaloAlto IPSec VPN tunnels, and all different things — in one command being in a crowded bus, or on the sofa!? ;)

Web site: infrabot.io
Address for contact and offers: infrabot@infrabot.io
Address for sending your addons: addons@infrabot.io
infrabot GitHub Repository: infrabot-io/infrabot
GUI Configurator GitHub Repository: infrabot-io/infrabot-gui-tool

Thanks for reading!

--

--

infrabot.io
0 Followers

infrabot.io — Control your infrastructure using Telegram bot