You would think a scripting engine that has a separate console version (cscript.exe) would allow you to execute an external command/application and handle basic stdout output for you with a simple command, but sadly this is not the case. WScript.Shell’s Run method uses ShellExecute and unsurprisingly so does Shell.Application’s ShellExecute, that just leaves us with Exec.
This is what MSDN has to say about this method:
Runs an application in a child command-shell, providing access to the StdIn/StdOut/StdErr streams.
Sounds good right?
The MSDN example code contains this line:
Set oExec = WshShell.Exec("calc")
Wait, why are they executing a GUI application in what should be a example about running commands in a child shell? Could it be because Exec does not hook up the child process’s streams to the console created by cscript?
While it is handy to have access to the streams in the script so you can parse the output, sometimes you just want to execute something and print the output to the “real” stdout. Calling CreateProcess on a terminal application in native code is actually less work than doing it in a script! I’m not going to post the 6 lines it takes in win32, but here is my take on the WSH/VB version:
Sub PipeTextStream(ByRef si,ByRef so) Do Until si.AtEndOfStream so.Write(si.Read(1)) Loop End Sub Function ConsoleExec(cmd) Set sh = WScript.CreateObject("WScript.Shell") On Error Resume Next Set exec = sh.Exec(cmd) If Err.Number <> 0 Then ConsoleExec = Err.Number Exit Function End If On Error Goto 0 Do While exec.Status = 0 WScript.Sleep 100 PipeTextStream exec.StdOut,WScript.StdOut PipeTextStream exec.StdErr,WScript.StdErr Loop ConsoleExec = exec.ExitCode End Function
call ConsoleExec("ping localhost")
This does not work for internal cmd.exe commands like DIR and DEL, for that you would have to execute %comspec% /c …