一段时间后,无限批处理脚本将停止

时间:2016-01-03 09:15:00

标签: windows batch-file vbscript batch-processing

我创建了一个批处理脚本文件来检测某个事件的发生。然后我使用以下代码将该批处理文件作为后台进程运行,保存在.vbs文件中:

CreateObject("Wscript.Shell").Run """" & WScript.Arguments(0) & """", 0, False

我不知道为什么在1-2小时之后,这项工作的过程将会消失,或者我不知道为什么这项工作不会在没有任何中断的情况下连续运行,正如其设计和计划的那样。

任何人都可以告诉我为什么吗?以及如何解决这个问题?我的意思是如何使我隐藏的批处理文件无限期地运行?

这是批处理文件

@ECHO OFF
set count=0
:LOOP
REM To Check the battery status, providing that 1 is discharging
REM and 2 is connected to the AC
for /F "delims== tokens=1,2" %%a in (
    'WMIC Path Win32_Battery Get BatteryStatus /format:textvaluelist.xsl'
) do @if "BatteryStatus"=="%%a" call :DoStaff "%%b"
:DoStaff
IF %~1 EQU 2 (
    if %count% NEQ 0 (
        set count=0
        netsh interface set interface name="Wi-Fi" admin=enabled
        netsh wlan connect name=GUEST
        REM will delay execution of the next command by 10 seconds
        TIMEOUT /T 10
    )
) 
IF %~1 NEQ 2 (
    set /a count=%count%+1
    if %count% EQU 1 (
        REM Disable the wireless interface
        netsh interface set interface name="Wi-Fi" admin=disabled
    )
)
TIMEOUT /T 60 /NOBREAK > nul
GOTO :LOOP

3 个答案:

答案 0 :(得分:4)

@ECHO OFF
set count=0
:LOOP
REM To Check the battery status, providing that 1 is discharging and 2 is connected to the AC   
for /F "delims== tokens=1,2" %%a in ('WMIC Path Win32_Battery Get BatteryStatus /format:textvaluelist.xsl') do @if "BatteryStatus"=="%%a" call :DoStaff "%%b"

:: You are CALLing the following routine. 
:: IF the routine was to terminate then batch would return to here on termination.
:: BUT the routine doesn't terminate - it loops back to LOOP
:: (Which invokes another CALL, loop back to LOOP ) ad infinitum
:: eventually, you run out of stack space and the batch terminates.

:: Fix : Loop back here

GOTO LOOP

:DoStaff
IF %~1 EQU 2 (
    if %count% NEQ 0 (
    set count=0
    netsh interface set interface name="Wi-Fi" admin=enabled
    netsh wlan connect name=EPFL-GUEST
    REM will delay execution of the next command by 10 seconds
    TIMEOUT /T 10
)
) 
IF %~1 NEQ 2 (
    set /a count=%count%+1
        if %count% EQU 1 (
        REM Disable the wireless interface
        netsh interface set interface name="Wi-Fi" admin=disabled
)
)
TIMEOUT /T 60 /NOBREAK > nul

:: Here you need to terminate the subroutine.
:: You could simply make thsi end-of-file,
:: But this following line forces the issue.
:: note that the colon before EOF is mandatory.
:: batch understands "GOTO :EOF" to mean, very specifically,
:: Go To End of physical file

GOTO :EOF

:: This following gotoline is not needed. it should be deleted.
GOTO :LOOP

每次CALL子例程时,都会向堆栈添加1个返回地址。由于您永远不会终止子例程(通过到达文件结尾或EXIT语句),因此最终会耗尽堆栈空间。

答案 1 :(得分:3)

如果我正确理解您的脚本,您想在计算机使用电池时关闭无线适配器,并在电源恢复时重新打开。我的建议是减少批处理脚本中的代码以打开/关闭适配器:

@echo off

set "interface=Wi-Fi"
set "network=EPFL-GUEST"

REM get battery state (1 => discharging, 2 => connected to AC)
for /f "delims== tokens=1,2" %%a in (
    'wmic Path Win32_Battery Get BatteryStatus /format:textvaluelist.xsl'
) do if "BatteryStatus"=="%%a" set "BatteryState=%%b"

REM get wireless interface state
for /f "tokens=3" %%a in (
  'netsh interface show interface "%interface%" ^| find /i "administrative state"'
) do set "InterfaceState=%%~a"

if %BatteryState% equ 2 (
    if /i "%InterfaceState%"=="disabled" (
        netsh interface set interface name="%interface%" admin=enabled
        netsh wlan connect name="%network%"
    )
) else if /i "%InterfaceState%"=="enabled" (
    netsh interface set interface name="%interface%" admin=disabled
)

并更改计划任务以在启动时运行批处理脚本(不使用VBScript启动程序),无限期地重复每一分钟。

Scheduled Task trigger: Begin at startup, repeat every minute indefinitely.

该任务还应配置为运行用户是否已登录(您的帐户需要"log on as batch job" privilege)。

Scheduled Task setting: Run whether user is logged on or not, don't store the password.

答案 2 :(得分:3)

我更喜欢Ansgar's solution。但是可以让你的原始设计发挥作用。

Magoo identified why your script eventually fails,但你的逻辑还有一个额外的缺陷。

您将count初始化为0,这意味着您假设在启动时,AC已连接,并且已启用WiFi。

但如果AC已连接且WiFi恰好被禁用,那么您的代码永远不会启用WiFi。

以下是解决问题的一种方法。

@echo off

:: Force the initial iteration to always enable or disable WiFi
set "priorState=0"

:LOOP
for /F "delims== tokens=1,2" %%a in (
  'WMIC Path Win32_Battery Get BatteryStatus /format:textvaluelist.xsl'
) do if "%%a"=="BatteryStatus" call :DoStuff "%%b"
goto :LOOP

:DoStuff
if %~1 neq %priorState% (
    if %~1 equ 2 (
        %= Connected to AC, so enable WiFi =%
        netsh interface set interface name="Wi-Fi" admin=enabled
        netsh wlan connect name=EPFL-GUEST
    ) else (
        %= Discharging battery, so disable WiFi =%
        netsh interface set interface name="Wi-Fi" admin=disabled
    )
    set "priorState=%~1"
)
timeout /t 60 /nobreak > nul
exit /b

可以将所有内容放在一个无限的FOR / L循环中,这样就不需要CALL和GOTO。但是,必须使用延迟扩展,以便循环可以看到更改的priorState值。

@echo off
setlocal enableDelayedExpansion

:: Force the initial iteration to always enable or disable WiFi
set "priorState=0"

:: Infinite loop
for /l %%N in () do (
  for /f "delims== tokens=1,2" %%A in (
    'wmic path Win32_Battery get BatteryStatus /format:textvaluelist.xsl'
  ) do if "%%A"=="BatteryStatus" if "%%B" neq "!priorState!" (
    %= Battery state has changed =%
    if %%B equ 2 (
      %= Connected to AC, so enable WiFi =%
      netsh interface set interface name="Wi-Fi" admin=enabled
      netsh wlan connect name=EPFL-GUEST
    ) else (
      %= Discharging battery, so disable WiFi =%
      netsh interface set interface name="Wi-Fi" admin=disabled
    )
    set "priorState=%~1"
  )
  timeout /t 60 /nobreak > nul
)