I've checked at least a couple of dozen of similar cases to mine and still haven't come up with a solution, I hope someone can shed some light, there's gotta be something I'm missing here.
I'm using Python3.6 to make a Windows service, the service has to run a .exe file if it's not running. Here's the .py:
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import psutil
import subprocess
import os, sys, string, time
import servicemanager
class SLAAgent (win32serviceutil.ServiceFramework):
_svc_name_ = "SLAAgent"
_svc_display_name_ = "SLAAgent"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
self.isAlive = True
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
self.isAlive = False
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
self._logger.info("Service Is Starting")
main(self)
def main(self):
while self.isAlive:
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
servicemanager.LogInfoMsg("SLAAService has stopped") #For Event Log
break
else:
try:
s = subprocess.check_output('tasklist', shell=True)
if "SLA_Client.exe" in s:
pass
else:
pass
#execfile("SLA_Client.exe") #Execute the script
except:
pass
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(SLAAgent)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(SLAAgent)
I've installed the pywin32 package, added those to the PATH since it was suggested in several solutions, and also copied the .dll from pywin32_system32 to win32
Environment variables
Event Viewer Error
The Event Viewer prints this error every time I run it be it python service.py, or python service.py start, console also prints this:
python SLA_Agent.py
Traceback (most recent call last):
File "SLA_Agent.py", line 56, in <module>
servicemanager.StartServiceCtrlDispatcher()
pywintypes.error: (1063, 'StartServiceCtrlDispatcher', 'The service process
could not connect to the service controller.')
When trying to start the service from the Services tool this is the error that pop ups. I've seen the other error too, the oneabout the service not responding in time.
I've tried compiling it with pyinstaller and nuitka, the errors are the same. I'm unsure as to how to proceed, I've changed the code to fit examples and solutions I've found using google and SO, and have gained little understanding of the hows and whys.
If anyone has faced these issues before, I'd really appreciate the input, other answers haven't helped me so far.
Late edit: fixed the code indentation
This ended up working for me, other than the difference in the code I didn't really do anything special, after a few tries I got to compile with pyinstaller and run service.exe install without issues. There are some extra logging lines that people might not need, but they came in handy when debugging and testing.
Thanks a lot to the everyone who left comments, they were extremely helpful and couldn't have done it without you <3
import win32service, win32serviceutil, win32api, win32con, win32event, win32evtlogutil
import psutil
import subprocess
import os, sys, string, time, socket, signal
import servicemanager
class Service (win32serviceutil.ServiceFramework):
_svc_name_ = "Service"
_svc_display_name_ = "Service"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self, *args)
self.log('Service Initialized.')
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def log(self, msg):
servicemanager.LogInfoMsg(str(msg))
def sleep(self, sec):
win32api.Sleep(sec*1000, True)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.stop()
self.log('Service has stopped.')
win32event.SetEvent(self.stop_event)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
try:
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.log('Service is starting.')
self.main()
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
except Exception as e:
s = str(e);
self.log('Exception :'+s)
self.SvcStop()
def stop(self):
self.runflag=False
try:
#logic
except Exception as e:
self.log(str(e))
def main(self):
self.runflag=True
while self.runflag:
rc = win32event.WaitForSingleObject(self.stop_event, 24*60*60)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
self.log("Service has stopped")
break
else:
try:
#logic
except Exception as e:
self.log(str(e))
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(Service)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(Service)
Related
I have created a test service file in pyhton:
import datetime
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
def writetofile():
DIR = "D:\prog\log.txt"
while True:
with open(DIR, 'a+') as file:
file.write(str(datetime.now()))
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TESTEST"
_svc_display_name_ = "TESTEST"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
writetofile()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
I've also installed it but when I want to start in win services it stops every time with 1053 error.
I have tried to overwrite the register file (ServicesPipeTimeout) not worked. I set it up 180000 and nothing. My program ran for a while then stopped again.
I've installed everthing in cmd as admin (pip install pywin32), not worked.
And I've installed the service too in cmd (python main.py install) and I see it, but thats all. I cant start it, cant delete it cant do anything with it.
I know this question was asked so many times. I read all those questions but i didn't find out my problem's solution. My issue is that i have created below window service with help of this link. How do you run a Python script as a service in Windows?
and I am running this service from command prompt.
Here is my python script that i need to run as a service.
import traceback
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import getpass
import json
import pathlib
import urllib.request
import sys
from time import time , sleep
import uuid
from urllib.request import urlopen , Request
from urllib.parse import urlencode , quote_plus
import subprocess
import threading
import requests
from requests.sessions import session
import os
import cgitb
import logging
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "PCSIGN"
_svc_display_name_ = "PC SIGN"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None,0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop( self ):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun( self ):
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
def main( ):
while True:
file = open ( 'geek.txt' , 'a+' )
file.write("hello world")
file.close()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(PythonService)
PythonService.main()
As you can see in the main function there is an infinite loop in which I am opening a file and writing hello world in it.
I install & start my service from command prompt.
C:\wamp64\www\project\python\New folder>start /min python testing.py install
C:\wamp64\www\project\python\New folder>start /min python testing.py start
after that service installed and start working properly and another window appear.
It also makes an entry successfully in Services.
But the issue here is when i close the above window of python console it stop writing hello world in the file don't know why kindly how can i make it persistent so that whenever system restarted my script start working automatically and start writing hello world in the file
Just a few days back I have successfully sorted out my issue I just made some changes to my code and it started working properly. I am only posting these answers for someone like me who got this issue in the future he can easily sort it out.
This is the new code:
def WriteToFile():
while True:
file = open ( "C:\\file.txt" , "w" )
now = datetime.now()
now = now.strftime("%B %d, %y %H:%M:%S")
file.write(now)
class Pythonservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'PC-Service'
_svc_display_name_ = 'PC-Service'
_svc_description_ = 'Freindly Service'
#classmethod
def parse_command_line(cls):
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.stop()
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.start()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def start(self):
self.isrunning = True
def stop(self):
self.isrunning = False
def main(self):
WriteToFile()
if __name__ == '__main__':
Pythonservice.parse_command_line()
After these changes, I opened up a command prompt as administrator and type this command to install my service.
C:\wamp64\www\project\python\New folder>python testing.py install
I got the success message. After successful installation, I started my service using this command
C:\wamp64\www\project\python\New folder>python testing.py start
and service started successfully I confirmed from service manager as well whether my service is running or not and it was running after restarting my pc service was still in running state.
Using Python 3.7, Windows 10 Pro, Pywin32
I have a test script that starts a service and pushes some basic lines into a log file as the different commands are issued. Code is as follows:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import logging
class AppServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "New Test Service"
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Class opened')
def __init__(self, args):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Init')
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Stop')
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Run')
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def main(self):
print("running")
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Main')
if __name__ == '__main__':
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Calling Handle Command Line')
win32serviceutil.HandleCommandLine(AppServerSvc)
I have gone through the basic trouble shooting with this, and the service is installing, starting, restarting and being removed without any errors. However I am expecting the log file to receive basic output to show the functions are being hit, and it isn't.
The calls I am making at the admin command prompt:
C:\PythonScripts\SearchServer>python servicetest.py install
Installing service TestService
Service installed
C:\PythonScripts\SearchServer>python servicetest.py start
Starting service TestService
C:\PythonScripts\SearchServer>python servicetest.py restart
Restarting service TestService
C:\PythonScripts\SearchServer>python servicetest.py remove
Removing service TestService
Service removed
C:\PythonScripts\SearchServer>
Contents of log file:
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
As you can see the service is being hit every time a command is issued, however I'd expect the internal functions to be called too. Being new to both services and Python I'm wondering if I've missed anything? I'm assuming the function names are predefined and don't need me to set up delegation to access them. Its not something I've seen in any of the questions I've come across.
I am of course assuming that these functions are supposed to be hit and they are being hit and are capable of creating logs?
Any help gratefully received.
There are a few problems with the code:
logging.basicConfig() should be called only once, if called again it won't have any effect.
Class definition will be called first in your code, even before block if __name__ == '__main__': because of natural flow of code. Due to this, whatever you set in logging.basicConfig() in class definition will become final for whole script. It is not an ideal place for this setting, so should be moved elsewhere (at the top, outside the class preferably).
filename parameter passed in the logging.basicConfig should be the absolute file path, because once service starts running, its current path won't be the same as the script, so logging won't be able to find out the log file. (current working directory for the service would become something like C:\Python37\lib\site-packages\win32).
(Optional): Try not to use root logging config at all, it's better to have an instance of logger for your own use.
After all these changes, the script will look like this:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import logging.handlers
log_file_path = "" # mention full path here
mylogger = logging.getLogger("TestLogger")
mylogger.setLevel(logging.INFO)
handler = logging.handlers.RotatingFileHandler(log_file_path)
mylogger.addHandler(handler)
class AppServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "New Test Service"
mylogger.info('Class opened')
def __init__(self, args):
mylogger.info('Init')
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
mylogger.info('Stop')
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
mylogger.info('Run')
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def main(self):
print("running")
mylogger.info('Main')
if __name__ == '__main__':
mylogger.info('Calling Handle Command Line')
win32serviceutil.HandleCommandLine(AppServerSvc)
Output:
Class opened
Init
Run
Main
Class opened
Calling Handle Command Line
I've had unexplainable problems with python logging, I solved them by setting up the logging right at the beginning of the program:
import logging
logging.basicConfig(filename='convert_st.log', level=logging.INFO)
logging.info('Started')
import all_other_packages
import...
...
def main:
# main comes here
...
if __name__ == '__main__':
main()
Is it possible to write a windows 10 service as a python script without involving 3rd party software, such as nssm or ActiveState python (not saying that either is a bad solution).
Only:
Script
Python pip installed packages
Install from command line
Possible?
So to use this example I found the simplest way to implement a self sufficient python script without any 3rd party compilers/services:
Install win32 module package:
pip3 install pypiwin32
Code:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import sys
class TestService(win32serviceutil.ServiceFramework):
_svc_name_ = 'TestService'
_svc_display_name_ = 'TestService'
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
self.main()
def main(self):
f = open('D:\\test.txt', 'a')
rc = None
while rc != win32event.WAIT_OBJECT_0:
f.write('Test Service \n')
f.flush()
# block for 24*60*60 seconds and wait for a stop event
# it is used for a one-day loop
rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
f.write('shut down \n')
f.close()
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(TestService)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(TestService)
Question
I am attempting to start a Python script as a Windows service using pywin32. I can properly install and remove the service, but while installed, its state never changes from "stopped." How can I fix my code so that the service actually runs?
Code
#!/bin/python
import winerror
import win32event
import win32service
import win32serviceutil
SVC_RUN = 1
SVC_REMOVE = 2
class TMP_Service(win32serviceutil.ServiceFramework):
_svc_name_ = "tmp_svc_name"
_svc_display_name_ = "tmp svc disp name"
_svc_reg_class = "tmp.reg_class"
_svc_description_ = "tmp description"
def __init__(self, dut_name):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.reportServiceStatus(win32service.SERVICE_STOP_PENDING)
# I will call reactor.callFromThread(reactor.stop) here to stop the
# FTP and SCP listeners
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# This infinite loop simulates future behavior of my service. It will
# run a Twisted reactor to handle FTP and TCP network connections.
while True:
pass
win32event.WaitforSingleObject(self.hWaitStop, win32event.INFINITE)
def install_svc():
try:
win32serviceutil.InstallService(
TMP_Service._svc_reg_class,
TMP_Service._svc_name_,
TMP_Service._svc_display_name_,
startType=win32service.SERVICE_AUTO_START)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_EXISTS:
pass # ignore install error if service is already installed
else:
raise
def handle_service(svc):
if svc == SVC_RUN:
try:
win32serviceutil.StartService(TMP_Service._svc_name_)
except win32service.error as e:
if ((e[0] == winerror.ERROR_SERVICE_ALREADY_RUNNING) or
(e[0] == winerror.ERROR_ALREADY_RUNNING_LKG)):
pass # ignore failed start if the service is already running
elif e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
# if the service is not installed, install it and try again
install_svc()
win32serviceutil.StartService(TMP_Service._svc_name_)
else:
# reraise any other start expection
raise
status = win32serviceutil.QueryServiceStatus(TMP_Service._svc_name_)
print("Service status: {}".format(status[1]))
else:
try:
win32serviceutil.RemoveService(TMP_Service._svc_name_)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
pass # ignore failed removal if service is not installed
else:
# reraise any other remove exception
raise
if __name__ == "__main__":
handle_service(SVC_RUN)
Other Details
When I look at the system event logs, I see this error:
Python could not import the service's module
ImportError: No module named tmp
%2: %3
The timestamp for these messages match the times that I tried to run this script.
I have seen this question: Can't start Windows service written in Python (win32serviceutil). Based on the advice there, I have made my code match the suggestion in the top answer there, and made sure that C:\Python27 is in my system path. Neither suggestion made a difference.
The status that is printed is always "2". According to MSDN, this is SERVICE_START_PENDING, which means the service should be starting.
Updated Details
If I change the value of the _svc_reg_class_ attribute to "tmp2.reg_class", then the name of the missing module, as reported in the Windows event log, changes to "tmp2", so this error is related to the _svc_reg_class_ attribute.
In reply to a comment below: I don't think I can capture the full traceback, because my service class is instantiated and used in the pywin32 library code. The offending import doesn't happen anywhere in my code, so there's nothing for me to wrap in a try/except block.
Change the _svc_reg_class = "tmp.reg_class" as shown below.
try:
module_path = modules[TMP_Service.__module__].__file__
except AttributeError:
# maybe py2exe went by
from sys import executable
module_path = executable
module_file = splitext(abspath(module_path))[0]
TMP_Service._svc_reg_class = '%s.%s' % (module_file, TMP_Service.__name__)
Below is the complete modified version of your original code.
#!/bin/python
import winerror
import win32event
import win32service
import win32serviceutil
from sys import modules
from os.path import splitext, abspath
SVC_RUN = 1
SVC_REMOVE = 2
class TMP_Service(win32serviceutil.ServiceFramework):
_svc_name_ = "tmp_svc_name"
_svc_display_name_ = "tmp svc disp name"
_svc_reg_class = "tmp.reg_class"
_svc_description_ = "tmp description"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.Stop = True
# I will call reactor.callFromThread(reactor.stop) here to stop the
# FTP and SCP listeners
win32event.SetEvent(self.hWaitStop)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
self.Stop = False
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# This infinite loop simulates future behavior of my service. It will
# run a Twisted reactor to handle FTP and TCP network connections.
while self.Stop == False:
pass
win32event.WaitforSingleObject(self.hWaitStop, win32event.INFINITE)
def install_svc():
try:
module_path = modules[TMP_Service.__module__].__file__
except AttributeError:
# maybe py2exe went by
from sys import executable
module_path = executable
module_file = splitext(abspath(module_path))[0]
TMP_Service._svc_reg_class = '%s.%s' % (module_file, TMP_Service.__name__)
try:
win32serviceutil.InstallService(
TMP_Service._svc_reg_class,
TMP_Service._svc_name_,
TMP_Service._svc_display_name_,
startType=win32service.SERVICE_AUTO_START)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_EXISTS:
pass # ignore install error if service is already installed
else:
raise
def handle_service(svc):
if svc == SVC_RUN:
try:
win32serviceutil.StartService(TMP_Service._svc_name_)
except win32service.error as e:
if ((e[0] == winerror.ERROR_SERVICE_ALREADY_RUNNING) or
(e[0] == winerror.ERROR_ALREADY_RUNNING_LKG)):
pass # ignore failed start if the service is already running
elif e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
# if the service is not installed, install it and try again
install_svc()
win32serviceutil.StartService(TMP_Service._svc_name_)
else:
# reraise any other start expection
raise
status = win32serviceutil.QueryServiceStatus(TMP_Service._svc_name_)
print("Service status: {}".format(status[1]))
else:
try:
win32serviceutil.RemoveService(TMP_Service._svc_name_)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
pass # ignore failed removal if service is not installed
else:
# reraise any other remove exception
raise
if __name__ == "__main__":
handle_service(SVC_RUN)
Reference: here