
Une fois que vous avez réfléchi à la façon de transformer un script ou une application en service Windows. Très probablement, la tâche ne sera pas si triviale - au moins l'application aura besoin d'une interface spéciale pour recevoir les commandes du système. Et puisqu'il y a des exigences et des limitations, c'est-à-dire des scripts et des béquilles, agréables à cœur, à surmonter.
L'article sera utile à ceux qui, comme moi, ne sont "pas un vrai programmeur".
Pourquoi ai-je besoin d'un service s'il y a des tâches planifiées
Contrairement aux tâches assignées, le service fonctionne en permanence, démarre au démarrage du PC et peut être contrôlé par les outils Windows. En outre, un script lancé régulièrement peut nécessiter des données d'un lancement précédent et il peut être utile d'obtenir des données de sources externes - par exemple, dans le cas de TCP ou d'un serveur Web.
Personnellement, au cours des cinq dernières années, j'ai dû créer un service trois fois et demi:
- Il était nécessaire de créer un service sur fail2ban pour Windows 2003. qui fonctionnait avec les journaux FileZilla et Apache, et s'il était suspecté de force brute, il bloquait IP en utilisant les outils Windows standard - ipsec.
- Un analogue du serveur telnet pour les versions domestiques de Windows. Il a fallu exécuter des commandes sur des postes de travail distants qui exécutaient Windows 7 Home. En fait, la deuxième tentative de jouer des services.
- Lecteur de musique pour la salle des marchés sous Windows. La tâche sur les savoirs traditionnels pourrait être résolue à l'aide de mpd et d'un pack de scripts, mais j'ai décidé - si nous devions créer des scripts, alors pourquoi ne pas «empiler» le joueur moi-même. Basé sur la bibliothèque BASS.dll .
- Lors du choix d'un serveur Web prenant en charge le téléchargement de fichiers sous Windows, une option était HFS . Il ne peut pas travailler seul, il a donc dû le «pousser» au service. En conséquence, je n'ai pas aimé la solution et j'ai juste installé le thème Apaxy sur le serveur Web Apache.
Pour créer un service, vous pouvez utiliser des langages de programmation pour adultes comme C. Mais si vous ne souhaitez pas communiquer avec Visual Studio, utilisez des utilitaires prêts à l'emploi. Il existe des solutions payantes comme FireDaemon Pro ou AlwaysUp , mais nous nous concentrons traditionnellement sur les solutions gratuites.
La première façon. De Microsoft
Ce mécanisme déjà ancien se compose de deux composants: l'utilitaire instsrv.exe pour installer le service et srvany.exe , le processus de lancement des fichiers exécutables. Supposons que nous ayons créé un serveur Web sur PowerShell à l'aide du module Polaris . Le script sera extrêmement simple:
New-PolarisGetRoute -Path '/helloworld' -Scriptblock { $Response.Send('Hello World!') } Start-Polaris -Port 8080 while($true) { Start-Sleep -Milliseconds 10 }

Le travail du soi-disant "serveur".
Essayons maintenant de transformer le script en service. Pour ce faire, téléchargez les outils du Kit de ressources Windows , où seront nos utilitaires. Commençons par installer un service vide avec la commande:
instsrv WebServ C:\temp\rktools\srvany.exe
Où WebServ est le nom de notre nouveau service. Si nécessaire, via le composant logiciel enfichable services.msc , vous pouvez spécifier l'utilisateur sous lequel le service sera lancé et autoriser l'interaction avec le bureau.
Écrivons maintenant le chemin de notre script en utilisant la magie du registre. Les paramètres de service se trouvent dans la clé de registre HKLM \ SYSTEM \ CurrentControlSet \ Services \ WebServ . Dans ce document, nous devons ajouter une nouvelle section Paramètres et y créer un paramètre de chaîne Application , en indiquant le chemin d'accès au fichier exécutable. Dans le cas d'un script PowerShell, il ressemblera à ceci:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoProfile -File C:\temp\Polaris\server.ps1

Service personnalisé.
Vous pouvez courir et profiter.

Service de travail.
Cependant, cette méthode présente des inconvénients:
- Les utilitaires sont anciens, développés avant l'invention de PowerShell, UAC et d'autres choses.
- Srvany ne contrôle pas le fonctionnement de l'application. Même en cas d'erreur, le service continuera son travail comme si de rien n'était.
- Devra s'ajuster et fouiller dans le registre. Vous souvenez-vous que creuser dans le registre n'est pas sûr?
Par conséquent, nous nous tournons vers une méthode partiellement dépourvue de ces problèmes.
La deuxième façon, presque un adulte
Il existe un utilitaire appelé NSSM - Non-Sucking Service Manager , qui peut être traduit par un non-bad service manager . Contrairement au précédent, il est pris en charge par le développeur et le code source est publié sur le site. En plus de la méthode habituelle, l'installation est également disponible via le gestionnaire de paquets Chocolately .
Vous pouvez créer un service à partir de la ligne de commande habituelle, armé de documentation sur le site du développeur. Mais nous utiliserons PowerShell. Parce que nous pouvons, bien sûr.
$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.
Pour une modification, nous vérifierons le fonctionnement du service non pas avec le navigateur, mais également via PowerShell à l'aide de la commande Invoke-RestMethod.

Et ça marche vraiment.
Contrairement à srvany , cette méthode vous permet de redémarrer l'application au démarrage, de rediriger stdin et stdout et bien plus encore. En particulier, si vous ne souhaitez pas écrire de commandes sur la ligne de commande, exécutez simplement l'interface graphique et entrez les paramètres nécessaires via une interface pratique.
L'interface graphique est démarrée avec la commande:
nssm.exe install ServiceName

Vous pouvez même configurer la priorité et l'utilisation des cœurs de processeur.
En effet, il existe beaucoup plus d'opportunités que la srvany et un certain nombre d'autres analogues . Parmi les inconvénients, un contrôle insuffisant sur l'ensemble du processus est frappant.
Il y a un manque d'étain. Par conséquent, je vais passer à la méthode la plus hardcore de tous les tests.
La troisième voie. AutoIT
Comme je suis un amoureux de longue date de ce langage de script, je n'ai pas pu dépasser la bibliothèque appelée _Services_UDF v4 . Il est équipé d'une riche documentation et d'exemples, donc sous le spoiler je donnerai immédiatement le texte complet du script résultant.
Liste des scriptsEssayons donc d’envelopper notre service Web:
#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
J'analyserai plus en détail le moment du lancement de l'application. Il démarre après l'opération $ bServiceRunning = True et se transforme en une boucle apparemment infinie. En fait, ce processus sera interrompu dès que le service recevra un signal d'achèvement - qu'il se déconnecte ou s'arrête manuellement.
Étant donné que le programme pour le script est externe (powershell.exe), après avoir quitté la boucle, nous devons terminer son travail en utilisant ProcessClose .
Pour ce faire, le script doit être compilé en .exe , puis installer le service en exécutant exe avec le commutateur -i.

Ça marche!
Bien sûr, cette méthode n'est pas la plus pratique et toutes les fonctionnalités supplémentaires devront être implémentées indépendamment, qu'il s'agisse de redémarrer l'application en cas d'échec ou de rotation du journal. Mais il donne un contrôle total sur ce qui se passe. Et à la fin, vous pouvez faire beaucoup plus - de notifier Telegram en cas d'échec de service à l'interaction IPC avec d'autres programmes. Et en plus - dans un langage de script, sans installer ni apprendre Visual Studio.
Dites-nous, avez-vous dû transformer des scripts et des applications en services?