0

I'm struggling to get this .bat to work, but it keeps throwing "syntax error". This batch file should get all scheduled tasks matching the name criteria and disable them, waiting for them to terminate their execution if they're running.

Where am I going wrong?

schtasks /Query /nh /fo CSV | findstr /i /c:"searchcriteria" | FOR /f "tokens=1 delims=," %%f IN ('more') DO (
    :loop

    FOR /f "tokens=*" %%a IN ('schtasks /query /nh /fo CSV /tn %%f ^| findstr /i /c:"running"') DO SET task=%%a

    IF [%task%] == [] (
        schtasks /change /tn %%f /DISABLE
    ) ELSE (
        GOTO loop
    )
)
5
  • I believe the systax error results from if as it does not like pipes (|). Perhaps try with if not defined task, or if not^ defined task (^ plus two spaces)... Commented Jun 26, 2018 at 11:19
  • Tried both, still throwing "syntax error" :\ Commented Jun 26, 2018 at 11:35
  • Okay... try to put parentheses around the for loop in addition (so you have ... | (for /F ...)... Commented Jun 26, 2018 at 11:47
  • Nope, still throwing @aschipfl Maybe it's the %%f inside the command in the second for loop? If so how should I write it? Commented Jun 26, 2018 at 11:49
  • 2
    Now I realised there is a goto loop inside of a parenthesised block of code, which cannot work, because goto breaks the block context. I would put the goto loop or even the outer for /F loop into a sub-routine and use call. Furthermore, I'd put timeout 1 into the goto loop in order to avoid heavy processor load... Commented Jun 26, 2018 at 12:04

2 Answers 2

1

What about this (untested):

for /F "tokens=1 delims=," %%F in ('schtasks /QUERY /NH /FO CSV ^| findstr /I /C:"searchcriteria"') do call :LOOP %%F
goto :EOF

:LOOP
    set "task="
    for /F "tokens=*" %%A in ('schtasks /QUERY /NH /FO CSV /TN %1 ^| findstr /I /C:"running"') do set "task=%%A"
    if not defined task (
        schtasks /CHANGE /TN %1 /DISABLE
    ) else (
        > nul timeout 1
        goto :LOOP
    )

This avoids the goto loop to be within a parenthesised block of code, because goto breaks the block context. The value from the first for /F loop in %%F is passed to the sub-routine :LOOP as an argument, which is then read by %1.

Additionally, I replaced more in the first for /F loop by the first schtasks/findstr command line to avoid multiple pipes, like you have done it in your second for /F loop anyway.

Sign up to request clarification or add additional context in comments.

1 Comment

I will try this on the morrow. As for the accepted answer I didn't run particularly elaborated tests apart from a quick run to see if it was working, and it did. I'm not into batch files programming and I just assumed the code to be instant-OK. My bad
1

The following seems to work. I changed the single quotes in the second for loop to double quotes and added parentheses for that loop.

schtasks /Query /nh /fo CSV | findstr /i /c:"time" | FOR /f "tokens=1 delims=," %%f IN ('more') DO (
    :loop
    FOR /f "tokens=*" %%a IN ("schtasks /query /nh /fo CSV /tn %%f ^| findstr /i /c:"running"") DO (
        SET task=%%a

        IF [%task%] == [] (
            schtasks /change /tn %%f /DISABLE
        ) ELSE (
            GOTO loop
        )
    )
)

Update: achipfl is right. His answer works for me

I tried again too and came up with the following solution. First it disables the sheduleing of the task and then end the task. Then if the task is still running it calls the batch file again. I was not sure if you want to end the task. But because you like to wait for the task to finish execution I have assumed that.

@echo off
set querystring="time"

schtasks /Query /nh /fo CSV | findstr /i /c:"%querystring%" | FOR /f "tokens=1,3 delims=," %%f IN ('more') DO (
      if %%g=="running" (
        schtasks /change /tn %%f /Disable
        schtasks /end /tn %%f
      )
)
schtasks /Query /nh /fo CSV | findstr /i /c:"%querystring%" | FOR /f "tokens=1,3 delims=," %%f IN ('more') DO (
      if %%g=="running" (
        call test2.bat
        exit /b 0
      )
)

schtasks /Query /nh /fo CSV | findstr /i /c:"%querystring%"

Update 2: combination

for /F "tokens=1,3 delims=," %%F in ('schtasks /QUERY /NH /FO CSV ^| findstr /I /C:"searchcriteria"') do call :LOOP %%F %%G
goto :EOF

:LOOP
    schtasks /CHANGE /TN %1 /DISABLE
    if %2=="running" schtasks /END /TN %1 & call :WAIT %1
    goto :EOF

:WAIT
    FOR /F "tokens=3 delims=," %%F IN ('schtasks /Query /nh /fo CSV /tn %1') DO set "test=%%F"
    if %test%=="running" GOTO :WAIT

:EOF

3 Comments

Works like a charm! Thank you
This is simply wrong! The single-quotes told for /F that the string is a command line to execute, double-quotes tells that it's a literal string! And a goto loop cannot be used within a parenthesised block of code! I'm really surprised your answer has been accepted...
As pointed out by @aschipfl the last for loop will never set task variable, thus always disabling the task without waiting if it's running.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.