11

My VBScript does not show the results of any command I execute. I know the command gets executed but I would like to capture the result.

I have tested many ways of doing this, for example the following:

Const WshFinished = 1
Const WshFailed = 2
strCommand = "ping.exe 127.0.0.1"

Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)

Select Case WshShellExec.Status
   Case WshFinished
       strOutput = WshShellExec.StdOut.ReadAll
   Case WshFailed
       strOutput = WshShellExec.StdErr.ReadAll
 End Select

WScript.StdOut.Write strOutput  'write results to the command line
WScript.Echo strOutput          'write results to default output

But it does not print any results. How do I capture StdOut and StdErr?

3 Answers 3

18

WScript.Shell.Exec() returns immediately, even though the process it starts does not. If you try to read Status or StdOut right away, there won't be anything there.

The MSDN documentation suggests using the following loop:

Do While oExec.Status = 0
     WScript.Sleep 100
Loop

This checks Status every 100ms until it changes. Essentially, you have to wait until the process completes, then you can read the output.

With a few small changes to your code, it works fine:

Const WshRunning = 0
Const WshFinished = 1
Const WshFailed = 2
strCommand = "ping.exe 127.0.0.1"

Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)

Do While WshShellExec.Status = WshRunning
     WScript.Sleep 100
Loop

Select Case WshShellExec.Status
   Case WshFinished
       strOutput = WshShellExec.StdOut.ReadAll()
   Case WshFailed
       strOutput = WshShellExec.StdErr.ReadAll()
 End Select

WScript.StdOut.Write(strOutput)  'write results to the command line
WScript.Echo(strOutput)          'write results to default output
Sign up to request clarification or add additional context in comments.

2 Comments

If the environment you're running in doesn't have access to WScript.Sleep, you can remove that line and perform a busy wait
This blocked execution on my win11 system, when stdout had more than 700 lines. I can see Tomek below also confirms this problem. See solution here: stackoverflow.com/a/74396983/197141
3

You should read both streams INSIDE the loop as well as after it. When your process is verbose then it will block on the I/O buffer when this buffer will not be emptyfied succesively!!!

In practice I use this schema in many scripts. It collects both streams: the output (as Shell.Exec called apps can return output info) and error.

        Dim vErrStr
        vErrStr = ""
        Dim vOutStr
        vOutStr = ""
        Do While oExec.Status = 0
            WScript.Sleep 1000
            If Not oExec.StdErr.AtEndOfStream Then
                vErrStr = vErrStr & oExec.StdErr.ReadAll
            End If
            If Not oExec.StdOut.AtEndOfStream Then
                vOutStr = vOutStr & oExec.StdOut.ReadAll
            End If
        Loop

        vExitCode = oExec.ExitCode
        If Not oExec.StdErr.AtEndOfStream Then
            vErrStr = vErrStr & oExec.StdErr.ReadAll
        End If
        If Not oExec.StdOut.AtEndOfStream Then
            vOutStr = vOutStr & oExec.StdOut.ReadAll
        End If

        Dim vEMStr
        vEMStr = vErrStr & IIf((vErrStr <> "") And (vOutStr <> ""), " | ", "") & vOutStr

4 Comments

But how to keep it from blocking inside the loop? Won't a readAll() block until there's data on it?
I check the AtEndOfStream condition. It does not block.
oExec is a Shell object, two variables are gathering the stream contents. You can drop it if it is too long.... Do While oExec.Status = 0 WScript.Sleep 1000 If Not oExec.StdErr.AtEndOfStream Then vErrStr = vErrStr & oExec.StdErr.ReadAll End If If Not oExec.StdOut.AtEndOfStream Then vOutStr = vOutStr & oExec.StdOut.ReadAll End If Loop
1

I think Tomek's answer is good, but incomplete.

Here's a code example.

Private Sub ExecuteCommand(sCommand$)
    Dim wsh As Object
    Set wsh = CreateObject("WScript.Shell")
    
    Dim oExec As Object, oOut As TextStream
    
    'Exec the command
    Set oExec = wsh.Exec(sCommand$)
    Set oOut = oExec.StdOut
    
    'Wait for the command to finish
    While Not oOut.AtEndOfStream
        Call Debug.Print(oOut.ReadLine)
    Wend
    
    Select Case oExec.Status
       Case WshFinished
       Case WshFailed
           Err.Raise 1004, "EndesaSemanal.ExecuteCommand", "Error: " & oExec.StdErr.ReadAll()
     End Select
End Sub

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.