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

问题描述 投票:0回答:6

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

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

strCommand = "cmd /C tasklist"

Set objExecObject = objShell.Exec(strCommand)

wscript.echo "Test"

如何防止它出现?

更新

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

strCommand = "cmd /C /Q tasklist"

现在窗口只显示一瞬间。但我根本不想让它出现。

vbscript
6个回答
44
投票

您总是会看到带有

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

FileSystemObject
类具有诸如
GetSpecialFolder()
之类的方法来检索Windows临时文件夹的路径,以及
GetTempName()
来生成可以使用的临时文件名,而不是像我上面所做的那样硬编码输出文件名。

另请注意,您可以将

/FO CSV
参数与
tasklist.exe
一起使用来创建 CSV 文件,这将使解析变得更加容易。

最后,还有 VBScript“本机”方法来检索正在运行的进程列表。例如,WMI 的 Win32_Process

 类可以做到这一点,而不需要 Run/Exec


编辑

为了完整起见,我应该提到您的脚本

可以在隐藏的控制台窗口中重新启动,您可以在其中静默运行Exec()

。不幸的是,这个隐藏的控制台窗口也会隐藏 
WScript.Echo()
 等函数的输出。然而,除此之外,您可能不会注意到在 
cscript
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

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


编辑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")
    

14
投票
您可以使用

.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

更新

我稍微修改了代码,使其更加简单:

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

顺便说一句,这是使用相同容器方法的

VBScript“多线程”实现


2
投票
上面列出了一些很好的建议。我想再提出一个建议,这更像是一种解决方法。您可以使用

Sysinternals Desktops(免费程序)在同一台计算机上的另一个桌面上运行宏。这样,闪烁就可以在自己的桌面上进行,不会中断您的工作。


1
投票
我使用 Sysinternals PSEXEC

https://learn.microsoft.com/sv-se/sysinternals/downloads/psexec

创建了一个批处理文件(与 vbs 和 exe 文件位于同一文件夹中),以系统用户身份运行脚本。 我无法访问用户配置文件,我需要成为本地管理员,但是当我运行脚本而不与桌面交互时,它将隐藏所有烦人的弹出窗口。

作为系统运行脚本,无需与桌面交互

"%~dp0PsExec.exe" -s wscript.exe "%~dp0MyScript.vbs"



作为系统运行脚本并与桌面交互

"%~dp0PsExec.exe" -s -i wscript.exe "%~dp0MyScript.vbs"


    


0
投票
要在 VBscipt 中隐藏命令行窗口,请使用

Run

 中的 WshShell
 对象 

然后要获得结果,您可以将此结果发送到文本文件中

%temp%



然后用

FileSystemObject

  读取结果

Set Sh = CreateObject("WScript.Shell") tFile=Sh.ExpandEnvironmentStrings("%Temp%")&"\t.txt" Sh.Run "cmd.exe /C tasklist > """&tFile&""" ",0,False Wscript.echo CreateObject("Scripting.FileSystemObject").openTextFile(tFile).readAll()

If StrComp(right(WScript.FullName,11),"wscript.exe",1) = 0 Then '' get only wscript.exe from "c:\windows\system32\wscript.exe" to compere with wscript.exe WScript.Quit CreateObject("WScript.Shell").Run("cscript.exe """ & WScript.ScriptFullName & """", 0, False) End If MsgBox CreateObject("WScript.Shell").Exec("cmd.exe /c tasklist /v /fi ""imagename EQ explorer*"" /FO LIST | FIND ""PID:""").StdOut.ReadAll()
    

0
投票
在尝试了主要解决方案但没有成功后,我能够使用以下代码解决我的问题:

With CreateObject("WScript.Shell") .Run "cmd /c start /b tasklist.exe > c:\out.txt", 0, True End With
真正的问题是控制台帮助显示的“/b”:

START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED] [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL] [/NODE <NUMA node>] [/AFFINITY <hex affinity mask>] [/WAIT] [/B] [command/program] [parameters] "title" Title to display in window title bar. path Starting directory. B Start application without creating a new window. The application has ^C handling ignored. Unless the application enables ^C processing, ^Break is the only way to interrupt the application.
    
© www.soinside.com 2019 - 2024. All rights reserved.