VBscript code to capture stdout, without showing console window
Solution 1
This proof of concept script:
' pocBTicks.vbs - poor man's version of backticks (POC)
Option Explicit
' Globals
Const SW_SHOWMINNOACTIVE = 7
Const ForReading = 1
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
Dim goWSH : Set goWSH = CreateObject( "WScript.Shell" )
' Dispatch
WScript.Quit demoBTicks()
' demoBTicks -
Function demoBTicks()
demoBTicks = 1
Dim aCmds : aCmds = Array( _
"dir pocBTicks.vbs" _
, "dur pocBTicks.vbs" _
, "xcopy /?" _
)
Dim sCmd
For Each sCmd In aCmds
WScript.Echo "########", sCmd
Dim aRet : aRet = BTicks( sCmd )
Dim nIdx
For nIdx = 0 To UBound( aRet )
WScript.Echo "--------", nIdx
WScript.Echo aRet( nIdx )
Next
Next
demoBTicks = 0
End Function ' demoBTicks
' BTicks - execute sCmd via WSH.Run
' aRet( 0 ) : goWSH.Run() result
' aRet( 1 ) : StdErr / error message
' aRet( 2 ) : StdOut
' aRet( 3 ) : command to run
Function BTicks( sCmd )
Dim aRet : aRet = Array( -1, "", "", "" )
Dim sFSpec2 : sFSpec2 = goFS.GetAbsolutePathName( "." )
Dim sFSpec1 : sFSpec1 = goFS.BuildPath( sFSpec2, goFS.GetTempName() )
sFSpec2 = goFS.BuildPath( sFSpec2, goFS.GetTempName() )
aRet( 3 ) = """%COMSPEC%"" /c """ + sCmd + " 1>""" + sFSpec1 + """ 2>""" + sFSpec2 + """"""
Dim aErr
On Error Resume Next
aRet( 0 ) = goWSH.Run( aRet( 3 ), SW_SHOWMINNOACTIVE, True )
aErr = Array( Err.Number, Err.Description, Err.Source )
On Error GoTo 0
If 0 <> aErr( 0 ) Then
aRet( 0 ) = aErr( 0 )
aRet( 1 ) = Join( Array( aErr( 1 ), aErr( 2 ), "(BTicks)" ), vbCrLf )
BTicks = aRet
Exit Function
End If
Dim nIdx : nIdx = 1
Dim sFSpec
For Each sFSpec In Array( sFSpec2, sFSpec1 )
If goFS.FileExists( sFSpec ) Then
Dim oFile : Set oFile = goFS.GetFile( sFSpec )
If 0 < oFile.Size Then
aRet( nIdx ) = oFile.OpenAsTextStream( ForReading ).ReadAll()
goFS.DeleteFile sFSpec
End If
End If
nIdx = nIdx + 1
Next
BTicks = aRet
End Function
shows how to use .Run and temporary files to get something like backticks with a hidden console. Decent file handling, quoting in sCmd, cleaning of the returned strings, and dealing with encodings will require more work. But perhaps you can use the strategy to implement something that fits your needs.
Solution 2
I usually use this:
Wscript.echo execStdOut("ping google.com")
Function execStdOut(cmd)
Dim goWSH : Set goWSH = CreateObject( "WScript.Shell" )
Dim aRet: Set aRet = goWSH.exec(cmd)
execStdOut = aRet.StdOut.ReadAll()
End Function
For more advanced commands youc an wrap to comspec (cmd)
my res = execStdOut("%comspec%" & " /c " & """" & "dir /b c:\windows\*.exe" & """" & " && Echo. && Echo finished")
Solution 3
In order to redirect the output to the console, run the script using cscript, ex.: c:\cscript myscript.vbs
.
cscript has a few command line options. The most important (to me) is the switch //NOLOGO. If yoy use it (cscript //nologo myscript.vbs
) it will omit Microsoft merchandise...
Solution 4
To return in VBA all subfolders in G:\OF
sub M_snb()
c00= createobejct("wscript.Shell").exec("cmd /c Dir G:\OF\*. /s/b").stdout.readall
end sub
to split the returned string into an array
sub M_snb()
sn=split(createobejct("wscript.Shell").exec("cmd /c Dir G:\OF\*. /s/b").stdout.readall,vbCrLf)
for j=0 to ubound(sn)
msgbox sn(j)
next
End Sub
Solution 5
If you don't mind having the taskbar button appear, you can just move the console window offscreen before launching it.
If the HKCU\Console\WindowPosition
key exists, Windows will use its value to position the console window. If the key doesn't exist, you'll get a system-positioned window.
So, save the original value of this key, set your own value to position it offscreen, call Exec()
and capture its output, then restore the key's original value.
The WindowPosition
key expects a 32-bit value. The high word is the X coordinate and the low word is the Y coordinate (XXXXYYYY
).
With CreateObject("WScript.Shell")
' Save the original window position. If system-positioned, this key will not exist.
On Error Resume Next
intWindowPos = .RegRead("HKCU\Console\WindowPosition")
On Error GoTo 0
' Set Y coordinate to something crazy...
.RegWrite "HKCU\Console\WindowPosition", &H1000, "REG_DWORD"
' Run Exec() and capture output (already demonstrated by others)...
.Exec(...)
' Restore window position, if previously set. Otherwise, remove key...
If Len(intWindowPos) > 0 Then
.RegWrite "HKCU\Console\WindowPosition", intWindowPos, "REG_DWORD"
Else
.RegDelete "HKCU\Console\WindowPosition"
End If
End With
If you really want to make sure the coordinates are offscreen, you can get the screen dimensions via VBScript by using IE or other tools.
Related videos on Youtube
mgr326639
Updated on October 02, 2020Comments
-
mgr326639 over 3 years
This is a VBScript code example that shows how to catch whatever a command line program sends to standard output. It executes the command
xcopy /?
and shows the output in a message box. Before the message box appears, for a split second you see the console window popping up.Set objShell = WScript.CreateObject("WScript.Shell") Set objExec = objShell.Exec("xcopy /?") Do line = objExec.StdOut.ReadLine() s = s & line & vbcrlf Loop While Not objExec.Stdout.atEndOfStream WScript.Echo s
Here is an other VBScript code example that shows how to execute a script without showing the console window.
objShell.Run "c:\temp\mybatch.bat C:\WINDOWS\system32\cmd.exe", 0
or
objShell.Run "c:\temp\myscript.vbs C:\WINDOWS\system32\cscript.exe", 0
As you can see it has the form
<script><space><executor>
. The last example usesobjShell.Run
instead ofobjShell.Exec
What I don't know is how to execute a command line program (if necessary from a batch file), catch the standard output, without showing the console window. Any ideas?
-
Camilo Martin over 11 yearsNote that this will hang if your program outputs too much (about 4KB IIRC), and it's not hidden.
-
mgr326639 about 10 yearsInteresting piece of code. But I don't really see the advantage in this case, because you are still relying on a temporary file.
-
tresf almost 9 years@CamiloMartin Where are you getting the 4KB limitation from? Is that a limitation of
StdOut.ReadAll()
. I just usedStdOut.ReadLine()
on a 109KB file without issues per ss64.com/vb/stdoutread.html. Although I can confirm the "not hidden" observation, making this solution non-ideal for those seeking a "hidden window" as a strict requirement, per the OP. -
Camilo Martin almost 9 years@QZSupport Honestly I don't have the faintest clue anymore, but probably I tried it and something hung after 4KB, then other two people came and upvoted it because something hung for them too. If it actually works that's great, just make sure to test on all Windows versions you're supporting. (Also, it should be noticed: it is very likely
ReadAll
will read everything into RAM, and would be very ugly on its own - I'd say you should stream the StdOut instead, but again I don't know how;ReadLine
wouldn't be good for binary output). -
tresf almost 9 years@CamiloMartin, good point about the binary and ReadLine(), that could get messy when the CRLFs never make it into the stream. However, I'd like to reiterate the OP's requirement of StdOut, which tends to favor non-binary representations of data. In regards to multiple platforms, I'll perform some testing as far back as XP and post an update.
-
tresf almost 9 years@CamiloMartin Edit: I just read 1145 lines on text weighing in at about 160KB and worked just fine on Windows XP SP3 (as long as I remember to use cmd /c and not cmd /k). For reading multi-line output, I see this solution as being perfectly adequate for most people, but I would recommend to use ReadLine() over ReadAll(). In terms of the 4KB limitation, it is explained further here: support.microsoft.com/en-us/kb/960246
-
Pankaj Jaju about 7 years@QZSupport - support.microsoft.com/en-us/help/960246/… talks about the 4kb limit
-
tresf about 7 years@PankajJaju thanks. Per that same article
Generally, this occurs if the spawned application is writing to both the StdOut and StdErr streams
. So applications that do not write to bothstderr
ANDstdout
shouldn't suffer this bug. -
gao.xiangyang about 4 yearsBut it still has an icon displayed in the taskbar,How to do?