Jump to content

Delaying operation of function


shornw
 Share

Recommended Posts

Hi All,

Can one of the infinitely better brains out there, suggest a way of delaying the progress of a function while a service stops. I know I can use Sleep() but wondered if there's a more relevant method, as the process is being run accross a network.

I tried:

Do
$svc = _ServiceRunning($server, "Sophos Agent")
If $svc = 0 Then ExitLoop
Sleep(500)
until $svc = 0

but the service reports that it's not running straight away. As the script stops a service, deletes some files then starts the service again, I need it to wait until the service has entered the stopped state before attempting to delete the files.

this is what I have so far:

Func RWTest()
$svc = _ServiceRunning($server, "Sophos Agent")
If $svc = 1 Then
;MsgBox(0, $server, "stop service " & $server & " Sophos Agent")
_StopService($server, "Sophos Agent")
If @error Then MsgBox(16, "Service Control Failure", "The service control failed with error " & @error)
Sleep(5000)
Else
MsgBox(0, $server, "The Sophos Agent service is currently not running")
EndIf
Sleep(1000)
;$del = FileDelete($path & "*.msg")
;If $del = 0 Then MsgBox(16, "Delete Error", "Files were not deleted")
;MsgBox(0, $server, "Start service " & $server & " Sophos Agent")
_StartService($server, "Sophos Agent")
If @error Then MsgBox(16, "Service Control Start Failure", "The service control failed with error " & @error)
Sleep(2000)
$svc = _ServiceRunning($server, "Sophos Agent")
If $svc = 1 Then
MsgBox(0, "Service Control", "Sophos Agent service is running")
Return
Else
_StartService($server, "Sophos Agent")
EndIf

EndFunc
Edit- Is there any remote process monitoring within AutoIT. This script will be run from various PC's/Servers so I dont really want to use SysInternals or other 3rd party tools. Edited by shornw

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Link to comment
Share on other sites

Hi Hannes,

Firstly, thanks for the idea.

I don't think I explained myself very well. I can view the runstate and send a stop control, no problem. What I want to do is delay further execution until the service is in a completely stopped state, so that the files to be deleted have no filelocks.

if I send a stop command, then query the runstate (the Do / Until attempt), I get an inaccurate response because the service has begun to shutdown so gets reported as not running, although it is in fact still running.

My next idea was to monitor the process, but as far as I'm aware ProcessMGmnt() only works locally. As this is going to be run from all sorts of computers I dont want to use 3rd party tools or O/S specific controls.

Currently it seems to be OK with Sleep() (very limited testing carried out), but I feel this is too 'rigid' and may not allow for slower network connections / blips etc bearing in mind that this could be run from any part of the UK, unless I use a ridiculously long time, but that would make it unnecessarily slow.

Any suggestions gratefully considered

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Link to comment
Share on other sites

Maybe you could use AdlibRegister to periodically check if the service has already stopped.

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

I'd still hit the problem of incorrect reporting between sending the stop control and the process actually terminating. As far as I can see, I'm going to have to monitor the process rather than the service. It's now a question of how to achieve that, within my working parameters

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Link to comment
Share on other sites

Hey shornm,

as I said, you can query the state of a service with "sc". The service will transist from "RUNNING" over "STOPPING" to "STOPPED" (and reverse: "STOPPED" to "STARTING" to "RUNNING"). I think with this Information you can build your own "Sleep" function, right?

Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]
Link to comment
Share on other sites

Here's what I use:

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Fileversion=1.0.0.10
#AutoIt3Wrapper_Res_FileVersion_AutoIncrement=p
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Run_Tidy=y
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#cs ----------------------------------------------------------------------------
#
# AutoIt Version: 3.3.6.0
# Author:         hannes08
#
# Script Function:
#   Checks a specified service on a specified server. If it is not running in between a specified timeout period the script will exit with an error.
#
# Script Parameters:
#   CheckService.exe <server> <service> <timeout> [<condition>]
#       <server>        - i.e. "lifd01" or "172.19.2.200"
#       <service>       - i.e. "snmp" or "Lotus Domino Server (DData)"
#       <timeout>       - i.e. 300  -- value in Seconds!
#       [<condition>]           - 0 OR 1  --    0: Service has to be stopped to complete successfully
#                           1: Service has to be running to complete successfully
#                               Default value for optional parameter <condition> is 1 ("running")
#
#
#ce ----------------------------------------------------------------------------

#include <Constants.au3>
#include <Timers.au3>

ConsoleWrite("Starting (Version " & FileGetVersion(@ScriptName) & ")" & @CRLF)
If $CmdLine[0] = 3 Then
    $s_cond = "running"
ElseIf $CmdLine[0] = 4 Then
    If StringIsInt($CmdLine[4]) Then
        If $CmdLine[4] = 0 Then
            $s_cond = "stopped"
        ElseIf $CmdLine[4] = 1 Then
            $s_cond = "running"
        Else
            ConsoleWrite("Parameter <condition> has a wrong format." & @CRLF & "Expected: 0 or 1" & @CRLF & "Recieved: " & $CmdLine[4])
            Exit 5
        EndIf
    Else
        ConsoleWrite("Parameter <condition> has a wrong format." & @CRLF & "Expected: Integer: 0 or 1" & @CRLF & "Recieved: " & $CmdLine[4])
        Exit 6
    EndIf
EndIf

If StringInStr($CmdLineRaw, '""') Then
    ConsoleWrite("No Service specified. This could be by default." & @CRLF & "Exit" & @CRLF)
    Exit 0
EndIf

If $CmdLine[0] = 3 Or $CmdLine[0] = 4 Then
;~  MsgBox(0,"test"," /c sc " & $CmdLine[1] & " """ & $CmdLine[2] & """ | find /C /I ""state"" >> test.cmd")
    If Ping($CmdLine[1]) > 0 Then
        ConsoleWrite("Checking for service: """ & $CmdLine[2] & """ on server: """ & $CmdLine[1] & """" & @CRLF)
        $t = _Timer_Init()
        $b_stopped = False
        While _Timer_Diff($t) / 1000 <= $CmdLine[3]
            $rc = Run(@ComSpec & " /c sc " & $CmdLine[1] & " query """ & $CmdLine[2] & """ | find /C /I """ & $s_cond & """", @ScriptDir, @SW_MINIMIZE, $STDERR_CHILD + $STDOUT_CHILD)
            $s_line = ""
            $s_rc = ""
            While 1
                $s_line = StdoutRead($rc)
                If @error Then ExitLoop
                If StringStripWS($s_line, 3) <> "" Then
                    $i_sec = Floor(_Timer_Diff($t) / 1000)
                    If Mod($i_sec, 5) = 0 Then ConsoleWrite("Message after " & $i_sec & "s: " & StringStripWS($s_line, 3) & @CRLF)
                    If StringStripWS($s_line, 3) = 1 Then
                        $b_stopped = True
                        ConsoleWrite("State (""" & $s_cond & """) for service " & $CmdLine[2] & " has been successfully identified after " & $i_sec & " seconds." & @CRLF)
                    EndIf
                Else

                EndIf
            WEnd
            If $b_stopped = True Then ExitLoop
            Sleep(1000)
        WEnd
        If $b_stopped Then
            ConsoleWrite("Service is " & $s_cond & "!" & @CRLF)
            Exit 0
        Else
            ConsoleWrite("State (""" & $s_cond & """) for service has not been identified after " & $CmdLine[3] & "s of waiting ... Timeout encountered." & @CRLF)
            Exit 4
        EndIf
    Else
        ConsoleWrite("Remote machine is not available!" & @CRLF)
        Exit 3
    EndIf
ElseIf $CmdLine[0] = 0 Then
    ConsoleWrite("No Parameter given. This could be by default." & @CRLF & "Exit" & @CRLF)
    Exit 0
ElseIf $CmdLine[0] = 1 Then
    ConsoleWrite("No Service specified. This could be by default." & @CRLF & "Exit" & @CRLF)
    Exit 0
Else
    If StringInStr($CmdLineRaw, '""') Then
        ConsoleWrite("No Service specified. This could be by default." & @CRLF & "Exit" & @CRLF)
        Exit 0
    EndIf
    ConsoleWrite("Wrong Parameter count." & @CRLF & "Expected: 3 or 4 (Servername, Service, Timeout [, condition])" & @CRLF & "Recieved: " & $CmdLine[0] & @CRLF)
    Exit 1
EndIf
Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]
Link to comment
Share on other sites

Hi Hannes.

I have to be completely honest on two counts:

1. I wasn't aware that 'SC' reported quite so accurately. I have in the past used Net Start / Stop in .bat files but not SC. I thought it only appeared on later O/S's. I stand corrected and thank you for that

2. I was kinda hoping to have a simpler (in my mind cleaner) solution without having to split/strip and general handling of strings. My ideal would have been remote process monitoring, but I can work with this, so I'll make a start.

Thanks for the pointer and the sample you posted (although that's way more complex than I need it to be for this :oops: )

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Link to comment
Share on other sites

Hey shornw,

to make it easier and more proper for you:

#include <Constants.au3>

$pc = @ComputerName
$servicename = "MyService"
$s_line = ""
$rc = Run(@ComSpec & " /c sc " & $pc & " query """ & $servicename & """ | find ""STATE""", @ScriptDir, @SW_MINIMIZE, $STDERR_CHILD + $STDOUT_CHILD)
While 1
    $s_line &= StdoutRead($rc)
    If @error Then ExitLoop
WEnd
$s_line = StringStripWS($s_line, 7)
$a_temp = StringSplit($s_line, " ")

If $a_temp[0] > 2 Then
    Switch $a_temp[3]
        Case 1
            "Service State: STOPPED"
        Case 2
            "Service State: START_PENDING"
        Case 3
            "Service State: STOP_PENDING"
        Case 4
            "Service State: RUNNING"
    EndSwitch
EndIf
Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]
Link to comment
Share on other sites

  • 2 weeks later...

Or - save this as UDF:

$service = ""
ConsoleWrite(_SetServiceState(@ComputerName, $service, "Stop") & @LF)
Sleep ( 5000 )
ConsoleWrite(_SetServiceState(@ComputerName, $service, "Start") & @LF)
Func _SetServiceState($s_pc, $service, $State)
  Local Const $wbemFlagReturnImmediately = 0x10
  Local Const $wbemFlagForwardOnly = 0x20
  Local $colItems = "", $objItem, $ret_status = -1
  Local $a_status[25] = ["Success", "Not supported", "Access denied", "Dependent services running", _
      "Invalid service control", "Service cannot accept control", "Service not active", "Service request timeout", _
      "Unknown failure", "Path not found", "Service already stopped", "Service database locked", "Service dependency deleted", _
      "Service dependency failure", "Service disabled", "Service logon failed", "Service marked for deletion", "Service no thread", _
      "Status circular dependency", "Status duplicate name", "Status - invalid name", "Status - invalid parameter", _
      "Status - invalid service account", "Status - service exists", "Service already paused"]
  If Ping($s_pc) Then
    Local $objWMIService = ObjGet("winmgmts:" & $s_pc & "rootCIMV2")
    If @error Then
      MsgBox(16, "_SetServiceState", "ObjGet Error: winmgmts")
      Return
    EndIf
    $colItems = $objWMIService.ExecQuery ("SELECT * FROM Win32_Service", "WQL", _
     $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    If @error Then
      MsgBox(16, "_SetServiceState", "ExecQuery Error: SELECT * FROM Win32_Service")
      Return
    EndIf
    If IsObj($colItems) Then
      For $objItem In $colItems
     If $objItem.Name = $service Then
       Select
         Case $State = "Boot" Or $State = "System" Or $State = "Automatic" Or $State = "Manual" Or $State = "Disabled"
           $ret_status = $objItem.ChangeStartMode ($State)
         Case $State = "Stop"
           $ret_status = $objItem.StopService ()
         Case $State = "Start"
           $ret_status = $objItem.StartService ()
         Case $State = "Pause"
           $ret_status = $objItem.PauseService ()
         Case $State = "Resume"
           $ret_status = $objItem.ResumeService ()
         Case $State = "Delete"
           $ret_status = $objItem.Delete ()
       EndSelect
       ExitLoop
     EndIf
      Next
    EndIf
  EndIf
  If $ret_status <> -1 Then
    Return $a_status[$ret_status]
  Else
    SetError(1)
    Return $ret_status
  EndIf
EndFunc   ;==>_SetServiceState

Then in your script, for example:

_setservicestate("computer-name", "spooler", "stop")
MsgBox(0,"", "Complete")

The MsgBox will not pop-up until the function completes, signifying that the service has completely stopped.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...