VBScript getting results from Shell
Asked Answered
D

5

14
Set wshShell = WScript.CreateObject ("WSCript.shell")
wshshell.run "runas ..."

How do I get the results and display in a MsgBox

Drum answered 19/5, 2011 at 15:15 Comment(1)
Define "results". Runas exit code? Exit code of the application run via runas? The application's console output?Magdalenemagdalenian
G
28

You will want to use the WshShell object's Exec method instead of Run. Then simply read the command line's output from the standard streams. Try this one:

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
MsgBox strOutput                'write results in a message box
Greenbelt answered 20/5, 2011 at 14:10 Comment(7)
Would we be able to do the same kind of thing with WshShell.Run?Donatus
No. Run does not provide access to standard streams.Greenbelt
Note: This is asynchronous so you will likely see an incorrect WshShellExec.Status at Select CaseDingy
@MattBorja If you use it as intended, to run command line programs, it will run the command and return an object at completion. However, if you launch a windowed application such as calc.exe, you would need a loop since the command line would return before the program execution ended. In that case, you would simply loop until WshShellExec.Status <> 0.Greenbelt
@Nilpo, it fails using your own strCommand value. It returns 0 (meaning Running) Fixed at #32921190Snowblink
@Snowblink Please see my previous comment.Greenbelt
@Greenbelt I had the same issue when running anything. As rdev5 said, Exec is asynch, so WshShellExec.Status is still 0 (running) at the time you first check it. You need to loop until it's done with something like While WshShellExec.Status = 0 : WScript.Sleep 50 : Wend Perhaps consider editing your answer.Manuel
M
9

This is a modified version of Nilpo's answer that fixes the issue with WshShell.Exec being asynchronous. We do a busy-loop waiting until the shell's status is no longer running, and then we check the output. Change the command-line argument -n 1 to a higher value to make ping take longer, and see that the script will wait longer until completion.

(If anyone has a true asynchronous, event-based solution to the problem, then please let me know!)

Option Explicit

Const WshRunning = 0
Const WshFinished = 1
Const WshFailed = 2

Dim shell : Set shell = CreateObject("WScript.Shell")
Dim exec : Set exec = shell.Exec("ping.exe 127.0.0.1 -n 1 -w 500")

While exec.Status = WshRunning
    WScript.Sleep 50
Wend

Dim output

If exec.Status = WshFailed Then
    output = exec.StdErr.ReadAll
Else
    output = exec.StdOut.ReadAll
End If

WScript.Echo output
Manuel answered 24/7, 2017 at 15:3 Comment(0)
G
3

The solution of BoffinBrain still doesn't work, since exec.Status doesn't return an error level (returns just 0 while running and 1 when finished). For that purpose you must use exec.ExitCode (Returns the exit code set by a script or program run using the Exec() method.). So the solution changes to

Option Explicit

Const WshRunning = 0
' Const WshPassed = 0    ' this line is useless now
Const WshFailed = 1

Dim shell : Set shell = CreateObject("WScript.Shell")
Dim exec : Set exec = shell.Exec("ping.exe 127.0.0.1 -n 1 -w 500")

While exec.Status = WshRunning
    WScript.Sleep 50
Wend

Dim output

If exec.ExitCode = WshFailed Then
    output = exec.StdErr.ReadAll
Else
    output = exec.StdOut.ReadAll
End If

WScript.Echo output
Gallant answered 10/12, 2019 at 17:10 Comment(0)
E
2

I think this makes the most sense. It is WshFinished, not WshFailed. I print the output as it comes, instead of at the end.

Function ExecCommand(cmd)
    Const WshRunning = 0
    Const WshFinished = 1

    Dim objWshShell : Set objWshShell = CreateObject("WScript.Shell")
    Dim oExec : Set oExec = objWshShell.Exec(cmd)

    Do
        'sleep in the loop before reading pipelines and reading finished state
        WScript.Sleep 50

        ' We must read these, or it seems to block execution after 700 lines out output,
        ' probably because VBScript is blocking the pipeline, because script completes if VBScirpt is stoped with Ctrl-C
        While oExec.StdOut.AtEndOfStream <> True
            WScript.StdOut.WriteLine(oExec.StdOut.ReadLine())
        Wend

        While oExec.StdErr.AtEndOfStream <> True
            WScript.StdErr.WriteLine("ERROR: " & oExec.StdErr.ReadLine())
        Wend

        Finished = ( oExec.Status = WshFinished )
    Loop Until Finished
    
    WScript.StdOut.WriteLine("ExitCode: " & oExec.ExitCode)
    WScript.Quit(oExec.ExitCode) ' Optionally sets exit-code and exits this VbScript (but does not stop the executing sub-shell)
End Function

A good example is: ExecCommand "ping.exe 127.0.0.1 -n 3 -w 500"

See error output with: ExecCommand "cmd /c Echo Test Error >&2"

Enright answered 11/11, 2022 at 1:3 Comment(1)
This seems best of the current answers. It always reads both stdout and stdErr, which it should, and which is required to avoid VBScript blocking when more than 700 lines is produced (on my win11 system). Sets exit code at the end as extra service to user. Run as script for exit-code with cscript.exe //nologo myscript.vbsKonstantine
F
0
var errorlevel = new ActiveXObject('WScript.Shell').Run(command, 0, true)

the third parameter must be true, and errorlevel will be return value, check if it is equal 0.

Ferial answered 8/3, 2017 at 8:41 Comment(4)
Not VBScript; not (std) out (put).Paulita
@Paulita I test code in jscript, and I think vbscript is ok tooFerial
as you can see from the other answer, your assumption is wrong.Paulita
@Paulita no, if the third parameter is true, the return value will be errorlevelFerial

© 2022 - 2024 — McMap. All rights reserved.