ActiveState Powered by ActiveState

Recipe 115875: Controlling Windows Services


The WService Class is used for controlling WinNT, Win2k & WinXP like services. Just pass the name of the service you wish to control to the class instance and go from there.

Python
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
"""
Module for manipulating WinNT, Win2k & WinXP services. 
Requires the win32all package which can be retrieved 
from => http://starship.python.net/crew/mhammond
"""
from sys import exit
import time, win32api, win32con, win32service
wa, wc, ws = win32api, win32con, win32service

class WService:
    """
    The WService Class is used for controlling WinNT, Win2k & WinXP like
    services. Just pass the name of the service you wish to control to the
    class instance and go from there. For example, if you want to control 
    the Workstation service try this:
     
        import WService
        workstation = WService.WService("Workstation")
        workstation.start()
        workstation.fetchstatus("running", 10)
        workstation.stop()
        workstation.fetchstatus("stopped")

    Creating an instance of the WService class is done by passing the name of
    the service as it appears in the Management Console or the short name as
    it appears in the registry. Mixed case is ok.
        cvs = WService.WService("CVS NT Service 1.11.1.2 (Build 41)")        
            or
        cvs = WService.WService("cvs")

    If needing remote service control try this:
        cvs = WService.WService("cvs", r"\\CVS_SERVER")
            or
        cvs = WService.WService("cvs", "\\\\CVS_SERVER")  
        
    The WService Class supports these methods:
        
        start:          Starts service.
        stop:           Stops service.
        restart:        Stops and restarts service.
        pause:          Pauses service (Only if service supports feature).
        resume:         Resumes service that has been paused.
        status:         Queries current status of service.
        fetchstatus:    Continually queries service until requested status(STARTING, RUNNING,
                            STOPPING & STOPPED) is met or timeout value(in seconds) reached.
                            Default timeout value is infinite.                              
        infotype:       Queries service for process type. (Single, shared and/or 
                            interactive process)
        infoctrl:       Queries control information about a running service.
                            i.e. Can it be paused, stopped, etc?
        infostartup:    Queries service Startup type. (Boot, System, 
                            Automatic, Manual, Disabled)
        setstartup      Changes/sets Startup type. (Boot, System, 
                            Automatic, Manual, Disabled)                    
        getname:        Gets the long and short service names used by Windows.
                            (Generally used for internal purposes)
    """    
        
    def __init__(self, service, machinename=None, dbname=None):
        self.userv = service
        self.scmhandle = ws.OpenSCManager(machinename, dbname, ws.SC_MANAGER_ALL_ACCESS)
        self.sserv, self.lserv = self.getname()
        if (self.sserv or self.lserv) == None: exit()
        self.handle = ws.OpenService(self.scmhandle, self.sserv, ws.SERVICE_ALL_ACCESS)
        self.sccss = "SYSTEM\\CurrentControlSet\\Services\\"
        
    def start(self):
        ws.StartService(self.handle, None)
        
    def stop(self):
        self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_STOP)

    def restart(self):
        self.stop()
        self.fetchstate("STOPPED")
        self.start()
        
    def pause(self):
        self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_PAUSE)
    
    def resume(self):
        self.stat = ws.ControlService(self.handle, ws.SERVICE_CONTROL_CONTINUE)
        
    def status(self, prn = 0):
        self.stat = ws.QueryServiceStatus(self.handle)
        if self.stat[1]==ws.SERVICE_STOPPED:
            if prn == 1:
                print "The", self.lserv, "service is stopped."
            else:
                return "STOPPED"
        elif self.stat[1]==ws.SERVICE_START_PENDING:
            if prn == 1:
                print "The", self.lserv, "service is starting."
            else:
                return "STARTING"
        elif self.stat[1]==ws.SERVICE_STOP_PENDING:
            if prn == 1:
                print "The", self.lserv, "service is stopping."        
            else:
                return "STOPPING"
        elif self.stat[1]==ws.SERVICE_RUNNING:
            if prn == 1:
                print "The", self.lserv, "service is running."        
            else:
                return "RUNNING"
                
    def fetchstatus(self, fstatus, timeout=None):
        self.fstatus = fstatus.upper()
        if timeout != None:
            timeout = int(timeout); timeout *= 2
        def to(timeout):
            time.sleep(.5)
            if timeout != None:
                if timeout > 1:
                    timeout -= 1; return timeout
                else:
                    return "TO"   
        if self.fstatus == "STOPPED":
            while 1:
                self.stat = ws.QueryServiceStatus(self.handle)
                if self.stat[1]==ws.SERVICE_STOPPED:
                    self.fstate = "STOPPED"; break
                else:
                    timeout=to(timeout)
                    if timeout == "TO":
                        return "TIMEDOUT"; break
        elif self.fstatus == "STOPPING":
            while 1:
                self.stat = ws.QueryServiceStatus(self.handle)
                if self.stat[1]==ws.SERVICE_STOP_PENDING:
                    self.fstate = "STOPPING"; break
                else:
                    timeout=to(timeout)
                    if timeout == "TO":
                        return "TIMEDOUT"; break                      
        elif self.fstatus == "RUNNING":
            while 1:
                self.stat = ws.QueryServiceStatus(self.handle)
                if self.stat[1]==ws.SERVICE_RUNNING:
                    self.fstate = "RUNNING"; break
                else:
                    timeout=to(timeout)
                    if timeout == "TO":
                        return "TIMEDOUT"; break                       
        elif self.fstatus == "STARTING":
            while 1:
                self.stat = ws.QueryServiceStatus(self.handle)
                if self.stat[1]==ws.SERVICE_START_PENDING:
                    self.fstate = "STARTING"; break
                else:
                    timeout=to(timeout)
                    if timeout == "TO":
                        return "TIMEDOUT"; break
        
    def infotype(self):
        self.stat = ws.QueryServiceStatus(self.handle)
        if self.stat[0] & ws.SERVICE_WIN32_OWN_PROCESS:
            print "The", self.lserv, "service runs in its own process."
        if self.stat[0] & ws.SERVICE_WIN32_SHARE_PROCESS:
            print "The", self.lserv, "service shares a process with other services."
        if self.stat[0] & ws.SERVICE_INTERACTIVE_PROCESS:
            print "The", self.lserv, "service can interact with the desktop."
        
    def infoctrl(self):
        self.stat = ws.QueryServiceStatus(self.handle)
        if self.stat[2] & ws.SERVICE_ACCEPT_PAUSE_CONTINUE:
            print "The", self.lserv, "service can be paused."
        if self.stat[2] & ws.SERVICE_ACCEPT_STOP:
            print "The", self.lserv, "service can be stopped."
        if self.stat[2] & ws.SERVICE_ACCEPT_SHUTDOWN:
            print "The", self.lserv, "service can be shutdown."    

    def infostartup(self):
        self.isuphandle = wa.RegOpenKeyEx(wc.HKEY_LOCAL_MACHINE, self.sccss + self.sserv, 0, wc.KEY_READ)
        self.isuptype = wa.RegQueryValueEx(self.isuphandle, "Start")[0]
        wa.RegCloseKey(self.isuphandle)
        if self.isuptype == 0:
            return "boot"
        elif self.isuptype == 1:
            return "system"
        elif self.isuptype == 2:
            return "automatic"
        elif self.isuptype == 3:
            return "manual"
        elif self.isuptype == 4:
            return "disabled"
         
    def setstartup(self, startuptype):
        self.startuptype = startuptype.lower()
        if self.startuptype == "boot":
            self.suptype = 0
        elif self.startuptype == "system":
            self.suptype = 1
        elif self.startuptype == "automatic":
            self.suptype = 2
        elif self.startuptype == "manual":
            self.suptype = 3
        elif self.startuptype == "disabled":
            self.suptype = 4
        self.snc = ws.SERVICE_NO_CHANGE
        ws.ChangeServiceConfig(self.handle, self.snc, self.suptype, \
        self.snc, None, None, 0, None, None, None, self.lserv) 
        
    def getname(self):
        self.snames=ws.EnumServicesStatus(self.scmhandle)
        for i in self.snames:
            if i[0].lower() == self.userv.lower():
                return i[0], i[1]; break
            if i[1].lower() == self.userv.lower():
                return i[0], i[1]; break
        print "Error: The", self.userv, "service doesn't seem to exist."
        return None, None

Discussion

Using this class in python scripts makes it easy to control Windows services without reinventing the wheel every time. The ability to create a class instance of any desired service allows one to control services with very little logic. This class extends the inspired work of Mark Hammond, author of the win32all package and more, and andy mckay, cookbook contributor.

Issues: Poor exception handling, i.e. None. ;-)

Comments

  1. 1. At 12:33 p.m. on 26 jun 2002, Lloyd Kvam said:

    usage difficulties. The fetchstatus method can loop forever if you ask for the wrong status. The service name requires an exact match (case sensitive) to process a service. This is stricter than the underlying system functions.

  2. 2. At 12:10 a.m. on 18 jul 2002, ap anonypea (the author) said:

    Re: usage difficulties. It's true the fetchstatus method can run forever but I don't see that as a bad thing, do you? It's not often we have things that can last forever, so I say enjoy it and let it rip! ;-) Actually I've updated the method, it now supports a timeout argument but forever is still the default. For the hard corers out there! lol

    The service name thingy... I thought "What's so hard about pulling the name out of the service control manager? Just double click on the service and then CTRL-C." when I wrote it. So I think the service name lookup is being a bit picky but it's been adjusted. It now supports long and short names with mixed cases. The feature in the win32serviceutil where it does the kinder, gentler service name lookup isn't that low level though. It uses some of the very code on this cookbook site. Look for the "Get the Windows service name from the long name" recipe, it's in the System Admin section. I'm not sure which came first though, the recipe or the win32serviceutil?

    Thanks for the comments. Keep them coming! ;-)

  3. 3. At 10:20 a.m. on 20 aug 2002, Mike Nugent said:

    Review status of remote servers. I wrote a small python hack using the sc.exe command to poll our Win2000 Domain Controller's Service status. I mainly look at ntfrs for File Replication. Would it be possible to add this ability to WService?

  4. 4. At 5:18 p.m. on 20 aug 2002, ap anonypea (the author) said:

    Re: Review status of remote servers. Good question. I've modified WService to work with remote machines but I'm not sure if it works correctly since I don't have a setup to properly test it. I believe the api depends on one or more services, namely the Server and possibly the RPC's and/or Remote Registry services, running on the remote machine. It would be great if you could test it and let me know if it works.

  5. 5. At 8:13 a.m. on 22 nov 2007, Artem Sopin said:

    fetchstate(). fetchstate() is not declarated within this class but used in restart() method. I suppose it was renamed to fetchstatus() but restart() methdod was not renewed. In common looks matue, will use it :)

  6. 6. At 6:14 a.m. on 11 feb 2008, Rick Glorie said:

    Raw input.. Hello,

    I don't speak python or any other language. Could there be some thing like a raw input where computername/ip adress and servicename/procesid could be filled in. I can't figure it out with the comments, they're to poor for me, raise more questions then they answer.

    Thanks!

Sign in to comment