Манипуляция службами в Windows c помощью Питона

Start  / Stop windows services with Python

При работе в Windows приходится использовать некоторые службы, которые не нужны постоянно. Особенно, когда эта машина локальная, не серверная.

Например, sphinxsearh, MySQL, PostgreSQL, очереди сообщений и проч. нужны либо в момент работы над проектом, их использующим, либо при изучении их разработчиком.

Бывают и другие примеры не нужных постоянно служб.

Обычно пользователи Виндоус могут остановить службу через Панель Управления (Администрирование - Службы) или, кто попродвинутей, через командную строку. Оба этих способа подразумевают трату времени или на поиск службы в списке, или на узнавание имени службы.

Хорошим способом будет запуск/останов/рестарт требуемых служб из Питон.

Для этого нам понадобится пакет pywin32 и простой скрипт на питоне.

Вначале автор нашел нечто готовое для задачи в PyPi репозитории. Возможно, вам подойдет:

Отсюда скачивайте последнюю версию pywin32 (там она вполне по x64 есть, не смущайтесь названием) под требуемую версию Питона, а отсюда  ( ну или с Гитхаба) устанавливаем PyWinServiceManager.

Для проверки работоспособности можно сваять простенький скрипт:

from pywinservicemanager.WindowsServiceConfigurationManager import ServiceExists

serviceName = 'TestService'
serviceExists = ServiceExists(serviceName)
print serviceExists

Сходу у меня он дал ошибку, решение которой описано тут:
http://stackoverflow.com/questions/22490233/win32com-import-error-python-3-4
(нужно выполнить из Питона скрипт [PythonDir]\Scripts\pywin32_postinstall.py)

После исправления ошибки все запускается, однако, похоже, PyWinServiceManager писан для второго Питона. Или не для второго, но ошибок многовато и править их лень. Хотя сама библиотека задумана с размахом и может подойти для задач типа "запуск Python скрипта как windows сервис".

Мы же поищем что-то попроще.

Что-то попроще описано по ссылкам:
http://code.activestate.com/recipes/59872-manipulating-windows-services/
https://www.safaribooksonline.com/library/view/python-cookbook/0596001673/ch07s13.html

Хинт: поскольку имеем дело с локальной машиной, в выозвах достаточно указать 
machine = None   или вообще переписать без использования этого параметра (по сети не тестировал, но идея выглядит интересной)

т.е. указываем
machine = None
service = 'postgresql-x64-9.5'
action = 'restart'
и проверяем работоспособность.

Тут все хорошо, кроме того, что служба стартует не мгновенно, точнее, не так быстро, как ее статус опрашивается. Как следствие - при запуске и перезапуске (start / restart)  вы будете получать сообщение, что запуск невозможен.

Исправим это простой функции проверки статуса.

Итоговый код:
import win32serviceutil

def service_running(service, machine):
    status = (win32serviceutil.QueryServiceStatus(service)[1] == 4)
    if not status:
        import time
        time.sleep(3)
        status = (win32serviceutil.QueryServiceStatus(service)[1] == 4)
    return status



def service_info(action, machine, service):
    running = service_running(service, machine)
    servnam = 'service (%s) on machine(%s)'%(service, machine)
    action = action.lower(  )
    if action == 'stop':
        if not running:
            print ("Can't stop, %s not running"%servnam)
            return 0
        win32serviceutil.StopService(service, machine)
        running = service_running(service, machine)
        if running:
            print ("Can't stop %s (???)"%servnam)
            return 0
        print ('%s stopped successfully' % servnam)
    elif action == 'start':
        if running:
            print ("Can't start, %s already running"%servnam)
            return 0
        win32serviceutil.StartService(service, machine)
        running = service_running(service, machine)
        if not running:
            print ("Can't start %s (???)"%servnam)
            return 0
        print ('%s started successfully' % servnam)
    elif action == 'restart':
        if not running:
            print ("Can't restart, %s not running"%servnam)
            return 0
        win32serviceutil.RestartService(service, machine)
        running = service_running(service, machine)
        if not running:
            print ("Can't restart %s (???)"%servnam)
            return 0
        print ('%s restarted successfully' % servnam)
    elif action == 'status':
        if running:
            print ("%s is running" % servnam)
        else:
            print ("%s is not running" % servnam)
    else:
        print ("Unknown action (%s) requested on %s"%(action, servnam))

if __name__ == '__main__':
    machine = None
    service = 'postgresql-x64-9.5'
    action = 'restart'
    service_info(action, machine, service)

теперь, зная список служб, можно держать их в отдельном файле и стартовать/останавливать группой применительно к конкретной задаче.

P.S. конечно же, права на запуск должны быть Администратора. Т.е. или запускайте PyCharm c админ правами или классическое CMD c Run As Administrator опцией.

еще сссылки по теме (не проверялись):
http://code.activestate.com/recipes/135700-win32-service-administration/  
https://github.com/SublimeText/Pywin32/blob/master/lib/x32/win32/lib/win32serviceutil.py

Комментарии