Манипуляция службами в 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
Provide feedback
Saved searches
Use saved searches to filter your results more quickly
Sign up
Appearance settings
Learn how to restart your computer (or any located in the area network) using Python in windows platforms.
Ask a geek how to fix a problem you’ve having with your Windows computer and they’ll likely ask «Have you tried rebooting it?». This seems like a flippant response, but rebooting a computer can actually solve many problems.
Whatever, you may have your own reasons to restart your computer, in this article we’ll show you how to restart it using Python.
Requirements
- pywin32 installed on the machine of execution.
Otherwise, you’ll get the following error on your script :
ImportError: no module named win32api
To install pywin32 on your windows, go to the build repository in Source Forge here. Choose the latest build in the list (till the date of this article the 220), then the list of distributions will be shown :x86 or x64
Install the distribution that works with your version of python and windows platform (x86 or x64).
Restarting
You may have found some solutions using the os module and executing a system shell module, the famous shutdown command :
import os
os.system("shutdown \r")
However, for some windows users this solution doesn’t work correctly.
To prevent any incompatibility, we will work directly with the win32api which allow us to achieve our goal.
As mentioned in the requirements, you need to have the pywin32 installed on your machine to prevent any error at execution.
Now, the following code provides all that you need to be able to restart the pc (and abort it if you need) using python :
# reboot.py
import win32security
import win32api
import sys
import time
from ntsecuritycon import *
def AdjustPrivilege(priv, enable=1):
# Get the process token
flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
htoken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), flags)
# Get the ID for the system shutdown privilege.
idd = win32security.LookupPrivilegeValue(None, priv)
# Now obtain the privilege for this process.
# Create a list of the privileges to be added.
if enable:
newPrivileges = [(idd, SE_PRIVILEGE_ENABLED)]
else:
newPrivileges = [(idd, 0)]
# and make the adjustment
win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges)
def RebootServer(user=None,message='Rebooting', timeout=30, bForce=0, bReboot=1):
AdjustPrivilege(SE_SHUTDOWN_NAME)
try:
win32api.InitiateSystemShutdown(user, message, timeout, bForce, bReboot)
finally:
# Now we remove the privilege we just added.
AdjustPrivilege(SE_SHUTDOWN_NAME, 0)
def AbortReboot():
AdjustPrivilege(SE_SHUTDOWN_NAME)
try:
win32api.AbortSystemShutdown(None)
finally:
AdjustPrivilege(SE_SHUTDOWN_NAME, 0)
The 2 main functions will be RebootServer
and AbortReboot
. The AdjustPrivilege
will grant the required permissions to reboot the system. Note that the RebootServer
function has a timeout of 30 seconds (The computer will be restarted after 30 seconds), change it if you need to.
To restart your machine (or network computers), use the RebootServer function :
# Restart this PC (actual, as first parameter doesn't exist)
RebootServer()
# Restart the network PC named "Terminator" or the direct IP to restart it
RebootServer("Terminator")
# Restart this PC (actual) with all parameters :
# User: None
# Message
# Time in seconds
# Force restart
# restart immediately after shutting down
# Read more about the InitiateSystemShutdown function here : https://msdn.microsoft.com/en-us/library/windows/desktop/aa376873(v=vs.85).aspx
RebootServer(None,"Be careful, the computer will be restarted in 30 seconds",30,0,1)
(Restarting warning and Reboot aborted messages)
You can test with a more dynamic example, executing the following code :
- Restart it in 30 seconds.
- Wait 10 seconds.
- Abort the reboot after 10 seconds.
# Reboot computer
RebootServer()
# Wait 10 seconds
time.sleep(10)
print ('Aborting shutdown')
# Abort shutdown before its execution
AbortReboot()
As the code talks by itself, now keep working in your project, have fun !
Manipulating Windows Services
Credit: Andy McKay
Problem
You need to control Windows services
on any local machine.
Solution
The win32all
package includes a
win32serviceutil
module that is specifically designed to
handle Windows services:
# needs win32all, or ActiveState's ActivePython distribution import win32serviceutil def service_running(service, machine): return win32serviceutil.QueryServiceStatus(service, machine)[1] == 4 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_ _': # Just some test code; change at will! machine = 'cr582427-a' service = 'Zope23' action = 'start' service_info(action, machine, service)
Discussion
Mark Hammond’s win32all
package
makes it child’s play to code Python scripts for a
huge variety of Windows system-administration tasks. For example,
controlling Windows services becomes a snap. In addition to the few
features exemplified in this recipe, which are similar to those
provided by Windows’ own net
command, win32all
also gives you options such as
installing and removing services.
The functions this recipe uses from the
win32serviceutil
module are
StartService
,
StopService
, RestartService
,
and QueryServiceStatus
. Each takes two arguments:
the name of the service and the name of the machine. The first three
perform the start, stop, and restart as requested. The fourth returns
a structured code describing whether and how the given service is
running on the given machine, but in this recipe we exploit only the
fact, encapsulated in the recipe’s
service_running
function, that the second item of the return value is the integer 4
if and only if the service is running successfully.