使用Exec()时隐藏命令提示符窗口

Bla*_*ack 13 vbscript

我正在尝试执行这个简单的测试脚本,但是在执行脚本后出现命令shell窗口:

Set objShell = WScript.CreateObject("WScript.Shell")

strCommand = "cmd /C tasklist"

Set objExecObject = objShell.Exec(strCommand)

wscript.echo "Test"
Run Code Online (Sandbox Code Playgroud)

如何防止它出现?

更新

我能够通过此代码更改来改进它:

strCommand = "cmd /C /Q tasklist"
Run Code Online (Sandbox Code Playgroud)

现在窗口只显示一瞬间.但我不希望它出现.

Bon*_*ond 31

你总会得到一个窗口闪光灯Exec().您可以Run()改为在隐藏窗口中执行命令.但是你无法直接捕获命令的输出Run().您必须将输出重定向到临时文件,然后VBScript可以打开,读取和删除.

例如:

With CreateObject("WScript.Shell")

    ' Pass 0 as the second parameter to hide the window...
    .Run "cmd /c tasklist.exe > c:\out.txt", 0, True

End With

' Read the output and remove the file when done...
Dim strOutput
With CreateObject("Scripting.FileSystemObject")

    strOutput = .OpenTextFile("c:\out.txt").ReadAll()
    .DeleteFile "c:\out.txt"

End With
Run Code Online (Sandbox Code Playgroud)

FileSystemObject类有方法,如GetSpecialFolder()检索Windows临时文件夹的路径,并GetTempName()生成临时文件名,你可以改用因为我之前所做的那样硬编码的输出文件名的.

另请注意,您可以使用/FO CSV参数tasklist.exe来创建CSV文件,这样可以更轻松地解析它.

最后,还有 VBScript的"原生"的方式来检索正在运行的进程的列表.Win32_Process例如,WMI的课程可以在不需要的情况下完成Run/Exec.


编辑:

为了完整起见,我应该提一下,您的脚本可以在隐藏的控制台窗口中重新启动,您可以在其中Exec()静默运行.不幸的是,这个隐藏的控制台窗口也会隐藏你的输出功能WScript.Echo().但是,除此之外,您可能不会注意到在cscriptvs 下运行脚本的任何差异wscript.以下是此方法的示例:

' If running under wscript.exe, relaunch under cscript.exe in a hidden window...
If InStr(1, WScript.FullName, "wscript.exe", vbTextCompare) > 0 Then
    With CreateObject("WScript.Shell")
        WScript.Quit .Run("cscript.exe """ & WScript.ScriptFullName & """", 0, True)
    End With
End If

' "Real" start of script. We can run Exec() hidden now...
Dim strOutput
strOutput = CreateObject("WScript.Shell").Exec("tasklist.exe").StdOut.ReadAll()

' Need to use MsgBox() since WScript.Echo() is sent to hidden console window...
MsgBox strOutput  
Run Code Online (Sandbox Code Playgroud)

当然,如果您的脚本需要命令行参数,那么在重新启动脚本时也需要转发这些参数.


编辑2:

另一种可能性是使用Windows剪贴板.您可以将命令的输出传递给clip.exe实用程序.然后,通过可以访问剪贴板内容的任意数量的可用COM对象检索文本.例如:

' Using a hidden window, pipe the output of the command to the CLIP.EXE utility...
CreateObject("WScript.Shell").Run "cmd /c tasklist.exe | clip", 0, True

' Now read the clipboard text...
Dim strOutput
strOutput = CreateObject("htmlfile").ParentWindow.ClipboardData.GetData("text")
Run Code Online (Sandbox Code Playgroud)


ome*_*pes 11

您可以使用.Exec()方法,无需控制台窗口闪存,临时文件和意外WScript.Echo输出静音.该方法有点棘手,需要启动辅助链接脚本,所以我添加了注释:

Option Explicit

Dim objDummy, strSignature, objPrimary, objSecondary, objContainer, objWshShell, objWshShellExec, strResult

' this block is executed only in the secondary script flow, after primary script runs cscript
If WScript.Arguments.Named.Exists("signature") Then
    ' retrieve signature string from argument
    strSignature = WScript.Arguments.Named("signature")
    Do
        ' loop through all explorer windows
        For Each objContainer In CreateObject("Shell.Application").Windows
            ' check if the explorer's property with signature name contains the reference to the live script
            If ChkVBScriptTypeInfo(objContainer.getProperty(strSignature)) Then
                Exit Do
            End If
        Next
        WScript.Sleep 10
    Loop
    ' create shell object within secondary script
    Set objWshShell = CreateObject("WScript.Shell")
    ' retrieve the primary script me object reference from explorer's property with signature name
    Set objPrimary = objContainer.getProperty(strSignature)
    ' quit explorer window to release memory as it's no longer needed
    objContainer.Quit
    ' assign the secondary script me object to the primary script's variable
    Set objPrimary.objSecondary = Me
    ' emtpy loop while primary script is working
    Do While ChkVBScriptTypeInfo(objPrimary)
        WScript.Sleep 10
    Loop
    ' terminate secondary
    WScript.Quit
End If

' the code below is executed first in the primary script flow 
' create signature string
strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
' create new hidden explorer window as container to transfer a reference between script processes
Set objContainer = GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}")
' put this script's me object reference into explorer's property
objContainer.putProperty strSignature, Me
' launch new secondary process of the same script file via cscript.exe with hidden console window, providing signature string in named argument to identify host script
CreateObject("WScript.Shell").Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0
' wait until secondary script has been initialized and put his me object into this script variable
Do Until ChkVBScriptTypeInfo(objSecondary)
    WScript.Sleep 10
Loop

' here is your code starts...
' create exec object within hidden console window of secondary script, execute cmd instruction
Set objWshShellExec = objSecondary.objWshShell.Exec("%comspec% /c tasklist")
' read cmd output
strResult = objWshShellExec.StdOut.ReadAll()
WScript.Echo strResult
' ...


' utility check if me object is live
Function ChkVBScriptTypeInfo(objSample)
    On Error Resume Next
    If TypeName(objSample) <> "VBScriptTypeInfo" Then
        ChkVBScriptTypeInfo = False
        Exit Function
    End If
    ChkVBScriptTypeInfo = True
End Function
Run Code Online (Sandbox Code Playgroud)

UPDATE

我稍微修改了代码以使其更直接:

Option Explicit

Dim strCmd, strRes, objWnd, objParent, strSignature

If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
strCmd = "%comspec% /c tasklist"
RunCScriptHidden
WScript.Echo strRes

Sub RunCScriptHidden()
    strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
    GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty strSignature, Me
    CreateObject("WScript.Shell").Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0, True
End Sub

Sub WshShellExecCmd()
    For Each objWnd In CreateObject("Shell.Application").Windows
        If IsObject(objWnd.getProperty(WScript.Arguments.Named("signature"))) Then Exit For
    Next
    Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))
    objWnd.Quit
    objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll()
    WScript.Quit
End Sub
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这是使用相同容器方法的VBScript"多线程"实现.