Jump to content

Is it possible to check the status for multiple remote computers at once?


Recommended Posts

Hi,

I'm trying to find a way to run a command on several computers at once, but so far my solution is to use batch files for part of the script.

One thing I try to do is check if the computers are online, but I do not wish to wait for a response from each computer before checking the next. In this case I now use a batch file with a "for" loop and calling another batch file using "start /b". Then I use a Third batch file to collect the data in a single log file I can display. It's not a pretty process, but it works.

Func CheckFileExist()
    DirRemove("tmp", 1)
    RunWait("Process1.bat", "", @SW_HIDE)
    For $i = 0 To 90
        GUICtrlSetData($NetworkProgressBar, $i)
        Sleep(30)
    Next
    RunWait("Process2.bat", "", @SW_HIDE)
    GUICtrlSetData($NetworkProgressBar, 95)
    _ReplaceStringInFile("tmp\temp.2tmp", "|0", "|Online")
    _ReplaceStringInFile("tmp\temp.2tmp", "|1", "|!.....Offline.....!")
    _FileReadToArray("tmp\temp.2tmp", $aNetworkOutput)
    DirRemove("tmp", 1)
    _GUICtrlListView_DeleteAllItems($NetworkListView)
EndFunc   ;==>CheckFileExist

Process1.bat

@echo off
for /f %%a in (list.txt) do start /b CheckForFile.bat %%a

CheckForFile.bat

@echo off
dir \\%1\c$\octopus\bin\appmon.exe > nul 2<&1
echo %1^|%errorlevel% > %1.tmp
exit

 Process2.bat

@echo off
for %%b in (*.tmp) do type %%b >> temp.2tmp
del *.tmp -Y

List.txt is a list of the computers in the network.

Is there a way to acheive this using only AutoIt?

 

Another case I do a similar thing is when checking cpu load.

I use 2 batch files for this.

Func GetLoad()
    DirRemove("tmp", 1)
    RunWait("cpuload1.bat", "", @SW_HIDE)
    For $i = 0 To 99
        GUICtrlSetData($LoadProgressBar, $i)
        Sleep(80)
    Next
    RunWait("cpuload2.bat", "", @SW_HIDE)
    _FileReadToArray("tmp\cpuload.2tmp", $aLoadOutput)
    DirRemove("tmp", 1)
    _GUICtrlListView_DeleteAllItems($LoadListView)
EndFunc   ;==>GetLoad

cpuload1.bat

@echo off

REM Delete any old files
rmdir tmp /s/ /q 2>nul

REM Creating directory for tmp files
mkdir tmp 2>nul

REM Get processor time value
for /f %%i in (list.txt) do start "" /b typeperf \\%%i "Processor(_Total)\%% processor time" -sc 4 -o tmp\%%i.tmp -y >nul

cpuload2.bat

REM @echo off
setlocal enabledelayedexpansion

REM Extract and show relevant processor value
for /f %%a in (list.txt) do (
for /f tokens^=4^ delims^=.^"^ skip^=4 %%b in (tmp\%%a.tmp) do @echo %%a^|%%b %%^|!time!
) >> tmp\cpuload.2tmp

Same thing here, I would like to do this using only AutoIt, and avoid using temporary files.

Link to comment
Share on other sites

You mean online / offline when remote system is pingable? If yes you can use Ping function but this will work only sequentially.

Br,

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

I had a similar project a while back, but it was to check to see if a user was logged on or not.  Since AutoIt is not multi-threaded, I used multi-processing.  I created a small script to just check the logged on user status using WMI and PLINK.  I then used the main script to run the smaller script for each computer name.  It would loop through a list of computer names and check around 120 computers at nearly the same time, and have a time out (20 s) to close any open processes.  I used the exit codes of the smaller script to determine if the user was logged on or not.  On average it took about 40 seconds to a complete a loop.  Since you are just checking online status, it shouldn't be as complicated.  

 

Adam

Link to comment
Share on other sites

Hi MortenM

if you want ping a lot of computers, you can use >this UDF (it pings up to 20-25 clients in parallel)

with that, you can also perform your own routine against each client that responds to the ping as soon as you get the ping response by just passing the name of your function to the udf.

a simple example of use is included there.

>here another simple example of use (view onlin/offline clients by green/red boxes)

Edited by Chimp

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

Thanks, I will look into both these suggestions.

I have just below 100 computers I want to get the status from.

Why is there a limitation on the amount of computers you can ping in parallel with the multiping UDF?

Do you have any suggestions on how I can get CPU load of the remote computers in a better way?

I would also need to run this on many computers in parallel, but I can adjust the multiping UDF or use multiprocessing to acheive this.

Thank you.

Link to comment
Share on other sites

Thanks, I will look into both these suggestions.

I have just below 100 computers I want to get the status from.

Why is there a limitation on the amount of computers you can ping in parallel with the multiping UDF?

Do you have any suggestions on how I can get CPU load of the remote computers in a better way?

I would also need to run this on many computers in parallel, but I can adjust the multiping UDF or use multiprocessing to acheive this.

Thank you.

 

Hi MortenM

I think that if you spawn too many ping processes simultaneously, then performances will worsen instead of improve (however you can modify the line  Local $MAX_PROCESS = 20 in that UDF if you want test different values)

anyway, the limit of 20-25 is on the simultaneously running ping and not on the total number of IP that you can ping. They are executed 20 at a time and in few second you will get result of all of your 100 devices.

In addition, I also "disconnected" from the whole MultiPing, only a general portion to run at the same time not only ping commands, but any list of commands.

I will reorganize it a bit and will post here

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

this is what I did.. I have several computers and a server I use thats holds files for those computers... The client machines send a 'beacon' to the file that corisponds to that machine, and my personal computer keeps an eye on that list of files... 

example:

CLIENTs:

AdlibRegister ( "beacon" , 90000)
Global $LiveFile = "\\MyServer\TEMP\" & @computername & ".ini"

; Code that puts all sorts of into ino the ini file for me

Func beacon()
FileSetTime($LiveFile, "" )
EndFunc

On the server, I have a list view that shows all files in a list ( not including the ini ), along with the details I need, and finally the last modified date and time. FileSetTime uses VERY little bandwidth, and updates the last updated time of the ini file for that machine so I know when it was last touched.

 

 

example of the function I used for my update list on my personal client machine:

func RefreshCompList() ; READY
clearit() ; clears lists
$FileList = ""
$FileList =_FileListToArray("\\MyServer\TEMP")
$fileloc = "\\MyServer\TEMP\"

for $i = 1 to ubound($FileList) - 1
local $inifile = $FileList[$i]
 If Stringinstr(Stringreplace($inifile,".ini",""), _GUICtrlListView_GetItemTextArray($MachList,0)) then ContinueLoop
if FileGetTime($fileloc & $FileList[$i], $FT_MODIFIED, 1) then
$modtime = DTFormat(FileGetTime($fileloc & $FileList[$i], $FT_MODIFIED, 1))
else
$modtime = "Unknown"
endif
    $stat = IniRead($fileloc & $FileList[$i], "Status", "Current_Status", "TBD")
    
        $DateVar = _DateDiff( 's',FileDTFormat(FileGetTime($fileloc & $FileList[$i], $FT_MODIFIED, 1)) ,_NowCalc())
    GUICtrlCreateListViewItem( Stringreplace($inifile,".ini","") & "|" & $stat & "|" & $modtime , $MachList)
    
    
     GUICtrlSetBkColor(-1, 0xA3FF75)
     If $DateVar > 120 then GUICtrlSetBkColor(-1, 0xFFF79)
     If $DateVar > 180 then GUICtrlSetBkColor(-1, 0xFF9933)
     If $DateVar > 240 then GUICtrlSetBkColor(-1, 0xFF0000)

    
    
next
;_ArrayDisplay($FileList,"$FileList")
endfunc

Obviously you would have the change the variables as needed

Edited by Kovacic

C0d3 is P0etry( ͡° ͜ʖ ͡°)

Link to comment
Share on other sites

Thanks for the great replies. I am trying to understand the code and simplify it to suit my needs instead of just copying the functions.

I will update with my code when I have something that may work.

Link to comment
Share on other sites

This is what I ended up doing, and it works great:

GUICreate("Network test", 500, 500)

$NetworkUpdateBtn = GUICtrlCreateButton("Update", $NetworkLeft - 50, $GuiHeight - 50, 65, 30)
$NetworkProgressBar = GUICtrlCreateProgress($NetworkLeft + 20, $GuiHeight - 50, $GuiWidth - 100, 30)

GUISetFont(8)
$NetworkListView = GUICtrlCreateListView("Name|IP|Status", $NetworkLeft - 50, $NetworkTop, $GuiWidth - 30, $GuiHeight - 80)

_GUICtrlListView_SetColumnWidth($NetworkListView, 0, 130)
_GUICtrlListView_SetColumnWidth($NetworkListView, 1, 130)
_GUICtrlListView_SetColumnWidth($NetworkListView, 2, 130)
Dim $NET_DESCENDING[_GUICtrlListView_GetColumnCount($NetworkListView)]

GUISetState(@SW_SHOW)

While 1
    $msg = GUIGetMsg()

    Select
        Case $msg = $GUI_EVENT_CLOSE
            ExitLoop

        Case $msg = $NetworkUpdateBtn
            $PingArray = _nPing($aCompNameIP, 1, 0, 0, Default)
            _ArrayDelete($PingArray, 0)

            For $n = 0 To UBound($aCompNameIP) - 1
                _GUICtrlListView_AddItem($NetworkListView, $aCompNameIP[$n][0], -1, $n + 9999)
                _GUICtrlListView_AddSubItem($NetworkListView, $n, $aCompNameIP[$n][1], 1)
                If $PingArray[$n][2] = -1 Then
                    $PingArray[$n][2] = "Offline"
                Else
                    $PingArray[$n][2] = "Online - Ping " & $PingArray[$n][2] & "ms"
                EndIf
                _GUICtrlListView_AddSubItem($NetworkListView, $n, $PingArray[$n][2], 2)
            Next

        Case $msg = $NetworkListView
            _GUICtrlListView_SimpleSort($NetworkListView, $NET_DESCENDING, GUICtrlGetState($NetworkListView))
    EndSelect
WEnd

Thanks for all the help.

I still need to figure out how to fix the CPU load function without calling external batch files, but one Down at least :)

Link to comment
Share on other sites

Hi MortenM
Glad you achieved part of your goal by using the _nPing function in multiping.udf.
as I told in post #7, here is a scaled down version of the manadar's nping minimized and adapted to run any DOS command instead of only specialized to PING as the original (I called Multi_DOS() in the listing). It will spawn up to 25 command at time in parallel to speed up job.
I arranged a bit the listing with comments, but is still a bit a draft.
In this example I used the wmic command to get cpu load percentage from remote clients. I used 6 clients all with the same hostname (local client) just to show a proof of concept (I know that it's a nonsense)  but I had not idea of other hostnames to use as example. In real situations many remote clients will be used instead of course.

#include <Constants.au3>
#include <array.au3>

; example of array with 6 hostnames
; (this is an useless example because the 6 clients are all the same, just to show this example)
; in normal real situations the clients in the list are much more and all different of course
;
; the array can be filled by reading a file from disk, or by scanning a network using Multiping.au3 for example.
;
Local $onLine[6] = [@ComputerName, @ComputerName, @ComputerName, @ComputerName, @ComputerName, @ComputerName]
;
; few local commands just to test.
; now we prepare the array (must have 4 columns) that will hold commands to run against all clients 
Global $Commands[UBound($onLine)][4]

; we use the wmic command to read cpu load of all clients in the list
; so we fill the column 1 of the array with the following command
; (one line for each client)
;
For $i = 0 To UBound($onLine) - 1
    $Commands[$i][0] = $onLine[$i] ; name of the client just for reference
    $Commands[$i][1] = 'wmic /node:' & $onLine[$i] & ' cpu get loadpercentage /value'
Next
; this is the array with all commands personalized for each client
_ArrayDisplay($Commands, "before run" & @CRLF)

Multi_DOS($Commands) ; here we fire all commands running 25 at time

; and this is the array with columns 2 and 3 filled by the Multi_DOS udf
_ArrayDisplay($Commands, "after run" & @CRLF)

; the end

; --- here is a modified and reduced portion of nping by manadar ---
; --- adapted tu run any dos command instead of only PING        ---
;
; array must be a 2D arry with 4 columns [n][4] (dimension [n] as many elements as nr. of DOS commands to run
;
; the functions accepts an array ByRef loaded with commands to run in column 1 [n][1]
; the function in turn will fill the array elements [n][2] or [n][3] as follows:
;
; [n][2] with the autput of the StdOut of the passed command
; [n][3] with the autput of the StdErr of the passed command
;
;
; | [n][0]                  | [n][1] provided by user | [n][2] filled by func   | [n][3] ] filled by func |
; +-------------------------+-------------------------+-------------------------+-------------------------+
; | [user defined value]    | DOS command to run      | DOS outpu (StdOut)      | DOS error (StdErr)      |
; +-------------------------+-------------------------+-------------------------+-------------------------+

Func Multi_DOS(ByRef $cmd)
    If Not IsArray($cmd) Or UBound($cmd, 2) < 3 Then Return SetError(1) ; must be an array with second dim >= 3
    Local $MAX_PROCESS = 25 ; A maximum number of processes
    Local $iTotal = UBound($cmd) ; Number of commands to run
    Local $Process[$MAX_PROCESS][2] ; array to track the simultaneously running commands (internal use)
    ; [0] PID of DOS spawn
    ; [1] index to bind this process to the command index in the $cmd array

    For $i = 0 To $MAX_PROCESS - 1
        $Process[$i][0] = 0
        $Process[$i][1] = 0
    Next

    Local $i = 0
    Local $iFinished = 0 ; how many processes have finished run

    While 1
        For $n = 0 To UBound($Process) - 1 ; ; We check all the currently running processes
            ; Check if we need a spot, and there is an existing spot here
            If ($i <> $iTotal And $Process[$n][0] = 0) Then ; if there are still commands to be run and if there is a free spot
                ; Spawn a new process in the available spot
                $Process[$n][0] = Run(@ComSpec & " /c " & $cmd[$i][1], "", @SW_HIDE, $STDOUT_CHILD + $STDERR_CHILD) ; spawn a new command
                $Process[$n][1] = $i ; take trak of commands
                $i += 1 ; Increment $i so we can run next process next time around
            Else
                ; Check if this process has been spawned and the process is ready
                If $Process[$n][0] <> 0 Then ; is this command still running?
                    ; collect output from this command
                    $cmd[$Process[$n][1]][2] &= StdoutRead($Process[$n][0])
                    $cmd[$Process[$n][1]][3] &= StderrRead($Process[$n][0])

                    If (@error) Then ; has this command terminated?

                        $Process[$n][0] = 0 ; Free up an empty space for the next command to run
                        $iFinished += 1 ; Increment the counter of processes that have finished

                        ; possible to call() a function here to notify the end of this command
                        ; ando/or perform some action (a sort of "OnfFnished" event)

                        ;  Else

                    EndIf
                    If ($iFinished == $iTotal) Then ExitLoop 2 ; the end
                EndIf
            EndIf
        Next
        Sleep(50) ; Give existing commands some time to process the request
    WEnd ; the end of job
EndFunc   ;==>Multi_DOS
Edited by Chimp

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

I had a similar project a while back, but it was to check to see if a user was logged on or not.  Since AutoIt is not multi-threaded, I used multi-processing.  I created a small script to just check the logged on user status using WMI and PLINK.  I then used the main script to run the smaller script for each computer name.  It would loop through a list of computer names and check around 120 computers at nearly the same time, and have a time out (20 s) to close any open processes.  I used the exit codes of the smaller script to determine if the user was logged on or not.  On average it took about 40 seconds to a complete a loop.  Since you are just checking online status, it shouldn't be as complicated.  

 

Adam

Hi AdamUL

could you post that script?

thanks

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

Hi Chimp,

I currently do not have the full source with me, as it was part of a larger project.  I will look to see if I can find it when I get back to work.  The code would need to be cleaned up, as this was wrote with an older version of AutoIt, and has some proprietary code in it that i cannot release.  

I did post an example script for accessing iMac coumputer that I used in the project.  

 

Adam

Edited by AdamUL
Broken Link
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...