0

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:

  1. Script
  2. Python pip installed packages
  3. Install from command line

Possible?

rubmz
  • 1,947
  • 5
  • 27
  • 49
  • 1
    the win32 modules can be used for this and can be written in such a way that you can run the script to install/enable/disable/start/stop the service, however note that if you have any code in your script that attempts to write to the console the script will stop with a traceback. also the file srvany.exe (available for download from microsoft) can be used to run any executable as a service (with arguments) however it doesn't play as nice with start/stop messages from what i remember – James Kent Oct 25 '17 at 12:34
  • that's the thing. I didn't find how to pip install the win32 modules. It seems to be shipped with ActiveState python .. Is it available for python.org python? – rubmz Oct 25 '17 at 12:43
  • ok found and installed it using "pip3 install pypiwin32" bypassing issues related to my dual python2/3 installations. any link to windows service code that uses win32 modules? – rubmz Oct 25 '17 at 12:46
  • 1
    there are a few: https://stackoverflow.com/questions/4499859/python-win32-service https://gist.github.com/drmalex07/10554232 https://stackoverflow.com/questions/263296/creating-a-python-win32-service – James Kent Oct 25 '17 at 12:56

1 Answers1

1

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)
James Kent
  • 5,763
  • 26
  • 50
rubmz
  • 1,947
  • 5
  • 27
  • 49
  • 1
    as an added bonus, you could import sys and overwrite sys.stderr and sys.stdout to point at `servicemanager.LogMsg` functions( or wrappers) so any output gets logged to the windows event log, note that the replacements will need to be file like objects – James Kent Oct 25 '17 at 13:01