Windows XP或更新的Windows操作系统:如何在后台运行批处理文件且不显示窗口?

132

我知道我已经回答了一个类似的问题(在Windows启动时运行批处理文件),但这次我需要启动一个批处理文件:

  • 从另一个批处理文件中启动,
  • 不显示任何控制台窗口,
  • 将所有参数传递给隐形批处理文件。

第一个批处理文件在控制台窗口中执行。但是,我不希望第二个批处理文件(由第一个以异步方式启动)也显示控制台窗口。

我想出了一个VBScript脚本,可以实现这一点,并将该脚本作为答案供其他人参考,但如果您有其他想法/解决方案,请随时贡献。

注意:许多人错误地称Windows命令处理器的控制台窗口为DOS窗口。


谢谢大家的答案。据我所知,如果我需要异步调用一个脚本以隐形方式运行:

  • 从另一个已在控制台窗口中的脚本中,只需使用start /b
  • 在Windows中,而不触发第二个窗口,我的解决方案仍然有效。

你是从另一个批处理文件中启动批处理文件吗?这个正在运行的批处理文件是否有窗口? - Oddthinking
是的,这个其他(第一个)批处理在 DOS 窗口中执行。然而,我不希望第二个批处理(由第一个异步启动)也显示一个窗口(这将发生在“start /b”命令中)。 - VonC
10个回答

115

这里是一个可能的解决方案:

从您的第一个脚本中,使用以下命令调用您的第二个脚本:

wscript.exe invis.vbs run.bat %*

实际上,你正在使用以下内容调用vbs脚本:

  • 脚本的[path]\名称
  • 脚本所需的所有其他参数(%*

然后,invis.vbs将使用Windows Script Host Run()方法调用您的脚本,该方法需要:

  • intWindowStyle:0表示“不可见窗口”
  • bWaitOnReturn:false表示您的第一个脚本无需等待第二个脚本完成

这是invis.vbs文件:

set args = WScript.Arguments
num = args.Count

if num = 0 then
    WScript.Echo "Usage: [CScript | WScript] invis.vbs aScript.bat <some script arguments>"
    WScript.Quit 1
end if

sargs = ""
if num > 1 then
    sargs = " "
    for k = 1 to num - 1
        anArg = args.Item(k)
        sargs = sargs & anArg & " "
    next
end if

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

WshShell.Run """" & WScript.Arguments(0) & """" & sargs, 0, False

唯一的问题是这会创建一个名为“cmd.exe”的进程,将来很难找到。 - YetAnotherBot

57

你需要让第二个批处理文件异步运行吗?通常情况下,一个批处理文件会使用 call 命令同步地运行另一个批处理文件,并且第二个批处理文件将共享第一个批处理文件的窗口。

可以使用 start /b second.bat 命令来异步地从第一个批处理文件中启动第二个批处理文件,这样第二个批处理文件就可以共享第一个批处理文件的窗口。如果两个批处理文件同时向控制台输出内容,则输出结果将会重叠并且可能难以辨认。此外,在第二个批处理文件的结尾要加上 exit 命令,否则当所有操作都完成后,你将处于第二个 cmd shell 中。


1
正确。我曾经认为使用/start b会打开一个新窗口,但如果在DOS窗口中执行,则与当前窗口共享。 - VonC

12

3
可以,但在这种情况下我会尽量避免任何额外的步骤。 - VonC
30
我通常不是那么偏执,但让一个匿名的人为我生成那个exe文件不是非常愚蠢吗?可能会注入各种恶意内容。 - Tobias

11

我认为这是运行批处理文件的最简单和最短的解决方案,而不需要打开DOS窗口,在想要定期运行一组命令时,DOS窗口经常会分散注意力,这是您的解决方案。 使用VBS脚本调用批处理文件...

Set WshShell = CreateObject("WScript.Shell" ) 
WshShell.Run chr(34) & "C:\Batch Files\ mycommands.bat" & Chr(34), 0 
Set WshShell = Nothing 

将上述行复制到编辑器中,并使用 .VBS 扩展名保存文件。相应地编辑 .BAT 文件的名称和路径。


1
有趣的方法,肯定比我的解决方案更短。+1 - VonC
很好的解决方案。 阅读 此链接 我注意到并不真正需要使用 Set WshShell = Nothing,我的情况下可以正常工作,而且你可以有更简单的方法来实现它。 - Patrick Bard

7

如果要自我隐藏,您可以使用getCmdPID.batwindowMode.bat

@echo off

echo --- self hiding bat ----
pause
call getCmdPid.bat
set PID=%errorlevel%
call windowMode.bat -pid %PID% -mode hidden

这是我收集的一些实现方法,甚至更多 - 在可能的情况下,我尝试返回启动进程的PID(所有链接的脚本都可以下载并保存为您方便的任何名称):
  1. 即使在旧的win 95/98机器上,也可以使用IEXPRESS解决方案。Iexpress是一个非常古老的工具,仍然与Windows捆绑在一起 - 仅接受命令及其参数作为参数。

示例用法:

call IEXPhidden.bat "cmd /c myBat.bat"  "argument"
  1. SCHTASKS - 只接受两个参数 - 命令和参数。还会检查是否使用提升的权限启动,并尝试使用WEVTUTIL(从Vista及以上版本可用,因此较新版本的Windows将收到PID)命令获取进程的PID。

示例用法:

call SCHPhidden.bat "cmd /c myBat.bat"  "argument"
  1. 'WScript.Shell' - 这个脚本是'WScript.Shell'的完整包装器,每个可能的选项都可以通过命令行选项进行设置。它是一个jscript/batch混合体,可以被称为一个批处理文件。

使用示例(更多信息请使用“-h”打印帮助):

call ShellRunJS.bat "notepad.exe" -style 0 -wait no 
  1. 'Win32_ProcessStartup' - 再次提供完整的封装,所有选项都可以通过命令行参数访问。这次是WSF / batch混合使用了一些Jscript和一些VBScript代码-但它返回已启动进程的PID。如果进程未隐藏,则可以使用某些选项,例如X / Y坐标(不适用于每个可执行文件-但例如cmd.exe接受坐标)。

示例用法(有关更多信息,请使用“-h”打印帮助):

call win32process.bat "notepad" -arguments "/A openFile.txt"  -showWindows 0 -title "notepad"
  1. 这是一个NET解决方案。大多数ProcessStartInfo选项都被使用了(但最后我太累了,没包含所有选项):

示例用法(要获取更多信息,请使用“-h”打印帮助):

call ProcessStartJS.bat "notepad" -arguments "/A openFile.txt"  -style Hidden -directory "." -title "notepad" -priority Normal

3

可以使用“runas”或在Windows计划任务中以不同的用户身份安排运行,以不同的用户名运行它。


可能可以实现,但不完全符合我的要求(直接在后台进行异步调用)。 - VonC

2
在另一个问题中,我建议使用autoexnt。在这种情况下也可以使用它。只需将服务设置为手动运行(即不自动启动),当您想要运行批处理时,修改autoexnt.bat文件以调用所需的批处理文件,并启动autoexnt服务。
启动此服务的批处理文件可能如下(未经测试):
echo call c:\path\to\batch.cmd %* > c:\windows\system32\autoexnt.bat
net start autoexnt

请注意,以此方式启动的批处理文件将作为系统用户运行,这意味着您无法自动访问网络共享。但是,您可以使用 net use 连接到远程服务器。
您需要 下载 Windows 2003 资源工具包 才能获得它。资源工具包也可以安装在其他版本的Windows上,如Windows XP。

1
有趣,但对于这种情况来说过于复杂了。 - VonC

2

我知道这个问题已经有了答案,但如果有人偶然遇到这个问题,这可能会有所帮助:

以下是一种完全在后台运行的好方法,没有任何查看它的方式。你唯一能与它交互的方式就是使用任务管理器或进程管理器来终止它。

这里使用了一个名为 NirCmd 的第三方工具。

  1. 创建一个包含以下代码的脚本:
@echo off
nircmd exec hide "MainScript.bat"
  1. 将其另存为您喜欢的任何名称。"MainScript.bat"可以是任何东西,但请注意以备后用。

  2. 现在,使用您之前记下的名称创建另一个脚本。例如,我将其命名为MainScript.bat,并给它添加以下代码:

@echo off
echo Can you see me now?
pause 
exit
  1. 这是你想要在后台执行的代码。

  2. 确保它们在同一个目录中,并将 NirCmd 下载到同一个目录中。

以下是这些脚本的结果:

演示GIF

NirCmd 下载链接

演示 ZIP 文件

注意:NirCmd 不是我的工具,但它仍然很有用。


哈哈,未被阻止的CMD是我在服务允许使用批处理脚本但不允许使用命令提示符时使用的工具。nircmd.exe不是我的工具,你可以通过谷歌搜索找到原始作者。 - i Mr Oli i
正确的链接是:https://www.nirsoft.net/utils/nircmd.html,来自[Nir Sofer](https://www.nirsoft.net/about_nirsoft_freeware.html)。然而,正如[这里所说的](https://twitter.com/AaronFriel/status/1162218034582265858):“如果Nir Sofer发布源代码,我会有不同的感受。” - VonC
我没有改变任何东西,只是将一个直接的镜像上传到我的GitHub。 :) - i Mr Oli i

0

你也可以使用

start /MIN notepad.exe

PS: 不幸的是,最小化窗口状态取决于运行的命令。很抱歉 V.G. 不能工作

start /MIN calc.exe

0

你可以通过一个 .vbs 文件来运行你的 .bat 文件
将以下代码复制到你的 .vbs 文件中:

Dim WshShell
Dim obj
Set WshShell = WScript.CreateObject("WScript.Shell") 
obj = WshShell.Run("C:\Users\file1.bat", 0) 
obj = WshShell.Run("C:\Users\file2.bat", 0)  and so on
set WshShell = Nothing 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接