Wednesday, May 21, 2008

RemoteService Function

Slacker.  Go ahead, say it. I know your thinking it.  Work has been busy but that doesn't mean I'm slacking off on coding.  Oh no, I'm hard at work writing new functions and subs.  I finished one recently when I needed to stop and start a service on a remote machine.  And as usual, I couldn't just make a sub that only stopped and started a service.  I had to add in other abilities like Pause, Resume, and Restart.  Oh yeah, now we're talking.

But that's not all.  I started to think, what else would I want to do with a service?  How about changing it's startup type to Automatic, Manual, or Disabled?  That's something we network administrators need to do from time to time.  So I added that in too.

I wrapped all the code up in a nifty little sub (sorry, no shiny paper and bow).  To use it, simply pass the computer name, service name, and the action you want to complete and presto!  The service will be changed.

chrip chrip chrip..  What's that?  The little birdy on my shoulder said "what about errors?".  Good point.  What if we want to capture the return status of the action?  For example, what if I try to start a service that is already started?  It turns out that we can capture the return code.  The code is a user un-friendly integer so run it through a select case and set a boolean variable as true/false as well as setting some status text. So now that we have that, how do we pass two variables back?  You can't pass it back in a single function.  So here's what I did.

To get the return code and status, declare these two variables in the main part of the script: blnServiceStatus and strServiceStatus.

When the action on the service completes, the return code is filtered and these two variables are set.  All you need to do is declare them globally and now you've got the status!  One special note on the blnServiceStatus results, I tried my best to interpret the return code as a true or false as representative of the success of the action.  You may need to tweak these for your desired results.

All this talk and no action.  Let's see some code!

Sub remoteService(sstrComputer,sstrService,sstrAction)
'This accepts a computer name, service name, and action to complete on the service.
'Input: sstrComputer = Machine to perform action on.  Use "." for local
'Input: sstrService = Name of the service
'Input: sstrAction = See options below
'        "Start" = Start the service
'        "Stop" = Stop the service
'        "Restart" = Restart the service
'        "Pause" = Pause the service
'        "Resume" = Resume the service
'        "Automatic" = Set the startup type to Automatic
'        "Manual" = Set the startup type to Manual
'        "Disabled" = Set the startup type to Disabled
'To get the status codes:
'1.  Declare strServiceStatus and blnServiceStatus globally (Main part of the script)
'2.  Call this sub as usual.
'3.  blnServiceStatus will be set to True if successfull.  
'4.  strServiceStatus will be set to the status of the action
On Error Resume Next 
    Set sobjWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & sstrComputer & "\root\cimv2")
    Set scolServiceList = sobjWMIService.ExecQuery("Select * from Win32_Service where Name='" & sstrService &"'")
    'Set colServiceList = objWMIService.ExecQuery("Select * from Win32_Service")
    For Each sobjService in scolServiceList
        'WScript.Echo sobjService.Name
        sstrAction = UCase(sstrAction)
        Select Case sstrAction
            Case "START"
                serrReturn = sobjService.StartService()
            Case "STOP"
                serrReturn = sobjService.StopService()
            Case "RESTART"
                serrReturn = sobjService.StopService()
                serrReturn = sobjService.StartService()
            Case "PAUSE"
                serrReturn = sobjService.PauseService()
            Case "RESUME"
                serrReturn = sobjService.ResumeService()
            Case "AUTOMATIC"
                serrReturn = sobjService.ChangeStartMode("Automatic")
            Case "MANUAL"
                serrReturn = sobjService.ChangeStartMode("Manual")
            Case "DISABLED"
                serrReturn = sobjService.ChangeStartMode("Disabled")
        End Select
        'WScript.Echo serrReturn
        Select Case serrReturn
            Case 0  'Success
                blnServiceStatus = True
                strServiceStatus = "Success"
            Case 1    'Not Supported
                blnServiceStatus = False
                strServiceStatus = "Not Supported"
            Case 2    'Access Denied
                blnServiceStatus = False
                strServiceStatus = "Access Denied"
            Case 3    'Dependent Services Running
                blnServiceStatus = True
                strServiceStatus = "Dependent Services Running"
            Case 4    'Invalid Service Control
                blnServiceStatus = False
                strServiceStatus = "Invalid Service Control"
            Case 5    'Service Cannot Accept Control
                blnServiceStatus = False
                strServiceStatus = "Service Cannot Accept Control"
            Case 6    'Service Not Active
                blnServiceStatus = False
                strServiceStatus = "Service Not Active"
            Case 7    'Service Request Timeout
                blnServiceStatus = False
                strServiceStatus = "Service Request Timeout"
            Case 8    'Unknown Failure
                blnServiceStatus = False
                strServiceStatus = "Unknown Failure"
            Case 9    'Path Not Found
                blnServiceStatus = False
                strServiceStatus = "Path Not Found"
            Case 10    'Service Already Running
                blnServiceStatus = True
                strServiceStatus = "Service Already Running"
            Case 11    'Service Database Locked
                blnServiceStatus = False
                strServiceStatus = "Service Database Locked"
            Case 12    'Service Dependency Deleted
                blnServiceStatus = True
                strServiceStatus = "Service Dependency Deleted"
            Case 13    'Service Dependency Failure
                blnServiceStatus = False
                strServiceStatus = "Service Dependency Failure"
            Case 14    'Service Disabled
                blnServiceStatus = True
                strServiceStatus = "Service Disabled"
            Case 15    'Service Logon Failure
                blnServiceStatus = False
                strServiceStatus = "Service Logon Failure"
            Case 16    'Service Marked For Deletion
                blnServiceStatus = True
                strServiceStatus = "Service Marked For Deletion"
            Case 17    'Service No Thread
                blnServiceStatus = False
                strServiceStatus = "Service No Thread"
            Case 18    'Status Circular Dependency
                blnServiceStatus = False
                strServiceStatus = "Circular Dependency"
            Case 19    'Status Duplicate Name
                blnServiceStatus = False
                strServiceStatus = "Duplicate Name"
            Case 20    'Status Invalid Name
                blnServiceStatus = False
                strServiceStatus = "Invalid Name"
            Case 21    'Status Invalid Parameter
                blnServiceStatus = False
                strServiceStatus = "Invalid Paramenter"
            Case 22    'Status Invalid Service Account
                blnServiceStatus = False
                strServiceStatus = "Invalid Service Account"
            Case 23    'Status Service Exists
                blnServiceStatus = True
                strServiceStatus = "Service Exists"
            Case 24    'Service Already Paused  
                blnServiceStatus = True
                strServiceStatus = "Already Paused"
        End Select
End Sub 

And there you have it.  A nice and robust sub for handling services.  Remember, you can use this in a local script too.  Just use "." as the computer name.  :)


Happy coding!