Forum Discussion

talisker's avatar
talisker
New Contributor
8 years ago
Solved

Call and wait on a .bat file in python script

Hi,

 

I am using python script to invoke a .bat file on Windows. This bat file contains a call to ssh.exe:

 

ssh.exe user@targetserver 'some remote command'

 

When running the batch file, I am prompted to enter a password (to authenticate the SSH session). I therefore need to wait on the proper execution of the batch file internal commands before moving along. I also need to collect the result value of the SSH method invocation. 

 

I have seen references to a Call method (see link below), but am unsure how to use it in Python and cannot find any reference to it:

 

Call Sys.OleObject("WScript.Shell").Run("""C:\Folder1\Folder2\App_Name.bat"", 1, true")

 

https://community.smartbear.com/t5/TestComplete-General-Discussions/How-to-wait-for-batch-file-execution-to-be-completed-before/td-p/108027

 

Any help appreciated,

 

Cheers,

 

S.

  • Hi,

     

    I believe that you are looking for something like this (DelphiScript):

    //-----------------------------------------------------------------------------
    //-----------------------------------------------------------------------------
    
    function ReadAllFromAny(oExec : OleVariant) : string;
    begin
      result := '';
      if (not oExec.StdOut.AtEndOfStream) then
      begin
        result := oExec.StdOut.ReadAll;
        exit;
      end;
    
      if (not oExec.StdErr.AtEndOfStream) then
      begin
        result := 'STDERR: ' + oExec.StdErr.ReadAll;
        exit;
      end;
    end;
    //-----------------------------------------------------------------------------
    
    function ExecAndWaitForEnd(strProg, strArgs : string; var strOutput : string) : integer;
      const cEXEC_DELAY = 500; // time interval (in ms) when looking if spawned process have finished
    
      var WshShell : OleVariant;
      var oExec : OleVariant;
      var strCommand  : string;
      var allInput  : string;
    begin
      result := -1;
    
      strProg := aqString.Trim(strProg);
      If ('"' <> aqString.GetChar(strProg, 0)) then
        strProg := aqString.Quote(strProg);
    
      strCommand := strProg + ' ' + strArgs;
      Log.AppendFolder('Executing: ' + strCommand, strCommand);
      try
        WshShell := Sys.OleObject('WScript.Shell');
        oExec := WshShell.Exec(strCommand);
    
        while (0 = oExec.Status) do
          BuiltIn.Delay(cEXEC_DELAY);
    
        allInput := ReadAllFromAny(oExec);
    
        result := oExec.ExitCode;
        strOutput := allInput;
        Log.Message(aqString.Format('Done. Exit code = %i (0x%x)', oExec.ExitCode, oExec.ExitCode), allInput);
      finally
        Log.PopLogFolder();
    
        oExec := nil;
        WshShell := nil;
      end;
    end;
    //-----------------------------------------------------------------------------
    //-----------------------------------------------------------------------------
    

     

    To use Call ExecAndWaitForEnd() function. Exit code is returned as a result of function's call and the text from console output is returned in the strOutput variable passed by reference.

3 Replies

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3

    Hi,

     

    I believe that you are looking for something like this (DelphiScript):

    //-----------------------------------------------------------------------------
    //-----------------------------------------------------------------------------
    
    function ReadAllFromAny(oExec : OleVariant) : string;
    begin
      result := '';
      if (not oExec.StdOut.AtEndOfStream) then
      begin
        result := oExec.StdOut.ReadAll;
        exit;
      end;
    
      if (not oExec.StdErr.AtEndOfStream) then
      begin
        result := 'STDERR: ' + oExec.StdErr.ReadAll;
        exit;
      end;
    end;
    //-----------------------------------------------------------------------------
    
    function ExecAndWaitForEnd(strProg, strArgs : string; var strOutput : string) : integer;
      const cEXEC_DELAY = 500; // time interval (in ms) when looking if spawned process have finished
    
      var WshShell : OleVariant;
      var oExec : OleVariant;
      var strCommand  : string;
      var allInput  : string;
    begin
      result := -1;
    
      strProg := aqString.Trim(strProg);
      If ('"' <> aqString.GetChar(strProg, 0)) then
        strProg := aqString.Quote(strProg);
    
      strCommand := strProg + ' ' + strArgs;
      Log.AppendFolder('Executing: ' + strCommand, strCommand);
      try
        WshShell := Sys.OleObject('WScript.Shell');
        oExec := WshShell.Exec(strCommand);
    
        while (0 = oExec.Status) do
          BuiltIn.Delay(cEXEC_DELAY);
    
        allInput := ReadAllFromAny(oExec);
    
        result := oExec.ExitCode;
        strOutput := allInput;
        Log.Message(aqString.Format('Done. Exit code = %i (0x%x)', oExec.ExitCode, oExec.ExitCode), allInput);
      finally
        Log.PopLogFolder();
    
        oExec := nil;
        WshShell := nil;
      end;
    end;
    //-----------------------------------------------------------------------------
    //-----------------------------------------------------------------------------
    

     

    To use Call ExecAndWaitForEnd() function. Exit code is returned as a result of function's call and the text from console output is returned in the strOutput variable passed by reference.

    • talisker's avatar
      talisker
      New Contributor

      Hi Alex, thank you very much for your answer.

       

      For anyone looking, here's the lesser version in Python (I will add StdErr and proper error handling):

       

      def ExecuteShellCommand(command):
      
        oShell = Sys.OleObject["WScript.Shell"]
        execution = oShell.Exec(command)
        
        while execution.Status is 0:
           aqUtils.Delay(100);
      
        exitCode = int(execution.ExitCode)  
        stdOut = ''
      
        if not execution.StdOut.AtEndOfStream: 
          stdOut = execution.StdOut.ReadAll()
      
        report = '***COMMAND:\n\n' + command + '\n\n***RESULT:\n\n' + stdOut
          
        if exitCode != 0:
          Log.Error(report)
        else:
          Log.Message(report)