• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2321
  • Last Modified:

VBScript to Stop/Terminate a Service

I've put together a VBScript to run on a scheduled task for restarting the MySQL server service using WMI.  However, recently the service seems to be hanging when the script tries to stop it.  When I come in, the notification I set up indicates that the STOP command was successfully sent, but the script failed after waiting for 20 minutes for it to actually stop.

If I go look at the services on the machine, the MySQL service shows that it's "Stopping", but I can't do anything with it.  If I go to the Task Manager and End Process on the mysqld.exe, the service finally stops, and I can then start it normally.  This has only happened a couple of times, but I'm wondering if I can optimize my script a little to end the process if the service gets hung in the "Stopping" state again.

I have a MySQL server running on my local machine which I've used for testing the script, but I can't seem to actually terminate the process.  Here's the section of the script I'm using to try to kill the process:
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

If Err.Number <> 0 Then
    WScript.Echo "Failed to access the running services on " & strComputer
    Exit Function
End If

Set colListOfProcesses = objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE Name = 'mysqld.exe")

For Each objProcess In colListOfProcesses
    WScript.Echo "Terminating process"
    objProcess.Terminate()
    
    If Err.number <> 0 Then
        WScript.Echo "Could not terminate the process. Error " & Err.number & " Description " & Err.Description
    End If
    
    WScript.Sleep 15000
    
    Dim colTempList
    Set colTempList = objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE Name = 'mysqld.exe'")
    
    If colTempList.Count = 0 Then
        WScript.Echo "Process terminated"
    Else
        WScript.Echo "Process is still running"
    End If
Next

Open in new window

Unfortunately, every time I run the script I get the "Process is still running" result, and looking at the Task Manager still shows the mysqld.exe running.  This tells me, that the Terminate() command was sent to the process, but for some reason the process basically ignored it.  I've even waited for a few minutes after the script completed before checking the processes again, and Task Manager still shows it running.  If I manually "Stop Process" through the Task Manager, it terminates as expected and the Services control panel shows that the MySQL server service is stopped.  I can then restart the service, and everything goes back to normal.

So, I'm kinda stumped.  More than likely I'm just missing something, but I just can't see it.  Any help would be appreciated.
0
G_Hosa_Phat
Asked:
G_Hosa_Phat
  • 2
  • 2
2 Solutions
 
Renato Montenegro RusticiIT SpecialistCommented:
You can call taskkill to force (terminate) the process:

taskkill /F /IM mysqld.exe /T

It's included with Windows. You can also use the kill.exe tool:

Free Resource Kit Tools
http://www.petri.co.il/download_free_reskit_tools.htm

However, It's recommended that you verify why the process is hanging on stop. You could even end up with a corrupt database if you continue to force a database process to exit.
0
 
RobSampsonCommented:
Instead of using WMI (because it doesn't wait for a response from the service), try shelling out to the command line.

Regards,

Rob.
Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec("net stop mysql")
While objExec.Status = 0
	WScript.Sleep 100
Wend
strOutput = objExec.StdOut.ReadAll & VbCrLf & objExec.StdErr.ReadAll
If InStr(strOutput, "service was stopped successfully") = 0 Then
	WScript.Echo strOutput & VbCrLf & "Attempting to terminate it."
	intReturn = objShell.Run("taskkill /IM mysqld.exe", 0, True)
	If intReturn = 0 Then
		WScript.Echo "Process terminated."
	Else
		WScript.Echo "Unable to terminate process. Return code " & intReturn
	End If
Else
	WScript.Echo "Service stopped."
End If

Open in new window

0
 
G_Hosa_PhatAuthor Commented:
Thank you for your replies.  I've been trying to determine why it has suddenly begun not stopping properly, but the problem is intermittent and giving me one of those great big IT-sized headaches. (Isn't that always the way?)

@rmrustice: I can certainly make a call to taskkill, and that definitely may be the way I have to go.  Even so, I'm really more curious as to why the process appears to be totally ignoring the Terminate() command.  I can't think of any reason that it wouldn't work, unless it's a "quirk" in MySQL, or something.  Still, I wouldn't think that this command would work any differently on one process or another.  I mean, Terminate() == Terminate(), right?

@RobSampson: Similar to my response above.  I can shell out the command, but I'd really like to figure out why I'm having problems using the Terminate() command.  Even if the script is moving on, once the command is sent to the process, that process should stop, even if the script completes and moves on.

@ALL: I've "beefed up" that section of my script a little to run on a loop.  It sends the Terminate() command to the process (only once), then check the service's state every 15 seconds for 10 minutes to determine if it has stopped.  This is actually part of a much larger script that uses WMI to try to stop the service.  It only runs this part if the service hasn't stopped normally after 20 minutes.  This gives it a full 30 minutes to try and stop the service before giving up.

Just for "giggles" (in case anyone is looking for a "mostly" working script), here's the full RestartService function in my script:
'----------------------------------------------------------------------
'----------------------------------------------------------------------
FUNCTION RestartService(strRestartMessage)
    ' *********************************************************************
    ' ** This function attempts to restart the specified service on the  **
    ' ** specified remote computer (server or workstation) while logging **
    ' ** any problems encountered to the system's event log, and sending **
    ' ** e-mail notifications out to alert system administrator(s) of    **
    ' ** those problems so that the script can be used as a scheduled    **
    ' ** task with no user intervention.                                 **
    ' *********************************************************************
    Const EVENT_SUCCESS = 0
    Const EVENT_ERROR = 1
    Const EVENT_WARNING = 2
    Const EVENT_INFORMATION = 4
    Const EVENT_AUDITSUCCESS = 8
    Const EVENT_AUDITFAILURE = 16
    
    Dim objWMIService, objItem, objService
    Dim objWscript
    Dim colListOfServices, strComputer, strService, intSleep, intDateLen, dtmStartTime, strMessage
    Dim colListOfProcesses, objProcess, colTermServices, objTermService
    Dim colTempServices, objTempService, strState, strUser, strIndent, strProcess
    
    On Error Resume Next
    Err.Clear
    
    intDateLen = Len("[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "]")
    strIndent = "                 "
    
    Do While Len(strIndent) < intDateLen + 1
        strIndent = strIndent & " "
    Loop
    
    ' *********************************************************************
    ' ** Get the username of whoever is running the script for possible  **
    ' ** use in the e-mail message.  This may help in diagnosing issues. **
    ' *********************************************************************
    Set WshNetwork = WScript.CreateObject("WScript.Network")
    strUser = WshNetwork.UserName
    Set WshNetwork = Nothing
    
    ' *********************************************************************
    ' ** Set the variables used for the script to make the necessary     **
    ' ** connections and queries.                                        **
    ' *********************************************************************
    
    ' *********************************************************************
    ' ** strComputer is the name of the remote system on which the       **
    ' ** service to be restarted is running.                             **
    ' *********************************************************************
    strComputer = "10.0.0.254"
    
    ' *********************************************************************
    ' ** strService is the actual name of the service running on the     **
    ' ** remote system.  NOTE: This is Case-Sensitive, so be sure to get **
    ' ** the exact spelling of the service name as it is running on the  **
    ' ** remote system.                                                  **
    ' *********************************************************************
    strService = "MySQL"
    
    ' *********************************************************************
    ' ** strProcess is the executable name of the process running on the **
    ' ** remote system. This can be found in the properties of the       **
    ' ** service in the "Path to Executable" line.                       **
    ' *********************************************************************
    strProcess = "mysqld.exe"
    
    ' *********************************************************************
    ' ** intSleep is the amount of time (in milliseconds) to wait        **
    ' ** between sending requests/commands to the remote system when     **
    ' ** needed.                                                         **
    ' *********************************************************************
    intSleep = 15000
    
    ' *********************************************************************
    ' ** dtmStartTime is used as a base for timing the restart actions   **
    ' ** out if they are failing or hung for some reason.                **
    ' *********************************************************************
    dtmStartTime = Time
    
    ' *********************************************************************
    ' ** Establish a connection to the remote system using whatever      **
    ' ** credentials with which either you are signed in, or you have    **
    ' ** identified via "Run As"                                         **
    ' *********************************************************************
    strRestartMessage = "---------- RESTARTING " & UCase(strService) & " SERVICE ON " & UCase(strComputer) & " ----------" & vbcrlf
    strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Attempting to restart the " & strService & " service on " & strComputer & "." & vbcrlf
    
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    
    If Err.Number <> 0 Then
        Set objWMIService = Nothing
        RestartService = False
        
        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Could not access the currently running services on " & strComputer & " as " & strUser & " at this time." & vbcrlf & vbcrlf
        Exit Function
    End If
    
    ' *********************************************************************
    ' ** Find the specified service in the remote system's current list  **
    ' ** of installed services.  NOTE: Again, strService is Case-        **
    ' ** Sensitive. If the script is unable to find the service you are  **
    ' ** trying to restart, log into the remote system and confirm the   **
    ' ** EXACT spelling of the service name.                             **
    ' *********************************************************************
    Set colListOfServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
    
    If Err.Number <> 0 Or colListOfServices.Count = 0 Then
        Set colListOfServices = Nothing
        Set objWMIService = Nothing
        RestartService = False
        
        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] The " & strService & " service was not found installed on " & strComputer & "." & vbcrlf & vbcrlf
        Exit Function
    End If
    
    For Each objService in colListOfServices
        ' *********************************************************************
        ' ** At this point we will perform the actual stopping and starting  **
        ' ** of the specified service.  Using the strState variable enables  **
        ' ** us to keep up with the current state of the service we're       **
        ' ** attempting to stop.                                             **
        ' *********************************************************************
        strState = UCase(objService.State)
        
        ' *********************************************************************
        ' ** Send the STOP command to the specified service.  This provides  **
        ' ** the service the opportunity to close out any connections and    **
        ' ** shut down gracefully.                                           **
        ' *********************************************************************
        objService.StopService()
        
        ' *********************************************************************
        ' ** If the STOP command generates an error, add the details of the  **
        ' ** error to the e-mail message being sent to the IT HelpDesk.      **
        ' *********************************************************************
        If Err.Number <> 0 Then
            Set objWscript = CreateObject("Wscript.Shell")
            objWscript.LogEvent EVENT_INFORMATION, "The " & strService & " service failed to stop properly."
            
            Set objWMIService = Nothing
            Set colListOfServices = Nothing
            RestartService = False
            
            strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Failed to STOP the " & strService & " service.  The service is currently " & strState & "." & vbcrlf _
                & strIndent & "Error Number: " & Err.Number & vbcrlf _
                & strIndent & "Error Source: " & Err.Source & vbCrLf _
                & strIndent & "Error Description: " & Err.Description & vbcrlf & vbcrlf
            Set objWscript = Nothing
                
            Exit Function
        End If
        
        ' *********************************************************************
        ' ** Maintain a loop to keep an eye on the current state of the      **
        ' ** service.  Once it has actually stopped, move to the next step.  **
        ' *********************************************************************
        Do While strState <> "STOPPED"
            WScript.Sleep intSleep
            
            Set colTempServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
            
            For Each objTempService In colTempServices
                strState = UCase(objTempService.State)
            Next
            
            If strState <> "STOPPED" And Time >= DateAdd("n", 20, dtmStartTime) Then
                ' *********************************************************************
                ' ** If the service hasn't stopped after 20 minutes, try to send the **
                ' ** Terminate command to the actual process (executable) that the   **
                ' ** service is running and loop for another 10 minutes.             **
                ' *********************************************************************
                strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] The " & strService & " service has failed to stop normally for 20 minutes." & vbcrlf _
                    & strIndent & "Attempting to TERMINATE the service." & vbcrlf & vbcrlf
                
                ' *********************************************************************
                ' ** We'll only send the Terminate command once.  If it still fails  **
                ' ** to stop after that, we'll just have to assume the service is    **
                ' ** "hung" and requires manual intervention.                        **
                ' *********************************************************************
                Set colListOfProcesses = objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE Name = '" & strProcess & "'")
                
                If colListOfProcesses.Count = 0 Then
                    Set colTermServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
                    
                    For Each objTermService In colTermServices
                        strState = UCase(objTermService.State)
                    Next
                    
                    If strState <> "STOPPED" Then
                        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] The " & strProcess & " process was not found running on " & strComputer & "." & vbcrlf _
                            & strIndent & "The " & strService & " service is currently " & strState & "." & vbcrlf _
                            & strIndent & "Terminating the script." & vbcrlf & vbcrlf
                        
                        Set colListOfProcesses = Nothing
                        Set colTermServices = Nothing
                        Set objWMIService = Nothing
                        RestartService = False
                        
                        Exit Function
                    Else
                        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] The " & strProcess & " process was not found running on " & strComputer & "." & vbcrlf _
                            & strIndent & "The " & strService & " service is currently " & strState & "." & vbcrlf & vbcrlf
                        
                        Set colListOfProcesses = Nothing
                    End If
                End If
                
                For Each objProcess In colListOfProcesses
                    objProcess.Terminate()
                    
                    If Err.Number <> 0 Then
                        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Failed to TERMINATE the " & strProcess & " process." & vbcrlf _
                            & strIndent & "The " & strService & " service is currently " & strState & "." & vbcrlf _
                            & strIndent & "Error Number: " & Err.Number & vbcrlf _
                            & strIndent & "Error Source: " & Err.Source & vbCrLf _
                            & strIndent & "Error Description: " & Err.Description & vbcrlf & vbcrlf
                        Set colListOfProcesses = Nothing
                        Set objWMIService = Nothing
                        RestartService = False
                        
                        Exit Function
                    End If
                Next
                
                Do While strState <> "STOPPED"
                    WScript.Sleep intSleep
                    
                    Set colTermServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
                    
                    For Each objTermService In colTermServices
                        strState = UCase(objTermService.State)
                    Next
                    
                    If strState <> "STOPPED" And Time >= DateAdd("n", 30, dtmStartTime) Then
                        ' *********************************************************************
                        ' ** If the service still hasn't stopped after 30 minutes, give up   **
                        ' ** and return a failure to the calling procedure.                  **
                        ' *********************************************************************
                        Set colTermServices = Nothing
                        Set colListOfProcesses = Nothing
                        Set objWMIService = Nothing
                        RestartService = False
                        
                        strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Failed to STOP the " & strService & " service." & vbcrlf _
                            & strIndent & "The script gave up after waiting for 30 minutes for the service to stop.  The service is currently " & strState & vbcrlf & vbcrlf
                        Exit Function
                    End If
                    
                    Set colTermServices = Nothing
                    Set colListOfProcesses = Nothing
                Loop
            End If
            
            Set colTempServices = Nothing
        Loop
        
        dtmStartTime = Time
        
        ' *********************************************************************
        ' ** Send the START command to initiate the specified service and    **
        ' ** wait for it to properly initialize.                             **
        ' *********************************************************************
        objService.StartService()
        
        If Err.Number <> 0 Then
            Set objWscript = CreateObject("Wscript.Shell")
            objWscript.LogEvent EVENT_INFORMATION, "The " & strService & " service failed to start properly."
            
            Set objWMIService = Nothing
            RestartService = False
            
            strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Failed to START the " & strService & " service.  The service is currently " & strState & "." & vbcrlf _
                & strIndent & "Error Number: " & Err.Number & vbcrlf _
                & strIndent & "Error Source: " & Err.Source & vbCrLf _
                & strIndent & "Error Description: " & Err.Description & vbcrlf & vbcrlf
            Set objWscript = Nothing
            
            Exit Function
        End If
        
        ' *********************************************************************
        ' ** Get the current state of the service before starting a look.    **
        ' *********************************************************************
        Set colTempServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
        
        For Each objTempService In colTempServices
            strState = UCase(objTempService.State)
        Next
        
        Do While strState <> "RUNNING"
            WScript.Sleep intSleep
            
            Set colTempServices = objWMIService.ExecQuery ("SELECT * FROM Win32_Service WHERE Name = '" & strService & "'")
            
            For Each objTempService In colTempServices
                strState = UCase(objTempService.State)
            Next
            
            If Time >= DateAdd("n", 20, dtmStartTime) Then
                Set objWMIService = Nothing
                RestartService = False
                
                strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] Failed to START the " & strService & " service." & vbcrlf _
                        & strIndent & "The script gave up after waiting for 20 minutes for the service to START.  The service is currently " & strState & vbcrlf & vbcrlf
                Exit Function
            End If
        Loop
        
        Set objWscript = CreateObject("Wscript.Shell")
        objWscript.LogEvent EVENT_INFORMATION, "The " & strService & " service was restarted by the scheduled task."
        
        Set objWscript = Nothing
    Next
    
    strRestartMessage = strRestartMessage & "[" & FormatDateTime(Date, vbShortDate) & " " & FormatDateTime(Time, vbLongTime) & "] The " & strService & " on " & strComputer & " was successfully restarted." & vbcrlf & vbcrlf
    
    Set objWMIService = Nothing
    Set colListOfServices = Nothing
    RestartService = True
END Function

Open in new window

The strRestartMessage is used for an e-mail submission when the restart is complete.  In my testing I've commented out everything except for the section for terminating the process, since the service will stop normally most of the time.  If it stops normally, I don't want to mess with terminating the process at all.  It's only if the service doesn't stop normally that I want it to kill the process (like in your example, Rob).

So, it comes back to my "real" question: why is the Terminate() command not working?
0
 
Renato Montenegro RusticiIT SpecialistCommented:
When you try to gracefully close an application, it will receive a message (at the API level, it's all about messages). If the application can't react to that message (usually started by the ExitProcess API) may be it's doing something else that requires a longer time to complete or may be it's trapped (hang) somewhere. In that case, you can try to close the application by force (the TerminateProcess API). I don't know for sure, but I think most scripting languages use the ExitProcess approach. So, when you want to really terminate a process, you need a external application like taskkill or kill.exe.

Try to get help from a database expert. They may be able to find out why MySQL is hanging.
0
 
G_Hosa_PhatAuthor Commented:
Thanks for the help.  I'll do some more digging into why the server isn't shutting down properly.  If necessary, I'll add the taskkill call to the script.  Hopefully this won't become a regular issue where I really need to rely on such drastic measures anyway, but it's always good to have a "backup".
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now