Jump to content

Parallelize PSexec


Recommended Posts

Dear Ladies and Gentlemen,

I currently try to run one of our check-tools on several remote machines in parallel. The final goal is to have a "stack", a pre-defined number of psexec-processes (dependent of the machine's performance), running in parallel.

Manadar once helped me greatly to parallelize the ping command, and I try to do the same with psexec, but I'm stuck: The tool hangs after executing the first stack of commands. PSEXECSVC is started on the remote machines, but then nothing happens. If the service is killed manually there, the next stack of machines is processed seemingly correctly.

Here's my current code - does somebody of you have any idea?

#include <Constants.au3>

Global $s_CRLF = @CRLF
Global $a_Hosts[3] = ["HOST1", "HOST2", "HOST3"] ; replace with existing hosts
Global $s_RemoteCMD = "net user" ; just an example

_CheckOnlineStatus($a_Hosts, 2)



; Function Name _CheckOnlineStatus()
; ==================================================================================================
;
; Function Name:    _CheckOnlineStatus()
; Description:      Use psexec to execute checker on several systems
; Parameter(s):     $a_Hostnames, $i_MaxProcess
; Requirement(s):   AutoIt 3.3
; Return Value(s):  Currently none - proof of concept
; Author(s):        Manadar, cs-it-solutions
;
; ==================================================================================================
Func _CheckOnlineStatus($a_Hosts, $i_MaxProcess)

    ; Prepare the asynchronous execution
    Local Const $MAX_PROCESS = $i_MaxProcess ; We spawn a maximum of "$i_MaxProcess" processes at once
    Local $a_process[$MAX_PROCESS] ; An array to keep a reference to spawned processes; the following loop we fill it with 0
    For $i = 0 To UBound($a_process) - 1
        $a_process[$i] = 0
    Next

    Local $i = 0 ; A pointer to run through the $a_Hosts array
    Local $i_finished = 0
    While True

        ; Check on the current processes, and look if there is one finished for use with our next host in line (from $a_Hosts)
        For $n = 0 To UBound($a_process) - 1
            If ($i <> UBound($a_Hosts) And $a_process[$n] == 0) Then ; Check if we need a spot, and there is an existing spot
                ; There is an empty spot
                $a_process[$n] = _MSpsexec($a_Hosts[$i])
                $i += 1
            Else
                ; Something is running here, let's check on the output
                If ($a_process[$n] <> 0 And _MSpsexecIsReady($a_process[$n])) Then
                    ; We have an output here, let's get it!
                    $s_hostname = _MSpsexecGetHostname($a_process[$n])
                    $i_success = _MSpsexecGetResult($a_process[$n])
                    If ($i_success == "Yes") Then
                        ; Do some command line output
                        ConsoleWrite("PSexec: Worked on " & $s_hostname & "." & $s_CRLF)
                    Else
                        ; Do some command line output
                        ConsoleWrite("PSexec: Didn't work on " & $s_hostname & "." & $s_CRLF)
                    EndIf

                    ; Free up an empty space for the next machine
                    $a_process[$n] = 0
                    $i_finished += 1
                    If ($i_finished == UBound($a_Hosts)) Then
                        ExitLoop 2 ; Return
                    EndIf
                EndIf
            EndIf
        Next
        Sleep(50) ; Give existing commands some time to process the request

    WEnd

EndFunc   ;==>_CheckOnlineStatus

; Function Name _MSpsexec()
; ==================================================================================================
;
; Function Name:    _MSpsexec()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar, cs-it-solutions
;
; ==================================================================================================
Func _MSpsexec($hostname, $timeout = 50)

    Local $return_struc[4]
    ; [0] = Successful Execution: Yes/No
    ; [1] = The hostname originally used
    ; [2] = Process handle (for internal use only)
    ; [3] = Buffer (for internal use only)

    $s_PsexecCMD = "psexec /accepteula \\" & $hostname & " -u " & $hostname & "\Administrator -p PASSWORD " & $s_RemoteCMD
ConsoleWrite($s_PsexecCMD & $s_CRLF)

    $return_struc[1] = $hostname
    $return_struc[2] = Run($s_PsexecCMD, "", @SW_HIDE, $STDOUT_CHILD)

    Return $return_struc
EndFunc   ;==>_MSpsexec

; Function Name _MSpsexecIsReady()
; ==================================================================================================
;
; Function Name:    _MSpsexecIsReady()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar
;
; ==================================================================================================
Func _MSpsexecIsReady(ByRef $return_struc)
    Return ___MSpsexecReadOutput($return_struc)
EndFunc   ;==>_MSpsexecIsReady

; Function Name _MSpsexecGetResult()
; ==================================================================================================
;
; Function Name:    _MSpsexecGetResult()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar
;
; ==================================================================================================
Func _MSpsexecGetResult($return_struc)
    Return $return_struc[0]
EndFunc   ;==>_MSpsexecGetResult

; Function Name _MSpsexecGetHostname()
; ==================================================================================================
;
; Function Name:    _MSpsexecGetHostname()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar
;
; ==================================================================================================
Func _MSpsexecGetHostname($return_struc)
    Return $return_struc[1]
EndFunc   ;==>_MSpsexecGetHostname

; Function Name ___MSpsexecReadOutput()
; ==================================================================================================
;
; Function Name:    ___MSpsexecReadOutput()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar, cs-it-solutions
;
; ==================================================================================================
; Internal use only
Func ___MSpsexecReadOutput(ByRef $return_struc)
    $data = StdoutRead($return_struc[2])
    If (@error) Then
        ___MSpsexecParseResult($return_struc)
        Return 1
    Else
        $return_struc[3] &= $data
        Return 0
    EndIf
EndFunc   ;==>___MSpsexecReadOutput

; Function Name ___MSpsexecParseResult()
; ==================================================================================================
;
; Function Name:    ___MSpsexecParseResult()
; Description:
; Parameter(s):
; Requirement(s):
; Return Value(s):
; Author(s):        Manadar, cs-it-solutions
;
; ==================================================================================================
; Internal use only
Func ___MSpsexecParseResult(ByRef $return_struc)
    $result = StringRegExp($return_struc[3], "error code ([0-1]*)", 3)
    If @error Then
        $return_struc[0] = "No"
    Else
        $return_struc[0] = "Yes"
    EndIf
EndFunc   ;==>___MSpsexecParseResult

Best Regards,

Chris

Edited by cherdeg
Link to comment
Share on other sites

The function Func _MSpsexec($hostname, $timeout = 50) add to the psexec the following switches:

-d meaning don't wait for process to terminate.

-i meaning run the program so that it interacts with the desktop.

I notice some time depending which command I'm try to run with psexec if I don't add -i the process freeze at the remote computer.

AutoIt Scripts:NetPrinter - Network Printer UtilityRobocopyGUI - GUI interface for M$ robocopy command line
Link to comment
Share on other sites

The function Func _MSpsexec($hostname, $timeout = 50) add to the psexec the following switches:

-d meaning don't wait for process to terminate.

-i meaning run the program so that it interacts with the desktop.

I notice some time depending which command I'm try to run with psexec if I don't add -i the process freeze at the remote computer.

-i helps - thank you!

-d can't be used because in my case: in a later iteration of this proof of concept I'm gonna copy certain result files from the remote machines; which can only be done after psexec has terminated after the "remote executed tool" is finished.

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...