我正在尝试执行这个简单的测试脚本,但执行脚本后会出现一个命令 shell 窗口。:
Set objShell = WScript.CreateObject("WScript.Shell")
strCommand = "cmd /C tasklist"
Set objExecObject = objShell.Exec(strCommand)
wscript.echo "Test"
如何防止它出现?
更新
我能够通过此代码更改来改进它:
strCommand = "cmd /C /Q tasklist"
现在窗口只显示一瞬间。但我根本不想让它出现。
您总是会看到带有
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")
.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“多线程”实现。
Sysinternals Desktops(免费程序)在同一台计算机上的另一个桌面上运行宏。这样,闪烁就可以在自己的桌面上进行,不会中断您的工作。
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"
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()
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.