Jump to content
Sign in to follow this  
therks

Exit code + StdoutRead/StderrRead

Recommended Posts

therks

Is there any way to retrieve the exit code from a process while also being able to use StdoutRead/StderrRead?

Share this post


Link to post
Share on other sites
AdamUL

Have a look at this example that pulled from this and edited.

Example.au3

#include <Constants.au3>
#include "ProcessExitCode.au3"
 
$iPid = Run(@ComSpec & ' /c dir /g', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$hHandle = _ProcessGetHandle($iPid)
ShowStdOutErr($hHandle)
$iExitCode = _ProcessGetExitCode($iPid)
_ProcessCloseHandle($hHandle)
MsgBox(0, "Program returned with exit code:", $iExitCode)
 
$iPid = Run(@ComSpec & ' /c dir', @WindowsDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)
$hHandle = _ProcessGetHandle($iPid)
ShowStdOutErr($hHandle)
$iExitCode = _ProcessGetExitCode($hHandle)
_ProcessCloseHandle($hHandle)
MsgBox(0, "Program returned with exit code:", $iExitCode)
 
Func ShowStdOutErr($l_Handle, $ShowConsole = 1)
    Local $Line, $tot_out, $err1 = 0, $err2 = 0
    Do
        Sleep(10)
        $Line = StdoutRead($l_Handle)
        $err1 = @error
        $tot_out &= $Line
        If $ShowConsole Then ConsoleWrite($Line)
        $Line = StderrRead($l_Handle)
        $err2 = @error
        $tot_out &= $Line
        If $ShowConsole Then ConsoleWrite($Line)
    Until $err1 And $err2
    Return $tot_out
EndFunc   ;==>ShowStdOutErr

ProcessExitCode.au3

#include-once
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessGetHandle()
; Description ...: Returns a handle from use of Run().
; Syntax.........: _ProcessGetHandle($iPID)
; Parameters ....: $iPID - ProcessID returned from a Run() execution
; Return values .: On Success - Returns Process handle while Run() is executing (use above directly after Run() line with only PID parameter)
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum)
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ProcessGetHandle($iPID) ;Return handle of given PID
    Local Const $PROCESS_QUERY_INFORMATION = 0x0400
    Local $avRET = DllCall("kernel32.dll", "ptr", "OpenProcess", "int", $PROCESS_QUERY_INFORMATION, "int", 0, "int", $iPID)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return $avRET[0]
    EndIf
EndFunc   ;==>_ProcessGetHandle
 
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessCloseHandle()
; Description ...: Closes a handle from use of Run().
; Syntax.........: _ProcessCloseHandle($hProc)
; Parameters ....: $hProc - Process handle
; Return values .: On Success - Closes Process handle after a Run() has executed.;
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum), PsaltyDS
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ProcessCloseHandle($hProc) ;Close process handle
    Local $avRET = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_ProcessCloseHandle
 
; #FUNCTION# ====================================================================================================================
; Name...........: _ProcessGetExitCode()
; Description ...: Returns a handle/exitcode from use of Run().
; Syntax.........: _ProcessGetExitCode($hProc)
; Parameters ....: $hProc   - Process handle
; Return values .: On Success - Returns Process Exitcode when Process does not exist.
;                 On Failure - 0
; Author ........: MHz (Thanks to DaveF for posting these DllCalls in Support Forum), PsaltyDS
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ===============================================================================================================================
Func _ProcessGetExitCode($hProc) ;Get process exit code from handle
    Local $t_ExitCode = DllStructCreate("int")
    Local $avRET = DllCall("kernel32.dll", "int", "GetExitCodeProcess", "ptr", $hProc, "ptr", DllStructGetPtr($t_ExitCode))
    If @error Then
        Return SetError(1, 0, 0)
    Else
        Return DllStructGetData($t_ExitCode, 1)
    EndIf
EndFunc   ;==>_ProcessGetExitCode

Adam

Share this post


Link to post
Share on other sites
therks

Thanks, that works perfectly. And I can use _WinAPI_OpenProcess() and _WinAPI_CloseHandle() from the WinAPI.au3 include. Sorry for the horrendous reply time, I don't get back here often.

Share this post


Link to post
Share on other sites
castens

This a simpler quick and dirty way

FileDelete("C:\temp\errorlevel.txt")

$file = fileopen(@TempDir & "\CMD.bat",2)
FileWrite($file,"start /wait c:\temp\test2.exe" & @CRLF)
FileWrite($file,"echo %errorlevel% > C:\temp\errorlevel.txt" & @CRLF)
FileClose($file)

$PID = run(@TempDir & "\CMD.bat")


While ProcessExists($PID)
wend

$file = fileopen("C:\temp\errorlevel.txt",0)
msgbox(0,"",fileread($file))
fileclose($file)
Edited by castens

Share this post


Link to post
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
Sign in to follow this  

  • Similar Content

    • nacerbaaziz
      By nacerbaaziz
      Hello
      i have searched a lot about how to run external programs with the administrator privileges without the script running with administrator privileges using autoit
      But all my attempts failed
      Finally, today I found the VBS function doing this task
      I immediately transferred it to our beloved language (autoit) and i decided to share it with you
      i hope you like it
      This is a simple example about how to use the function

      runAsAdmin("cmd.exe", "/c @echo off & cls & echo test & pause", "c:\", @sw_show)
      this is the function

      func runAsAdmin($program, $parameters = "", $workingDir = @workingDir, $show = "") local $oShell = OBJCreate("Shell.Application") if isOBJ($oShell) then local $result = $oShell.ShellExecute($program, $parameters, $workingDir, "runas", $show) else $result = false endIf return $result endFunc
       
    • rudi
      By rudi
      Hello,
      to provide an easy to use starter to capture traffic on all NICs found, I can successfully get all the interfaces of TSHARK.EXE (the command line version that's automatically installed along with wireshark) with this script:
      #include <AutoItConstants.au3> #include <Array.au3> $TS_WD = "C:\Program Files\Wireshark" $TS_exe = $TS_WD & "\tshark.exe" if not FileExists($TS_exe) Then MsgBox(48,"Fatal Error","No Wireshark Commandline Tool ""TSHARK.EXE"" found:" & @CRLF & _ $TS_exe) Exit EndIf $DString = "" $PIDGetIFs = Run($TS_exe & " -D", $TS_WD, @SW_HIDE, $STDERR_MERGED) While ProcessExists($PIDGetIFs) $DString &= StdoutRead($PIDGetIFs) WEnd ; MsgBox(0,"IFs",$DString) $aNICs = StringSplit($DString, @CRLF, 1) _ArrayDisplay($aNICs) $RegExIF = "^(?:\d+\. )(\\.*?})(?: \()(.*?)(\))$" ; $1 = TSHARK Interface Name, $2 = Windows Interface Name ; ... get the names to run TSHARK with the appropriate interface string  
      When I run TSHARK.EXE using this line directly, I see a continuously growing number telling the number of packets captured so far.
      "C:\Program Files\Wireshark\tshark.exe" -i \Device\NPF_{AEB931E9-E5FA-4DA5-8328-D87BDF53805C} -b duration:300 -b files:600 -w "y:\TShark-Ringbuffer\LAN-Verbindung\TSHARK-Com-0317_17---LAN-Verbindung___.pcap" Using this script, I *DO* see the first output line "Capturing on 'LAN-Verbindung'", but I cannot get hold of the continuously growing number of packets captured so far.
      #include <AutoItConstants.au3> $WD="C:\Program Files\Wireshark" $CMD='"C:\Program Files\Wireshark\tshark.exe" -i \Device\NPF_{AEB931E9-E5FA-4DA5-8328-D87BDF53805C} -b duration:300 -b files:600 -w "y:\TShark-Ringbuffer\LAN-Verbindung\TSHARK-Com-0317_17---LAN-Verbindung___.pcap"' ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $CMD = ' & $CMD & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $PID=Run($CMD,$WD,@SW_SHOW,$stderr_merged) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $PID = ' & $PID & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $OutputAll="" While ProcessExists($PID) $output=StdoutRead($PID) $OutputAll&=$output ToolTip($OutputAll) if $output <> "" then ConsoleWrite("""" & $output & """" & @CRLF) Sleep(1000) WEnd ConsoleWrite("Process vanished" & @CRLF)  
      This is the output of SciTE, when I let TSHARK.EXE run for a short while, the "close" it's "box" ...
       
      --> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop @@ Debug(10) : $CMD = "C:\Program Files\Wireshark\tshark.exe" -i \Device\NPF_{AEB931E9-E5FA-4DA5-8328-D87BDF53805C} -b duration:300 -b files:600 -w "y:\TShark-Ringbuffer\LAN-Verbindung\TSHARK-Com-0317_17---LAN-Verbindung___.pcap" >Error code: 0 @@ Debug(13) : $PID = 10948 >Error code: 0 "Capturing on 'LAN-Verbindung' " Process vanished  
      Howto catch the "growing-packet-number" TSHARK.EXE is writing continuously to the same "window position"???
       
       
      Regards, Rudi.
       


    • PoojaKrishna
      By PoojaKrishna
      Hi friends,
      The Run command on my machine suddenly stopped execution.
      Anyone of you facing the same issue?
      #include <AutoItConstants.au3> #include <FileConstants.au3.> #RequireAdmin $ExeName = FileOpenDialog("Select AutoIt executable", @ScriptDir & "\", "(*.exe)", $FD_FILEMUSTEXIST) If not @error Then If FileExists($ExeName) Then $iPID = Run($ExeName, "", @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD) If @error Then msgbox(0,"Failed", "Failed execution with @error: " & @error) EndIf Else Msgbox(0,"", "File does not exist") EndIf EndIf The above code always fails to execute the executable file. It was working perfect and stopped working now.
      I have tried adding the files and folders to windows defender exclusion list and uninstalling the anti virus but still no luck.
      OS: Windows 10 - 64 bit
      Please help.
       
    • rudi
      By rudi
      Hello,
      for a script to display PDF files I'd like to simply use the default program for PDF files, so I used "ShellExecute(<pdf-file-full-path>)" to open these files.
       
      The result for *SOME* of the workstations is, that the Adobe Reader starts up with asking for its language. (English/German). When starting AcroRd32.exe through "ShellExecute()", this "choose your language" dialog is showing up *ALWAYS*.
       
      Just to have mentioned it: Process Explorer is presenting this command line, it looks the same for both, PCs with and without that question "Choose Language? [English|German]"
      "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" --channel=4680.0.860715181 --type=renderer "\\pc0009\Y_DRV_H\Daten\TIF\08\32\G000110832_Freigegeben.idw.pdf"  
      The next approach I thought of was to use Foxit Portable (instead of Acrord32.exe), started from a Network Drive, but it's starting up ugly slowly...
      So I tried to "Run()" instead to "ShellExecute()" the Adobe Reader. Now the result looks more stange, the "select your language" dialog shows up every now and then, but not always for the Win7 installations affected.
       
      If I place a "msgbox()" just in front of the "run()" command, it seems never to show this "select your language" dialog.
      If I take out this MsgBox() the "select your language" dialog shows up sometimes.
      When I "ClipPut()" the run command prior the "Run()" and paste that one to a CMD box, then it seems to *NEVER* happen, that this "select your language" dialog shows up.
       
      "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" "\\pc0009\Y_DRV_H\Daten\TIF\08\32\G000110832_Freigegeben.idw.pdf" $AcroRead='"C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"' $PDF='"Y:\Temp\DRV_H\Daten\TIF\33\85\153385_Freigegeben.dwg.pdf"' MsgBox(0,"Values",$AcroRead & @CRLF & $PDF,1) $MyCommand=$AcroRead & " " & $PDF ClipPut($MyCommand) Run($MyCommand)  
      It looks like, that this "--channel=... --type=renderer" parameters are always fact for the AcroRd32.exe instance, that is opening the PDF to be displayed. The Instance opening the "PDF Display GUI" seems to always be a child process of another AcroRd32.exe process.
       
      Any clue, what's going on "backstage" here? How to avoid this "Choose your language" dialog? Or maybe someone can mention a different "portable" PDF viewer, I could use for this purpose?  
      Any suggestions appreciated, regards, Rudi.
    • ModemJunki
      By ModemJunki
      OK, the odd stuff seems to happen to me. Not sure if this belongs here or in the deployment forum.
      The Question: Why would the console output results from a command-line tool need to know the working dir on one system but not the other?
      Though in the end I solved the issue I still am not understanding why StdoutRead seems to behave differently as I describe below.
      Preamble: Windows 10 image deployment to two different HP workstation hardware platforms. After deployment set up some disk space using Intel RAID. I script the Intel RSTe client (Intel® Rapid Storage Technology enterprise). Same version of the RSTe client and same storage controller hardware (Intel C600+/C220+ series chipset SATA RAID controller). The only difference is in the driver - one system has 4.2.0.1136 and the other has 5.2.0.1194, but even after I update the older driver the anomaly persists. There are of course other differences - the older system has different CPUs (Xeon E5-2620 vs Xeon Silver 4108), different chipsets, different SMBIOS, etc..). Both have Nvidia Quadro cards with driver 385.90, but the older has 3x P2000 cards and the newer has 3x Quadro M4000 and a Quadro K1200.
      To script RAID creation and maintenance I have a function that uses StdoutRead with Intels command line client tool "rstcli64.exe".
      On the older system, the below call to StdoutRead fails. On the newer system, it works. This only started happening on the older hardware when I updated the Windows version 1607 image to build 14393.2189 (but the Windows image used is the same for both hardware targets).
      $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) But if I change it to use @ScriptDir as the working dir, it works for both systems.
      $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, @ScriptDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)  The code below is the one that works on both systems (hint: the comment " ; this only deals with one device" is because I've no hardware with more than one ATAPI device to test with).
      $s_RSTExe = ".\rstcli64.exe" ; for production (compiled executable) ; #FUNCTION# ==================================================================================================================== ; Name ..........: GetDiskInfoFromRSTE() ; Description ...: Queries for hard disks attached to the controller ; Syntax ........: GetDiskInfoFromRSTE() ; Parameters ....: None ; Return value...: An array of attached hard disk datas from the RST command line tool without ATAPI devices such as optical drives ; =============================================================================================================================== Func _GetDiskInfoFromRSTE() Local $s_RSTcmd = $s_RSTExe & " -I -d" Local $s_DoRST, $a_RSTDisksTemp, $s_rawdata, $numDISK = 0 If $Debug <> 0 Then ConsoleWrite("Get disk info: " & $s_RSTcmd & @CRLF) ; useful during dev but cannot be used if #requireadmin $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, @ScriptDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) ProcessWaitClose($s_DoRST) $s_rawdata = StdoutRead($s_DoRST) $a_RSTDisksTemp = StringSplit($s_rawdata, @CRLF) For $i = $a_RSTDisksTemp[0] To 1 Step -1 ; since we are deleting items, we have to go backwards through the array If $a_RSTDisksTemp[$i] = "" Or $a_RSTDisksTemp[$i] = "--DISK INFORMATION--" Then _ArrayDelete($a_RSTDisksTemp, $i) EndIf Next $a_RSTDisksTemp[0] = UBound($a_RSTDisksTemp) If IsArray($a_RSTDisksTemp) Then For $j = $a_RSTDisksTemp[0] - 1 To 1 Step -1 ; we need to remove the ATAPI device(s), since we delete we have to step through in reverse If StringInStr($a_RSTDisksTemp[$j], "Disk Type: SATA") Then $numDISK = $numDISK + 1 EndIf Next For $j = $a_RSTDisksTemp[0] - 1 To 1 Step -1 ; we need to remove the ATAPI device(s), since we delete we have to step through in reverse If StringInStr($a_RSTDisksTemp[$j], "ATAPI") Then ; we have to delete the ID entry BEFORE and AFTER the ATAPI entry to remove the ATAPI device (always delete from the bottom up!). _ArrayDelete($a_RSTDisksTemp, $j + 1) ; delete entry below _ArrayDelete($a_RSTDisksTemp, $j) ; delete entry _ArrayDelete($a_RSTDisksTemp, $j - 1) ; delete entry above ExitLoop ; this only deals with one device. If there were more we would need to capture all ATAPI device ID locations into another array then delete the original array entries based on the index numbers in the new array. EndIf Next $a_RSTDisksTemp[0] = UBound($a_RSTDisksTemp) If $a_RSTDisksTemp[0] <> 1 Then If $Debug <> 0 Then ConsoleWrite("Found " & $numDISK & " disk(s) attached to controller." & @CRLF) _infoLog("_GetDiskInfoFromRSTE() found " & $numDISK & " disk(s) attached to controller.", $msgSource) Else If $Debug <> 0 Then ConsoleWrite("No disks found to be attached to controller." & @CRLF) _infoLog("No disks found to be attached to controller.", $msgSource) EndIf Else If $Debug <> 0 Then ConsoleWrite("Unable to query RAID controller. Check hardware and version of RST client software." & @CRLF) _errorLog("Unable to query RAID controller. Check hardware.", $msgSource) Exit EndIf Return $a_RSTDisksTemp EndFunc ;==>_GetDiskInfoFromRSTE  
×