Saturday, May 03, 2008

Windows Services Management via VBScript

If you have ever used any Unix/Linux based systems you know that windows does not even come close to providing as reliable service management as its counterparts. I have been burnt  by the stuck services issue so many times that it was natural for me to look for alternate mechanisms.

VB script is a scripting language developed by Microsoft and is a limited variation of Visual Basic programming language. To me its a much better and more powerful alternative to Batch Scripting.

Being new to VBScript i had to spend some time initially to grasp the basics but when i did it was quite easy. Here is a simple VBscript to manage windows services.  You just need to modify the number of services to manage and their names and the script lets you bulk start/stop, check status and individually control each service. Thankfully since i have used this script i have not experienced the stuck services issue and i am strongly inclined to believe that most services start/stop issues may be caused by bugs in the GUI based Windows Services Manager (this is just speculation and i have no conclusive evidence to prove it).

Execute the following from your command prompt to run this script:
cscript [path to script]

The script:

============================================================

dim input
dim strComputer
dim svrList


rem Main Body

input = 0
do
    input = getInput()

    processInput(input)
loop until input=5

rem Supporting Functions


function processInput(input)

    if input = "5" then
        s_quit()

    else
        strComputer = "."
        
        ' Modify this array size to add or remove services. The length of this array should be    
        ' exactly same as the number of services.
        ' Note: If you want to initialize this array to hold 4 services, set its size to 3. The array
        ' like most has a zero based index i.e. 0 to 3.
        dim myservices(3)

        ' specify the actual service names here
        myservices(0)="<service-mgmt1>"
        myservices(1)="<service-mgmt2>"
        myservices(2)="<service-mgmt3>"
        myservices(3)="<service-mgmt4>"

        'get service object
        Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
        
        'debug statement
        'wscript.echo cstr(ubound(myservices))
        
        k = 0
        svrList = ""
        for each service in myservices
            svrList = svrList & "Name='" & service & "'"
            
            ' do not end the services string with an 'or' this causes the query to fail
            if k < ubound(myservices) then
                svrList = svrList & " or "
            end if
            
            k = k+1
        next
        
        'debug statement
        'wscript.echo svrList
        
        Set colServiceList = objWMIService.ExecQuery("Select * from Win32_Service where " & svrList)

        ' debug statement
        'for each s in colServiceList
        '    WScript.Echo s.name
        'next
        
        select case input

            case "1"
                staggard_start(colServiceList)
            case "2"
                startSrv(colServiceList)
            case "3"
                stopSrv(colServiceList)
            case "4"
                statusSrv(colServiceList)
            case else
                Wscript.echo "Invalid Input!"
                's_quit()
                
        end select

    end if
end function


rem Quit Script
function s_quit()
    WScript.Echo "bye!"
    WScript.Quit
end function


rem Fetch script option
function getInput()
    WScript.echo
    WScript.echo "Select one of the options below:"
    WScript.echo "1 - Staggard Start"
    WScript.echo "2 - Start services"
    WScript.echo "3 - Stop service"
    WScript.echo "4 - Service status"
    WScript.echo "5 - Exit"
    getInput = textInput("Input = > ")
end function


rem Fetch user input
function textInput(prompt)
    WScript.StdOut.Write prompt
    textInput = WScript.StdIn.ReadLine
    rem WScript.StdOut.WriteLine username
end function


rem Staggard Start services
function staggard_start(serviceObjs)

    WScript.Echo "staggard start :: 1 - start; 2 - stop; 3 - ignore; q - quit"
    flag = "0"
    
    do
        For each serviceObj in serviceObjs

            flag = textInput(serviceObj.name & " -> ")

            select case flag

                case "1"
                    errReturn = serviceObj.StartService()
                    'WScript.Echo errReturn
                    WScript.Sleep 15000

                    if errReturn=0 then
                        WScript.Echo " ...started service"
                    else
                        WScript.Echo " ...failed to start service/running already"
                    end if

                case "2"
                    errReturn = serviceObj.StopService()
                    'WScript.Echo errReturn
                    WScript.Sleep 15000

                    if errReturn=0 then
                        WScript.Echo " ...stopped service"
                    else
                        WScript.Echo " ...failed to stop/not-running service"
                    end if

                case "q"
                    's_quit()
                    exit do

                case else
                   WScript.Echo " ...ignored"

            end select
        Next        
    loop
    
end function


rem Start services
function startSrv(serviceObjs)

dim tempObj
WScript.Echo "starting services ..."
    For each serviceObj in serviceObjs
    
        errReturn = serviceObj.StartService()
        'WScript.Echo errReturn
        WScript.Sleep 15000

        if errReturn=0 then
            WScript.Echo "started service - " & serviceObj.name
        else
            WScript.Echo "failed to start/running already service - " & serviceObj.name
        end if
            
    Next
        
end function


rem Stop services
function stopSrv(serviceObjs)

WScript.Echo "stopping services ..."
    For each serviceObj in serviceObjs
        errReturn = serviceObj.StopService()
        'WScript.Echo errReturn
        WScript.Sleep 15000

        if errReturn=0 then
            WScript.Echo "stopped service - " & serviceObj.name
        else
            WScript.Echo "failed to stop/not-running service - " & serviceObj.name
        end if

    next    
    
end function


rem Service status
function statusSrv(serviceObjs)

WScript.Echo "Service Status"
    For each serviceObj in serviceObjs
        WScript.Echo "Name: " & serviceObj.name
        WScript.Echo "State:" & serviceObj.State
    next
    
end function

===========================================================

Hope this script helps you alleviate some of your windows services woes.

Disclaimer: I am not a VBScript developer. If you find any bad coding practices please do let me know and i will be more than happy to fix my script. Also the exception handling could be done in a much better fashion.