I have a batch file I need to run ever x minutes. I know how to set up the scheduled task but I'm not sure if there is a parameter I can use to take advantage of the advanced setting "Stop the existing instance".
Basically, I want to be able to run the batch file every x minutes and when it runs again, if for some odd reason the first instance did not complete, I need it to be killed and the new instance to run.
Right now, I'm using:
schtasks /create /tn [TASKNAME] /tr C:\[DIR]\au.bat /sc MINUTE /mo 15 /ru "System"
which is great, but it lacks this extra part.
I already know the GUI is an option but the reason I am using the command prompt is that this is included in an installer clients will be using to make things easy for them and I don't want them to have to take this last step of going into the GUI to make this one change.
EDIT:
Ended up going with something like this:
REM Checks to see if any instances of 'MYTITLE'
FOR /F "tokens=* USEBACKQ" %%F IN (`tasklist /v /fo csv ^| findstr /i MYTITLE`) DO (
FOR /F "tokens=2 delims=," %%B IN (%%F) DO (
taskkill /pid %%B /f
)
)
title=MYTITLE
[BATCH FILE DOES STUFF HERE]
At launch, it looks to see if there are any instances that match MYTITLE and then kills those tasks. Then names itself and runs the batch. If it stays open, it will be killed next time the task it run.
Actually, the quick and easy answer to my question is to simply set up the task in Task Scheduler in the GUI and when all parameters are set, just export the xml file. Once this is done, you just have to create using the /xml option.
schtasks /create /tn [TASKNAME] /XML C:\[DIR]\schedule.xml
You can store the STATUS (i.e. {START, STOP, RUNNING, ...}) of your application along with its PID in environment variables.
For example (environment variables):
MY_APP_STATUS = 1
MY_APP_PID = 1234
For getting PID, see:
getting process ID of exe running in Bat File,
how to get own process pid from the command prompt in windows
In your batch script, you can kill the running batch if the environment variable is set using the PID.
You can use taskkill command to do this:
taskkill /pid 1234 /f
You need to reset the STATUS flag after killing the existing running batch and update the PID with the new running instance.
Related
I'm working on a batch file that is supposed to START a process (CMD) and then it should kill the process after finished. Problem is, that Imagename is cmd.exe and the other problem is that it should be running on Jenkins.
This is what I have tested:
Getting PID with wmic using name of window to find process -> Failed at Jenkins
Taskkill by naming the window-> Failed because Jenkins does not
display windows due to security issues.
Taskkill by imagename -> Failed because there are other cmd processes
running at the same time
Taskkill with pid but pid from the last cmd started. -Works but it is
not very safe.
I couldnĀ“t understand how wmic works but as I see, I cannot start a process with a command like with START command.
Conditions:
It can't be kill after some time because I need the output from the
mergetool and sometimes mergetool can take too long.
It should run at same time with other (cmd) processes // Jenkins
My question, is there a way of getting the PID from the START Command?
Here are some questions that helped me a lot!
Windows batch file : PID of last process?
Compare number of a specific process to a number
CODE:
set "console_name=cmd.exe"
set "git_command=%gitcmd% mergetool ^>output.txt"
tasklist /FI "imagename eq %console_name%" /NH /FO csv > task-before.txt
START "mergetool_w" CMD /c %git_command%
tasklist /FI "imagename eq %console_name%" /NH /FO csv > task-after.txt
for /f "delims=, tokens=2,*" %%A in ('fc /L /LB1 task-before.txt task-after.txt') do set pid=%%A
pid=!pid:"=!
echo pid is %pid%
TASKKILL /t /pid %pid% /f
You could actually use findstr for checking what tasks have been added after your start command line, relying on your files task-before.txt and task-after.txt:
findstr /LXVG:task-before.txt task-after.txt
Due to a nasty bug, this might under some circumstances lead to an unexpected output. To prevent that, add the /I option, if you can live with case-insensitive searches:
findstr /ILXVG:task-before.txt task-after.txt
Yes it's very possible. I'm going to take code from my previous awnser on another post here: Stop Execution of Batch File after 20 Seconds and move to Next
I want to first assume "mergetool_w" is the name of the CMD you are opining with the start...
The way you want to go about this is to search the tasklist for your console title and extract the PID# out of the context. The find suffix can be used to "Filter" the results along with tokens=2 to extract only the PID#.
FOR /F "tokens=2" %%# in ('tasklist /v ^| find "mergetool_w"') do set PID=%%#
From there, you can now kill this new window using the taskkill /pid command. The PID# is stored in the string %PID% so the command is simple:
taskkill /pid %PID% /t /f
Finaly, it looks as if you are trying to "Log" the data so feel free to put > text-task.txt where it's needed.
I need to create a windows batch file (*.bat) file that only runs its commands if certain processes (and batch files) are NOT running.
I have looked at a solution that works for processes (*.exe) here:
How to wait for a process to terminate to execute another process in batch file
I want to do something very similar, however, there is one difficulty: Batch files show up as "cmd.exe" in the "TASKLIST" command.
I want to check if a specific bat file is running, for example: "C:\mybatch.bat", and if it is, wait until it is closed.
Checking if a specific bat file mybatch.bat is running could be a tougher task than it could look at first sight.
Looking for a particular window title in tasklist /V as well as testing CommandLine property in wmic process where "name='cmd.exe'" get CommandLine might fail under some imaginable circumstance.
1st. Can you
add title ThisIsDistinguishingString command at beginning of the mybatch.bat and
remove all other title commands from mybatch.bat and
ensure that mybatch.bat does not call another batch script(s) containing a title command?
Then check errorlevel returned from find command as follows:
:testMybatch
tasklist /V /FI "imagename eq cmd.exe" | find "ThisIsDistinguishingString" > nul
if errorlevel 1 (
rem echo mybatch.bat batch not found
) else (
echo mybatch.bat is running %date% %time%
timeout /T 10 /NOBREAK >NUL 2>&1
goto :testMybatch
)
2nd. Otherwise, check if wmic Windows Management Instrumentation command output could help
wmic process where "name='cmd.exe'" get /value
Then you could detect mybatch.bat in its output narrowed to
wmic process where "name='cmd.exe'" get CommandLine, ProcessID
Note that wmic could return some Win32_Process class properties, particularly CommandLine, empty if a particular process was launched under another user account or elevated (run as administrator).
Elevated wmic returns all properties in full.
What you say happens by default.
To test, crate a new .bat file (let's say 1.bat) and put in it
calc
mspaint
Save and run it.
Calculator will start. You will notice that Paitbrush will launch only when you have closed calculator.
can someone think of a solution for something like this? :
Program/script logic: It would constantly monitor the windows OS for a process starting within it (***1.exe) (I guess it could constantly run via task scheduler to do the constant monitoring?) , while it sees that ***1.exe is running, it would kill/end another process ***2.exe, and once ***1.exe would go away, it would no longer be stopping the ***2.exe process.
I think it could be either a bash script, powershell script, or a windows service?
Thanks!!!
You can use the Register-CimIndicationEvent cmdlet to register for events raised by Win32_ProcessStartTrace WMI class:
# Define which events to listen for
$NewProcessQuery = "SELECT ProcessId,ProcessName FROM Win32_ProcessStartTrace WHERE ProcessName LIKE '%1.exe'"
# Define the code to run every time a new process is created
$ProcessAction = {
# See if any instances of *2.exe processes are running
if(($TargetProcess = Get-CimInstance -ClassName Win32_Process -Filter "Name LIKE '%2.exe'"))
{
# Terminate them
$TargetProcess |Invoke-CimMethod -MethodName Terminate
}
}
# Register for the event
Register-CimIndicationEvent -Query $NewProcessQuery -SourceIdentifier ProcessCreated
So since the solution above was for only windows 2012 and up, I decided to try another solution. This should work for regular processes, but I'll have to try something else rather than %ERRORLEVEL% because the process I'm monitoring is originally an msi installer and seems like it returns and errorlevel of 1 all the time (running or not) while regular processes return 0 or 1 depending on the status. The process I'm ending starts back up automatically, that's the reason there's no start service command included in here, timeout was set to 62 seconds because the service starts back up automatically every 60 seconds, a /NOBREAK can be added if wanted to eliminate the possibility of user input starting it (if this would be ran without a task scheduler,etc.)
:loop_check
TIMEOUT /T 62
TASKLIST /FI "IMAGENAME eq process.exe" 2>NUL | find /I /N "process.exe">NUL
IF "%ERRORLEVEL%"=="0" (
GOTO stop_process2
) ELSE (
GOTO loop_check
)
:stop_process2
ECHO killing task
TASKKILL /F /IM process2.exe
GOTO loop_check
Read my previous reply/comment before this one for more clarity. This is the final solution that worked for me. A star(*) is included at the end of the 'BeginningOfApplicationName' because the installer/msi I'm detecting has sometimes different names based on it's version, so it finds/finishes the ending (wildcard). Since the name of the process I'm monitoring can have different names, I couldn't compare it to a static string, so I'm comparing it to INFO: , seems thats what windows (2008 and 2012!) both print out when a process is not found.
#ECHO OFF
SETLOCAL EnableExtensions
:loop_check
TIMEOUT /T 62
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq BeginningOfApplicationName*"') DO IF %%x == INFO: (
GOTO loop_check
) ELSE (
GOTO stop_process
)
:stop_process
TASKKILL /F /IM process.exe
GOTO loop_check
I want to create a task in task shaduler on windows which executed a xx.bat program whenever the program isn't running. The question is, how can i check the program is running or not whenever my computer is ready/on. So i just want to check the bat isn't running. When the bat isn't running, the task shaduler will run the bat.
If it was an exe you want to check, Stephan's comment would do it. But running bat files are just shown as cmd.exe in the task list as long as you don't give the process a name. So the point is to start your bat file with a certain "name". You can achieve this starting with this command:
start "somename" xx.bat
Now it can be found with tasklist and findstr easily:
#ECHO OFF
SET running=0
FOR /f "tokens=*" %%A IN ('tasklist^ /v^| findstr /i /c:"somename"') DO SET running=1
IF NOT %running%==1 (
start "somename" c:\SomePath\xx.bat
)
There is this application build process that I am trying to automate. For this i wrote a java file, which runs every 24 hours.
A batch file is called from here that runs the application build whenever it is called.
I've run into a small problem, when the build fails due to incomplete or invalid files, a window pops up which tells me to look at the logs.
Since I haven't written the build files, I'm not really sure where this gets created from. I wanted to know if I can close this window while the process runs from the bat file.
It may be possible using taskkill, but you'd have to devise a filter that would ideally only match the process displaying the window and never match any other process. Something like:
taskkill /im program.exe
or maybe:
taskkill /fi "windowtitle eq title*"
You might also want to include the /f flag for forceful termination.
You'd also have to try and make sure that the taskkill command doesn't run too quickly and precede the creation of the popup window. You could try to query for the existence of such a process/window; your best bet here is probably wmic. Maybe:
#echo off
setlocal enabledelayedexpansion
set title=Notepad
set pid=
for /f %%i in ('wmic process where "caption like \"%%!title!%%\"" get processid^| findstr /r [0-9]') do #set pid=%%i
if "!pid!" neq "" taskkill /f /pid !pid!
There's no guarantee this will always work, but it's probably the best you can do.