0

I already have a python script that runs continuously. It's very similar to this: https://github.com/walchko/Black-Hat-Python/blob/master/BHP-Code/Chapter10/file_monitor.py

Similar as in, when running it as a script, it opens a CMD which shows some data when stuff happens - it's not user-interactible so it's not mandatory that it shows (just in case someone wishes to point out that windows services can't have interfaces)

I've tried to convert it to a service. It starts for a fraction of a second and then automatically stops. When trying to start it via services.msc (instead of python script.py start) it doesn't start at all, Windows error says something like: "The service on local computer started and then stopped" which sounds just about what's happening if I try to start it with the argument.

I've tried modifying the script to allow it to run as a service - adding the skeleton I found here: Is it possible to run a Python script as a service in Windows? If possible, how?

I've also tried just getting the skeleton script above and just trying to make it run the other script with examples from here: What is the best way to call a Python script from another Python script?

Does anyone have any idea what the best course of action would be to run that script above as a service?

Thanks!

1 Answers1

2

Edited

"...services can be automatically started when the computer boots, can be paused and restarted, and do not show any user interface." ~Introduction to Windows Service Applications

Windows services require the implementation to make a specific interface available:

So you will need to access the Windows API through Python:

You can see the example code, from Python Programming On Win32, within which Chapter 18 Services (ch18_services folder) contains a sample (SmallestService.py) demonstrating the smallest possible service written in Python:

# SmallestService.py
# 
# A sample demonstrating the smallest possible service written in Python.

import win32serviceutil
import win32service
import win32event

class SmallestPythonService(win32serviceutil.ServiceFramework):
    _svc_name_ = "SmallestPythonService"
    _svc_display_name_ = "The smallest possible Python Service"
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        # Create an event which we will use to wait on.
        # The "service stop" request will set this event.
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

    def SvcStop(self):
        # Before we do anything, tell the SCM we are starting the stop process.
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        # And set my event.
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        # We do nothing other than wait to be stopped!
        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)

if __name__=='__main__':
    win32serviceutil.HandleCommandLine(SmallestPythonService)

You may need to download the appropriate pywin32 wheel for your particular python environment here: http://www.lfd.uci.edu/~gohlke/pythonlibs/#pywin32

And install it (system wide, from admin cmd prompt):

> cd \program files\python<ver>\scripts
> pip install \path\to\pywin32‑221‑cp<ver>‑cp<ver>m‑win_<arch>.whl

Or install it (per user, from regular cmd prompt):

> cd \program files\python<ver>\scripts
> pip install --user \path\to\pywin32‑221‑cp<ver>‑cp<ver>m‑win_<arch>.whl

Be sure to replace the occurences of <ver> and <arch> appropriately.

veganaiZe
  • 539
  • 5
  • 13
  • Thanks for the info! And if I'd want to have the service run my other script, where and how should my code go and look like? Should I just put something like subprocess.call("script.py") under the win32serviceutil.HandleCommandLine(SmallestPythonService) ? – Claudiu Dragan Jul 04 '17 at 09:05
  • Try starting your script from inside the SvcDoRun() function. – veganaiZe Jul 04 '17 at 17:21
  • 1
    I accepted your answer as it sort-of worked. The service is installing and the script starts running in the same CMD I used the "python script.py install" command on. But it's not started, and it's only working as long as I leave that CMD window open. I'm getting this: "The instance's SvcRun() method failed – Claudiu Dragan Jul 05 '17 at 19:31
  • You need to also adjust the code inside of `__init__` and `SvcStop()` appropriately; Remember that this is _minimal_ so you may need to add additional functions or more code inside of the existing functions. – veganaiZe Jul 05 '17 at 22:27