I've checked other tons of answers related to my issue and none worked. I suppose it's a syntax typo, but I cannot seem to find it.
My script should simply tell me if a process is running, then save the path into a variable, go to that path and delete the .exe.
Unfortunately, I get ECHO is OFF. Any ideas why?
#echo off
setlocal EnableDelayedExpansion
set /p PROGRAM=NAme of the exe:
tasklist /FI "IMAGENAME eq %PROGRAM%" 2>NUL | find /I /N "%PROGRAM%">NUL
if "%ERRORLEVEL%"=="0" echo. %PROGRAM% is running
for %%i in (%PROGRAM%) do (
echo %%~$PATH:i
set PROGRAM_PATH=%%~$PATH:i
)
cd %PROGRAM_PATH%
del /F %PROGRAM_PATH%
pause
So, I realized that my program wasn't doing what I wanted because the .exe didn't exist.
So, I modified a little bit the script, so that I will handle that case:
if the .exe is running, exit because I won't be able to delete a already in use .exe anyway;
otherwise go to its location and delete it.
My final program:
#echo off
setlocal EnableDelayedExpansion
goto start_program
:start_program
set /p PROGRAM=Name of exe(ex:cmd.exe):
tasklist /FI "IMAGENAME eq %PROGRAM%" 2>NUL | find /I /N "%PROGRAM%">NUL
if "%ERRORLEVEL%"=="0" do (
goto enter_program
)
if "%ERRORLEVEL%"=="1" do (
goto exit_program
)
:enter_program
for %%i in (%PROGRAM%) do (
set PROGRAM_PATH=%%~$PATH:i
)
cd %PROGRAM_PATH%
del /f %PROGRAM_PATH%
goto:eof
:exit_program
goto:eof
Thanks for tips Ryan and jeb
Related
I'm working on a cmd script and want to find some processes in the tasklist. So what I have is an array like "prog[0]=devcpp.exe, prog[1]=notepad.exe..."
And to find these processes I'm using FOR command. Ok, but when I execute the command "tasklist /fi" it seems won't recognize the array, and don't give me the expected result.
The code is:
set prog[0]=devcpp.exe
set prog[1]=notepad.exe
set prog[2]=calc.exe
FOR /l %%a IN (0,1,2) DO (
tasklist /fi "IMAGENAME eq %prog[%%a]%"
)
But the result is:
error: the search filter cannot be recognized
And of course I am running these processes...
So, any suggestions?
First, remove the trailing QUOTATION MARK character on the prog[2] setting.
Secondly, when invoking tasklist, the PERCENT character must be doubled to retain one. And, use the command line interpreter. %ComSpec%, to interpret the variable.
set prog[0]=devcpp.exe
set prog[1]=notepad.exe
set prog[2]=powershell.exe
FOR /l %%a IN (0,1,2) DO (
"%ComSpec%" /C tasklist /fi "IMAGENAME eq %%prog[%%a]%%"
)
You have given no clue as to what the end goal is about. It would likely be easier to code this in PowerShell as #Bill_Stewart suggested.
Here is my suggestion for this task with a commented batch file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Delete all environment variables of which name starts with prog[.
for /F "delims==" %%I in ('set prog[ 2^>nul') do set "%%I="
rem Define environment variables with the executables to get listed.
set "prog[0]=devcpp.exe"
set "prog[1]=notepad.exe"
set "prog[2]=calc.exe"
rem Run TASKLIST in a loop to get output a list of those processes
rem from the list defined above which are currently running with the
rem header output on English Windows just on first running process.
set "Header=1"
for /F "tokens=1* delims==" %%I in ('set prog[') do if defined Header (
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %%J" 2>&1 | %SystemRoot%\System32\findstr.exe /B /I /L /V /C:"INFO:"
if not errorlevel 1 set "Header="
) else (
%SystemRoot%\System32\tasklist.exe /NH /FI "IMAGENAME eq %%J" 2>nul
)
endlocal
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
findstr /?
for /?
if /?
rem /?
set /?
setlocal /?
tasklist /?
My code below doesn't work
echo will now go ahead and load the essential programs needed for
project: %project%
set "programlistopen=sublime_text.exe xampp-control.exe"
for /f "delims=" %%j in (%programlistopen%) do (
if %%j=="sublime_text"(set pathtopen=%defaultpath%\Sublime_Text&&set
dirpath="%workdirectory%\%project%") else
if %%j=="xampp-control.exe"(set pathtopen=%xampp%\&&set dirpath=)
tasklist /FI "IMAGENAME eq %%j" 2>NUL | find /I /N "%%j">NUL
if "%ERRORLEVEL%"=="1" goto notstartedsublimetext
if "%ERRORLEVEL%"=="0" goto startedsublimetext
:notstartedsublimetext
Echo started %%j at %time%
pause
start /d "%pathtopen%" %%j %dirpath%
:startedsublimetext
echo %%j is already running......
)
I would suggest possibly changing the structure to this:
#Echo Off
For %%A In ("C:\Program Files\SomeName\madeup.exe"
"C:\Users\Vibrations\Portables\Some Name\dummy.exe"
"C:\Windows\built-in.exe"
) Do TaskList|FindStr/BRIC:"%%~nxA\>">Nul&&(Echo %%~nxA already running
)||(Start "" "%%~A"&Echo Started %%~nxA at %TIME%)
Pause
Just list the full paths to the executables you want to check/start similarly to the three I've used as an example
Edit
As a result of the latest comment, here is an example of what I assume you're trying to do by way of your modification, (replace from line 6):
)||(If "%%~nxA"=="sublime_text.exe" (Start "" "%%~A" "%workdirectory%\%project%"
) Else Start "" "%%~A"
Echo Started %%~nxA at %TIME%)
Pause
#echo off
setlocal
#rem Variables to be set.
#rem changedir is an optional pushd on each call of :notstarted.
#rem startdir is passed to the /d argument in the start command.
#rem programpath is the path to the program executable.
#rem args are any arguments to pass to the program executable.
#rem Variables are undefined at start of loop.
echo will now go ahead and load the essential programs needed for project: %project%
set "programlistopen=wordpad.exe notepad.exe"
for %%j in (%programlistopen%) do (
for %%B in (changedir startdir programpath args) do set "%%~B="
if "%%~j" == "wordpad.exe" (
set "changedir=%userprofile%"
set "startdir=%cd%"
set "programpath=C:\Program Files\Windows NT\Accessories"
) else if "%%~j" == "notepad.exe" (
rem Nothing to set. Just start notepad.exe.
)
tasklist /FI "IMAGENAME eq %%~j" 2>NUL | find /I /N "%%~j" >NUL
if errorlevel 1 (
call :notstarted "%%~j"
) else call :started "%%~j"
)
exit /b
:notstarted
setlocal
echo started "%~1" at %time%
set "cli=start """
if defined startdir set "cli=%cli% /d "%startdir%""
if defined programpath (
set "cli=%cli% "%programpath%\%~1""
) else set "cli=%cli% "%~1""
if defined args set "cli=%cli% %args%"
if defined changedir pushd "%changedir%"
echo %cli%
%cli%
if defined changedir popd
exit /b
:started
echo "%%~1" is already running......
exit /b
Your code has many unknowns so I have done an example which you
can adapt to your needs.
I chose some simple programs like notepad and wordpad to test with.
Variables for use are commented at the top of the script. These
variables are undefined at start of each loop so you do not need
to undefined them and just use the variables that you want to set
with each program.
The errorlevel of tasklist is checked and will call the name of
the label required. This allows the call to return back to the
position of the caller so the loop can continue.
The :notstarted label will bulid the command line (cli) with
each of the defined variables that are relevent to the cli. The
optional pushd and popd was added just for an unusual use.
I have a program which has following flow. Problem is the windows batch file doesn't properly checks errorlevel and doesn't set KILLSTS value. Could you please let me know what's wrong with this program and how to fix this?
Ask user to open an exe
if Yes
check exe is running or not
if running, ask user whether to close that exe
if yes close exe
run the exe
else
exit
Here is the sample batch file.
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P AREYOUSURE="Open Spring STS [y/n]>"
set AREYOUSURE=%AREYOUSURE:~0,1%
ECHO AREYOUSURE=%AREYOUSURE:~0,1%
IF /I %AREYOUSURE% == N (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" |find ":" > nul
ECHO Error %errorlevel%
IF %errorlevel% neq 0 (
SETLOCAL
SET /P KILLSTS="Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set KILLSTS=%KILLSTS:~0,1%
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
ENDLOCAL
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
I am getting below error
You need to learn how to properly format if statements.
You are formatting them as:
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
When they should be formatted as:
if /i "%KILLSTS%"=="Y" (TASKKILL /f /im STS.exe)
The formatting doesn't really matter as such in simple batch files, but it's best to use the correct syntax which can handle special characters such as SPACES, AMPERSANDS, QUOTES, PIPE for when more complex variables are involved.
Updated script:
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P "AREYOUSURE=Open Spring STS [y/n]>"
set "AREYOUSURE=%AREYOUSURE:~0,1% "
echo "AREYOUSURE=%AREYOUSURE:~0,1%"
IF /I "%AREYOUSURE%"=="N" (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" | find ":" > nul
ECHO Error %errorlevel%
IF "%errorlevel%" neq "0" (
call :escapeexpansion
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
exit /b
:escapeexpansion
SETLOCAL
SET /P "KILLSTS=Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set "KILLSTS=%KILLSTS:~0,1%"
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I "%KILLSTS%"=="Y" TASKKILL /f /im "STS.exe"
ENDLOCAL
goto :EOF
The entire structure seems wrong to me; as well as pointlessly using SET /P instead of CHOICE.
#ECHO OFF
TASKLIST /FI "IMAGENAME eq STS.exe"|FIND ":">NUL 2>&1&&GOTO ASKIF
CHOICE /M "Spring STS is running. Kill STS Process"
IF ERRORLEVEL 2 GOTO ENDIT
TASKKILL /F /IM "STS.exe"
TIMEOUT 3 /NOBREAK>NUL
:ASKIF
CHOICE /M "Open Spring STS"
IF ERRORLEVEL 2 GOTO ENDIT
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
:ENDIT
Echo=Exiting Batch
TIMEOUT 3 /NOBREAK>NUL
The past few days I have been working on a script that I thought would be rather easy but it seems not, and I do understand why. My problem is how to get around it.
The batch script I need explained:
I have a script that runs in cmd.exe that does a bunch of things like moving a huge amount of files from a location to another. Lets call it
movefile.cmd. This script works, but happens to stop sometimes (very rarely - lets not go into why and that script). Its important that this script always runs, so my idea here was to create a batch that exits cmd.exe and then re-opens the script each hour or so. Lets call this script restartcmd.bat
Sounds perfectly easy as I could do this:
#echo off
:loop
start c:\script\movefile.cmd
Timeout /nobreak /t 3600
Taskkill cmd.exe
goto loop
But obviously this doesn't work because my new script also runs in cmd.exe, so it would kill this process as well.
What I've tried:
So I made a copy of cmd.exe and renamed it into dontkillthis.exe. I run dontkillthis.exe and then open the restardcmd.bat from dontkillthis.exe - this works perfectly! But I need to be able to just dobbleclick my script instead of doing that. Why? Because its supposed to be as easy as possible and I want my restartcmd.bat to be in my startup folder.
I've been looking at the ideas of getting the exact process ID of cmd.exe and shutting that so that my dontkillthis.exe will remain, but I can't seem to nail it. Tried all thats written in here how to kill all batch files except the one currently running , but I can't get it to work.
I'm not sure if I'm being confused or if it actually is a bit hard to do this.
I'd really appreciate some help here.
Best Regards
MO
first you'll need the PID of the current CMD instance. The topic has been discussed here . I will offer you my solution - getCmdPID.bat
and here's the script (getCmdPID should in the same directory ):
#echo off
call getCmdPID
set "current_pid=%errorlevel%"
for /f "skip=3 tokens=2 delims= " %%a in ('tasklist /fi "imagename eq cmd.exe"') do (
if "%%a" neq "%current_pid%" (
TASKKILL /PID %%a /f >nul 2>nul
)
)
Normally with the following command I should be able to find the PID. Unfortunately this is not the case.
title exclude &tasklist /NH /v /fo csv /FI "WINDOWTITLE ne exclude*" /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"
So to achieve my goal, I used the following command:
FIND /I "exclude" 1>NUL
#echo off
TITLE exclude
(for /f "usebackq tokens=*" %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"`) do (
(
echo %%a | FIND /I "exclude" 1>NUL
) || (
for /f "usebackq tokens=2 delims=," %%i in (`echo %%a`) do (
echo TASKKILL /PID %%~i /f
)
)
)
)>_output-taskill.txt
TYPE _output-taskill.txt
Another approach to kill all the processes in a single line is to use filters on the command taskkill with filters should look like:
TASKKILL /F /FI "PID ne XXXX" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe
eq (equal)
ne (not equal)
gt (greater than)
lt (lesser than)
#echo off
TITLE exclude
(for /f "usebackq tokens=2 delims=," %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running" ^| FIND /I "exclude"`) do (
echo TASKKILL /F /FI "PID ne %%~a" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe
)
)>_output-taskill.txt
TYPE _output-taskill.txt
I have found a solution that utilizes text files to keep track of all previous PIDs the bat file has had. It attempts to kill them silently and then adds the current PID to the list after.
If you don't want it to kill the old, already existing process, simply replace the line that has "taskkill" with whatever you were wanting to do with it.
(might require you to run as admin in order to have permissions to kill the duplicate process. see permission elevation code below for optional implementation if you don't want to have to run as admin every time.)
#echo off
set WorkingDir=%cd%
if exist MostRecentPID.txt ( del "PIDinfo.txt" /f /q ) > nul
cd ..\..\..\..\..\..\..
title mycmd
tasklist /v /fo csv | findstr /i "mycmd" > %WorkingDir%\PIDinfo.txt
set /p PIDinfo=<%WorkingDir%\PIDinfo.txt
REM below, the 11 means get substring starting a position 11 with length of 5 characters. The tasklist command gives a long and verbose value so this will get just the PID part of the string.
set PID5chars=%PIDinfo:~11,5%
set PID4chars=%PIDinfo:~11,4%
if exist PreviousPIDs.txt (
for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
goto CheckIfFourCharPID
)
:CheckIfFourCharPID
if %PID4chars% gtr 8100 (
for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
echo %PID4chars% >> "PreviousPIDs.txt"
) else (
echo %PID5chars% >> "PreviousPIDs.txt"
)
Explanation: (warning: very technical)
-This solution gets a substring of the tasklist command to get just the PID. There will not be a PID for cmd.exe that is greater than 18100 so check if PID4chars is greater than 8100 so we know if it's a 4 digit or 5 digit number
case 1: a 5 digit PID like 17504 has a PID5chars val 17504 and a PID4chars val of 1750, so we add PID5chars to the text files of PIDs to kill
case 2: a 4 digit PID like 8205 has a PID5chars val of 8205" and a PID4chars val of 8205, so we add PID4chars to the text files of PIDs to kill
case 3: a 4 digit PID like 4352 has a PID5chars val of 4352" and a PID4chars val of 4352, so we add PID4chars to the text files of PIDs to kill
OPTIONAL PERMISSION ELEVATION CODE
(put this at the top of your bat file and it will auto-run it as admin.)
#echo off
setlocal DisableDelayedExpansion
set "batchPath=%~0"
for %%k in (%0) do set batchName=%%~nk
cd ..\..\..\..\..\..\..\..
if exist %cd%\Temp (
set temp=%cd%\Temp
goto vbsGetPrivileges
)
if exist %cd%\Windows\Temp (
set temp=%cd%\Windows\Temp
goto vbsGetPrivileges
)
set temp=%cd%
:vbsGetPrivileges
set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
setlocal EnableDelayedExpansion
:CheckIfRunningAsAdmin
net session >nul 2>&1
if %ERRORLEVEL% == 0 (
goto gotPrivileges
) else ( goto ElevatePermissions )
:ElevatePermissions
if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
ECHO args = "ELEV " >> "%vbsGetPrivileges%"
ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
ECHO args = args ^& strArg ^& " " >> "%vbsGetPrivileges%"
ECHO Next >> "%vbsGetPrivileges%"
ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
"%SystemRoot%\System32\WScript.exe" "%vbsGetPrivileges%" %*
exit /B
:gotPrivileges
setlocal & pushd .
cd /d %~dp0
if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul & shift /1)
net session >nul 2>&1
if %ERRORLEVEL% == 0 (
goto Continue
) else (
REM unable to elevate permissions so tell user to run file as admin manually
echo Please re-run this file as administrator. Press any key to exit...
pause > nul
goto Exit
)
:Continue
<insert rest of code here>
It would be much better to get the PID of your movefile.cmd. If you can edit it, add a title MyMoveFileProcess and get it's PID with
for /f "tokens=2" %%i in ('tasklist /v ^|find "MyMoveFileProcess"') do set PID=%%i
Then you can kill it with taskkill /pid %pid%
Instead of changing your movefile.cmd, you can also just start it with an title:
start "MyMoveFileProcess" c:\script\movefile.cmd
A couple of lines will help you achieve this:
TITLE exclude
taskkill /IM cmd.exe /FI "WINDOWTITLE ne exclude*"
Right now, I'm writing a batch file with a line that is identifying if a process is running from my process list.
The line I'm referring to:
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto ProcessFound
EXE is defined beforehand as EXE= My Process Here.exe
My batch file works with normal processes, but as you can see with My Process Here.exe, there is a space between My and Process and Here.exe and this is not recognizable.
Is there any way to fix this? The process I am looking for has spaces and I can't change the process name as the program it is related to will not run if I do.
Thanks.
#ECHO OFF
SETLOCAL
SET "exe=7+ Taskbar Tweaker.exe"
FOR /F %%x IN ('tasklist ^|FINDSTR /i /b /L /c:"%EXE%"') DO IF NOT ERRORLEVEL 1 goto ProcessFound1
ECHO "%exe%" not found
GOTO again
:Processfound1
ECHO "%exe%" found!
:again
SET "exe=I dont exist.exe"
FOR /F %%x IN ('tasklist ^|FINDSTR /i /b /L /c:"%EXE%"') DO IF NOT ERRORLEVEL 1 goto ProcessFound1
ECHO "%exe%" not found
GOTO :eof
:Processfound2
ECHO "%exe%" found!
GOTO :EOF
This may work for you. You'd need to fix the process names of course.
#echo off
setlocal enableextensions disabledelayedexpansion
set "exe=My Process Here.exe"
set "processFound="
for /f "tokens=5 delims=," %%a in ('
tasklist /fi "imagename eq %exe%" /fo:csv /nh
') do set "processFound=1"
if defined processFound (
echo %exe% is running
) else (
echo %exe% is NOT running
)
The tasklist will retrieve the list of processes for for the indicated image name and in csv format, without headers.
There are two options: the process is not running and then there are not csv records in the output, or the process is running and there are csv records in the ouptut.
The for command will try to tokenize the output of tasklist and retrieve the 5th token in the line using commas as delimiters.
If the output from tasklist is a csv record, this token will exist, the replaceable parameter will get data and the code in the do clause will be executed. If the output is not a csv record, the token will not exist, and the code in the do clause will not be executed.
Neither of the prior answers worked for me for identifying imagenames with embedded spaces. What did work for me was to use "delims=tab" where tab is the actual tab character as in:
FOR /F "delims=tab" %%X IN ('tasklist /NH /FI "IMAGENAME eq !EXE!"') DO (...
The resulting %%X will either be the entire tasklist entry corresponding to the !EXE! imagename, if found, or "INFO: No tasks are running which match the specified criteria", if not found, that can be acted on by something like:
SET TASKLINE=%%X
IF "!TASKLINE!"=="!TASKLINE:No tasks are running=!" (
ECHO !EXE! FOUND IN !TASKLINE!
) ELSE (
ECHO !EXE! NOT FOUND IN !TASKLINE!))