Welcome, guest | Sign In | My Account | Store | Cart

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, 211 lines
  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
"""
Module for manipulating WinNT, Win2k & WinXP services.
Requires the win32all package which can be retrieved
from => http://starship.python.net/crew/mhammond
"""
import sys, time
import win32api as wa, win32con as wc, win32service as ws

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: sys.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.fetchstatus("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 %s service is stopped." % self.lserv
            else:
                return "STOPPED"
        elif self.stat[1]==ws.SERVICE_START_PENDING:
            if prn == 1:
                print "The %s service is starting." % self.lserv
            else:
                return "STARTING"
        elif self.stat[1]==ws.SERVICE_STOP_PENDING:
            if prn == 1:
                print "The %s service is stopping." % self.lserv
            else:
                return "STOPPING"
        elif self.stat[1]==ws.SERVICE_RUNNING:
            if prn == 1:
                print "The %s service is running." % self.lserv
            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] and ws.SERVICE_WIN32_OWN_PROCESS:
            print "The %s service runs in its own process." % self.lserv
        if self.stat[0] and ws.SERVICE_WIN32_SHARE_PROCESS:
            print "The %s service shares a process with other services." % self.lserv
        if self.stat[0] and ws.SERVICE_INTERACTIVE_PROCESS:
            print "The %s service can interact with the desktop." % self.lserv

    def infoctrl(self):
        self.stat = ws.QueryServiceStatus(self.handle)
        if self.stat[2] and ws.SERVICE_ACCEPT_PAUSE_CONTINUE:
            print "The %s service can be paused." % self.lserv
        if self.stat[2] and ws.SERVICE_ACCEPT_STOP:
            print "The %s service can be stopped."  % self.lserv
        if self.stat[2] and ws.SERVICE_ACCEPT_SHUTDOWN:
            print "The %s service can be shutdown." % self.lserv

    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 %s service doesn't seem to exist." % self.userv
        return None, None

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.

9 comments

Lloyd Kvam 21 years, 9 months ago  # | flag

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.

ap anonypea (author) 21 years, 8 months ago  # | flag

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! ;-)

Mike Nugent 21 years, 7 months ago  # | flag

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?

ap anonypea (author) 21 years, 7 months ago  # | flag

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.

Artem Sopin 16 years, 4 months ago  # | flag

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 :)

Rick Glorie 16 years, 1 month ago  # | flag

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!

Dan Ryan 14 years ago  # | flag

There is a small mistake in the code. Once I changed "fetchstate" to "fetchstatus" the restart method worked fine.

ap anonypea (author) 13 years, 6 months ago  # | flag

The fetchstatus bug in the restart method has been fixed. It's amazing after 8+ yrs some folks are finding the code useful. Good to know.

James Boone 8 years, 9 months ago  # | flag

@ ap anonypea, 13 years and counting! Used it for reference today on a service tool I'm building. Thanks!