One day you will think how to turn a script or application into a Windows service. Most likely, the task will not be so trivial - the application will need at least a special interface to receive commands from the system. And since there are requirements and limitations, there are scripts and sweethearts to overcome.
The article will be useful to those who, like me - "the programmer is not real."
Unlike scheduled tasks, the service runs continuously, starts at the start of the PC, and can be controlled by Windows tools. Also, a regularly running script may need data from a previous launch, and it may be useful to get data from external sources - for example, in the case of TCP or Web server.
Personally, over the past five years I have had to create a service three and a half times:
To create a service, you can use adult programming languages like C. But if you don’t want to contact Visual Studio, then get ready-made utilities. There are paid solutions like FireDaemon Pro or AlwaysUp , but we traditionally focus on free ones.
This is a middle-aged mechanism consists of two components: instsrv.exe utilities for installing the service and srvany.exe , a process for running any executable files. Suppose we created a web server on PowerShell using the Polaris module. The script will be extremely simple:
New-PolarisGetRoute -Path '/helloworld' -Scriptblock { $Response.Send('Hello World!') } Start-Polaris -Port 8080 while($true) { Start-Sleep -Milliseconds 10 }
The work of the so-called "server".
Now we will try to turn the script into a service. To do this, download the Windows Resource Kit Tools , where our utilities will be. Let's start by installing an empty service with the command:
instsrv WebServ C:\temp\rktools\srvany.exe
Where WebServ is the name of our new service. If necessary, using the services.msc snap-in, you can specify the user under which the service will run, and allow interaction with the desktop.
Now let's write the path to our script with the help of registry magic. The service settings are in the registry key HKLM \ SYSTEM \ CurrentControlSet \ Services \ WebServ . In it, we need to add a new Parameters section and create an Application string parameter there, indicating in it the path to the executable file. In the case of the PowerShell script, it will look like this:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoProfile -File C:\temp\Polaris\server.ps1
Customized service.
You can run and enjoy.
Running service
However, this method has disadvantages:
Therefore, we turn to the method, partially devoid of these problems.
There is a utility called NSSM - Non-Sucking Service Manager , which can be translated as a non-bad service manager . Unlike the previous one, it is supported by the developer, and the source code is published on the site. In addition to the usual method, installation is also available through the Chocolately package manager.
You can create a service from the usual command line, armed with documentation on the developer's site. But we will use PowerShell. Because we can, of course.
$nssm = (Get-Command ./nssm).Source $serviceName = 'WebServ' $powershell = (Get-Command powershell).Source $scriptPath = 'C:\temp\Polaris\server.ps1' $arguments = '-ExecutionPolicy Bypass -NoProfile -File "{0}"' -f $scriptPath & $nssm install $serviceName $powershell $arguments & $nssm status $serviceName Start-Service $serviceName Get-Service $serviceName
Installation via PowerShell.
For a change, we’ll check the operation of the service not with a browser, but also through PowerShell with the Invoke-RestMethod command.
It really works.
Unlike srvany , this method allows you to restart the application at startup, redirect stdin and stdout, and more. In particular, if you do not want to write commands on the command line, then it is enough to launch the GUI and enter the necessary parameters through a convenient interface.
The GUI is started with the command:
nssm.exe install ServiceName
You can even adjust the priority and use of processor cores.
Indeed, the possibilities are much greater than those of srvany and a number of other analogues . Of the minuses is the lack of control over the whole process.
There is a lack of "tin". Therefore, I turn to the most hardcore method of all tested.
Since I am a longtime lover of this scripting language, I could not pass by a library called _Services_UDF v4 . It is equipped with rich documentation and examples, so under the spoiler I will immediately give the full text of the resulting script.
So, let's try to “wrap” our web service in it:
#NoTrayIcon #RequireAdmin #Region #AutoIt3Wrapper_Version=Beta #AutoIt3Wrapper_UseUpx=n #AutoIt3Wrapper_Compile_Both=y #AutoIt3Wrapper_UseX64=y #EndRegion Dim $MainLog = @ScriptDir & "\test_service.log" #include <services.au3> #include <WindowsConstants.au3> $sServiceName="WebServ" If $cmdline[0] > 0 Then Switch $cmdline[1] Case "install", "-i", "/i" InstallService() Case "remove", "-u", "/u", "uninstall" RemoveService() Case Else ConsoleWrite(" - - - Help - - - " & @CRLF) ConsoleWrite("params : " & @CRLF) ConsoleWrite(" -i : install service" & @CRLF) ConsoleWrite(" -u : remove service" & @CRLF) ConsoleWrite(" - - - - - - - - " & @CRLF) Exit EndSwitch Else _Service_init($sServiceName) Exit EndIf Func _main($iArg, $sArgs) If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0) Exit EndIf $bServiceRunning = True $PID=Run("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoProfile -File C:\temp\Polaris\server.ps1") While $bServiceRunning _sleep(1000) WEnd ProcessClose($PID) _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000) DllCallbackFree($tServiceMain) DllCallbackFree($tServiceCtrl) _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0) DllClose($hAdvapi32_DLL) DllClose($hKernel32_DLL) EndFunc Func _Sleep($delay) Local $result = DllCall($hKernel32_DLL, "none", "Sleep", "dword", $delay) EndFunc Func InstallService() #RequireAdmin Local $bDebug = True If $cmdline[0] > 1 Then $sServiceName = $cmdline[2] EndIf If $bDebug Then ConsoleWrite("InstallService("&$sServiceName &"): Installing service, please wait") _Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_SEVERE, '"' & @ScriptFullPath & '"');,"",False,"","NT AUTHORITY\NetworkService") If @error Then Msgbox("","","InstallService(): Problem installing service, Error number is " & @error & @CRLF & " message : " & _WinAPI_GetLastErrorMessage()) Else If $bDebug Then ConsoleWrite("InstallService(): Installation of service successful") EndIf Exit EndFunc Func RemoveService() _Service_Stop($sServiceName) _Service_Delete($sServiceName) If Not @error Then EndIf Exit EndFunc Func _exit() _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0); EndFunc Func StopTimer() _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, $iServiceCounter) $iServiceCounter += -100 EndFunc Func _Stopping() _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 3000) EndFunc
I will analyze in more detail the moment you start the application It starts after the operation $ bServiceRunning = True and turns into a seemingly infinite loop. In fact, this process will be interrupted as soon as the service receives a signal for termination - be it to log out or stop manually.
Since the script program is external (powershell.exe), after exiting the loop we need to finish its work using ProcessClose .
To do this, the script must be compiled into .exe , and then install the service by running exe with the -i key .
It is working!
Of course, this method is not the most convenient, and all additional features will have to be implemented independently, whether it be a restart of the application in case of failure or log rotation. But then he gives full control over what is happening. Yes, and in the end you can do much more - from the notice in the Telegram about the failure of the service to IPC-interaction with other programs. And in addition - in the scripting language, without installing and learning Visual Studio.
Tell me, did you have to turn scripts and applications into services?
Source: https://habr.com/ru/post/421019/
All Articles