Wednesday, April 29, 2009

Starting/stopping Windows services from a script

Ever had a situation where you needed to stop at least one Windows service that also is dependent on other services? I've got one now, where Oracle WCI and BPM Enterprise are running on a box with other more critical services, but eventually, one of the Oracle processes starts running out of control and takes up 100% of CPU and memory. If you can get to the console and eventually login (it take 5 minutes, literally), you see a message box telling you the server has run out of virtual memory.

Normally, we administer the server via remote desktop/terminal server from our desktop or VPN if we happen to be remote. But in this case, the box does not have enough free CPU or memory to even respond to remote connections and someone has to physically go into the server room and shutdown the box (it takes 30 minutes for the box to shutdown) or kill the power (if they don't have a login). Not very good options in any case...

So, I poked around the Microsoft site and thought, "hey, I've created Windows services before with sc.exe, I should be able to stop them from a command window." A great idea, until you try sc.exe to stop a service that depends on other services. You get the dreaded


[SC] ControlService FAILED 1051:

A stop control has been sent to a service that other running services are dependent on.


error message. Worst of all, you won't even see the error if you have written this in a batch script - it'll just fly on by.

I thought, ok, so I have to specify each service in reverse order of dependency in my script. There are 7 services to stop, so I had a line calling sc.exe for each one.


sc.exe stop Tomcat6
sc.exe stop ptautomationservices
sc.exe stop "Ldap server"
sc.exe stop wsserver
sc.exe stop OracleBPMWebApplications
sc.exe stop SQLBrowser
sc.exe stop MSSQL$SQLEXPRESS


Well, only the first service stopped and none of the others. Eventually I found that sc.exe returns immediately, and any dependent services probably haven't even begun to stop, so they fail the stop command. So we have to wait until each service completes stopping.

After Googling around for a while, I eventually came upon sites that pointed out that you have to prepend with "start" like velocityreviews or tek-tips.com suggests:

start /wait sc \\server_name stop service_name1
start /wait sc \\server_name stop service_name2

Great! every call to sc.exe will wait until the command finishes stopping the service befre executing the next one. So I happily went on to modify my script to:


start /wait sc.exe stop Tomcat6
start /wait sc.exe stop ptautomationservices
start /wait sc.exe stop "Ldap server"
start /wait sc.exe stop wsserver
start /wait sc.exe stop OracleBPMWebApplications
start /wait sc.exe stop SQLBrowser
start /wait sc.exe stop MSSQL$SQLEXPRESS


and then executed the batch script, expecting all the services to shutdown gracefully in order.

Wrong! On Windows 2003 Server, it doesn't wait. :-( WTF!!

Again, Tomcat stopped and sometimes the automation services, but I didn't see anything on the screen appear to wait or pause. The script still just flies by. So I Googled around a bunch more... There must be a solution and I can't be the only one trying to do something like this. I found similar issues with the same answers, but no resolution. One suggested, write a WMI script, another suggested write a VB program. What? Just to shutdown services? There has to be a better way.

Then I thought, you can use net \\servername stop servicename from the command line to stop a service on another box over the network, what happens when I do it on the same box? So I tried:

c:\net stop MSSQL$SQLEXPRESS

in a DOS window, and waited...


The following services are dependent on the SQL Server (SQLEXPRESS) service.
Stopping the SQL Server (SQLEXPRESS) service will also stop these services.

Apache Tomcat
BEA ALI Automation Service
BEA ALI LDAP Directory
BEA ALI API Service
Oracle BPM Web Applications
SQL Server Browser

Do you want to continue this operation? (Y/N) [N]:


hmm.... at least it asks me if I really want to do it, so I enter "Y" and cross my fingers:

The Apache Tomcat service was stopped successfully.

The BEA ALI Automation Service service is stopping.......
The BEA ALI Automation Service service was stopped successfully.

The BEA ALI LDAP Directory service is stopping........
The BEA ALI LDAP Directory service was stopped successfully.

The BEA ALI API Service service is stopping.......
The BEA ALI API Service service was stopped successfully.

The Oracle BPM Web Applications service is stopping.......
The Oracle BPM Web Applications service was stopped successfully.

The SQL Server Browser service is stopping.
The SQL Server Browser service was stopped successfully.

The SQL Server (SQLEXPRESS) service is stopping.
The SQL Server (SQLEXPRESS) service was stopped successfully.


it actually works! But what if I don't want the user to have a choice and just force the "y" answer? In my case, the machine is usually not responsive enough for the user to sit around for minutes before being prompted for a "Y" or "N", it just has to work. Is that possible inside a batch script? I still haven't found the answer to that yet, but this is a start...

Update... ( Wed 29 Apr 2009 10:09:20 PM PDT )
to force net stop to not prompt for user input you append /YES, e.g.:


c:\net stop MSSQL$SQLEXPRESS /YES


But, I still have the problem if the server is too busy, it may not be able to keep track of the dependent services to shutdown or the stop command may time out before the service even receives the event. So, I'm probably back to sending each service the shutdown signal:

net stop Tomcat6 /YES
net stop ptautomationservices /YES
net stop "Ldap server" /YES
net stop wsserver /YES
net stop OracleBPMWebApplications /YES
net stop SQLBrowser /YES
net stop MSSQL$SQLEXPRESS /YES

at least my user will be able to see the progress (or lack thereof) while the server attempts to stand itself back up.

1 comment:

  1. Thank you this works great and in conjunction with cygwin does exactly what I need!

    ReplyDelete