我正在尝试执行这个简单的测试脚本,但是在执行脚本后出现了命令shell窗口。:
Set objShell = WScript.CreateObject("WScript.Shell")
strCommand = "cmd /C tasklist"
Set objExecObject = objShell.Exec(strCommand)
wscript.echo "Test"
如何防止它出现?
更新
我可以通过此代码更改来改进它:
strCommand = "cmd /C /Q tasklist"
现在窗口只显示一瞬间。但我不希望它出现。
答案 0 :(得分:29)
您总是会使用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()
的路径,以生成一个临时文件名,你可以使用它而不是硬编码输出文件名为I&# 39;已完成上述工作。
另请注意,您可以将/FO CSV
参数与tasklist.exe
一起使用来创建CSV文件,这样可以更轻松地解析它。
最后,是 VBScript" native"检索正在运行的进程列表的方法。例如,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")
答案 1 :(得分:6)
您可以使用.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 "multithreading" implementation。
答案 2 :(得分:2)
上面列出了一些很棒的建议。我想再提一个建议,这更像是一种解决方法。您可以使用Sysinternals Desktops(免费程序)在同一台计算机上的另一台桌面上运行宏。这样闪烁就可以在自己的桌面上发生,不会打断你的工作。
答案 3 :(得分:1)
我使用Sysinternals PSEXEC https://docs.microsoft.com/sv-se/sysinternals/downloads/psexec
创建一个批处理文件(与vbs和exe文件位于同一文件夹中),以文件系统用户身份运行脚本。 我无法访问用户配置文件,我需要成为本地管理员,但是当我运行脚本而不与桌面交互时,它将隐藏所有烦人的弹出窗口。
将脚本作为系统运行而不与桌面交互
"%~dp0PsExec.exe" -s wscript.exe "%~dp0MyScript.vbs"
将脚本作为与桌面交互的系统运行
"%~dp0PsExec.exe" -s -i wscript.exe "%~dp0MyScript.vbs"
答案 4 :(得分: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()
OR
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()
答案 5 :(得分:0)
这里是Windows脚本宿主的替代方法:Run a batch program(.bat) through a Visual Basic 6.0
它运行一个程序并捕获其屏幕输出。它在VB6中对我有效,但在VBA中不起作用(挂在WaitForSingleObject上,不知道为什么)。
答案 6 :(得分: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.
答案 7 :(得分:0)
Omegastripes的答案让我着迷,并稍微改善了本已漂亮的代码。
这是omegastripes代码的改进版本,该代码允许从vbs静默调用cmd.exe。我今天做了。将来自cmd.exe的混乱响应拆分为一个数组,而不是将所有内容都放入一个难以解析的字符串中。
此外,如果在执行cmd.exe的过程中发生错误,则有关该错误的消息将在vbs中变为已知。
Option Explicit
Sub RunCScriptHidden()
strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty strSignature, Me
objShell.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() 'simple solution
Set exec = CreateObject("WScript.Shell").Exec(objParent.strCmd)
While exec.Status = WshRunning
WScript.Sleep 20
Wend
Dim err
If exec.ExitCode = WshFailed Then
err = exec.StdErr.ReadAll
Else
output = Split(exec.StdOut.ReadAll,Chr(10))
End If
If err="" Then
objParent.strRes = output(UBound(output)-1) 'array of results, you can: output(0) Join(output) - Usually needed is the last
Else
objParent.wowError = err
End If
WScript.Quit
End Sub
Const WshRunning = 0,WshFailed = 1:Dim cmdExeString,i,name,objShell
Dim strCmd, strRes, objWnd, objParent, strSignature, wowError, output, exec
Set objShell = WScript.CreateObject("WScript.Shell"):wowError=False
cmdExeString="echo Hello World."
strCmd = "%comspec% /c " & cmdExeString
If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
RunCScriptHidden
If wowError=False Then
objShell.popup(strRes)
Else
objShell.popup("Error=" & wowError)
End If