Monitor a start of process in windows, then execute something (stop another process/service) - windows

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

Related

how to kill a cmd process without killing others cmds?

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.

Schtaks - Command Prompt Parameters

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.

i want to run a batch script into my pc when it is locked

i want to run a batch file on my pc for an overnight activity. The problem is that i can't do that because the pc is locked.
I am using this code:
#echo off
tasklist /FI "IMAGENAME eq \\Desktop\notepad.exe" | find /i "\\Desktop\notepad.exe"
IF ERRORLEVEL 1 GOTO LOOP1
IF ERRORLEVEL 0 GOTO EXIT
:LOOP1
start notepad.exe
goto EXIT
:EXIT
and it works only the pc is unlocked.
Any help will matters.
Create a new Scheduled Task. Set the task to run when user is logged in or not. Then set the interval of your task time.
On Windows 8 etc you are able to set triggers on when the task should be kicked of by using either a set time or when PC goes on idle, when an event occurs etc.
There is also an option for On Workstation Lock
If this is not your intention to use scheduler. Then right a script that runs in a permanent loop by adding some sleep time and only rerun the taks every now and again, something like this (untested, just used yours as example)
:START
#echo off
tasklist /FI "IMAGENAME eq \\Desktop\notepad.exe" |find /i "\\Desktop\notepad.exe"
IF ERRORLEVEL 1 GOTO LOOP1
IF ERRORLEVEL 0 GOTO EXIT
:LOOP1
start notepad.exe
timeout 300
goto START
timeout 300 is basically sleeping the script for 300 seconds and will start from START again. We can then run the batch file before locking the PC and it wil lrun in a continuous loop. Even though it might not be the right way, it is an option. Perhaps some more detail around how often the batch file should run?

Batch file wait for another processes to finish before continuing

I have a batch file that I use every time I start my work PC. Basically, it kills all the bloatware that the IT department puts on the PC that run as my user account that I never even use using taskkill, installs a small program, then loads all the programs I actually need at once. Problem is, one of the programs that I run, the IT department recently thought it would be helpful to install a "helper" program to automate some things within the program that I already know how to do and can do it fairly quickly manually. Problem is, the helper program actually has the reverse effect and slows the actual program down. We are of course complaining to IT about it but it'll probably take them months to fix it, if ever. In the meantime, I found out that the helper program runs as it's own process under my user account, which means I can kill it, and everything runs smoothly again. Problem is, how the program runs. I launch the program normally and this happens:
Process A loads. Process A loads process B. Process A kills itself. Process B loads process C. Process C loads process D, E, and F (the helper programs). Process B kills itself, while leaving C, D, E, and F in memory (program is fully loaded at this point)
How can I have the batch file just wait for process B to kill itself, before proceeding with the taskkill commands to kill processes D, E, and F? Since the command line only sees process A when directly calling the EXE, it resumes the batch file in under a second since A kills itself that quickly. I can't just use timeout or some other generic time waster because the load time of the program is too volatile, what with network issues, program updates, etc.
I built something exactly like this a few years ago, but unfortunately don't have the code with me and don't have access to a Windows machine at the moment.
However, it should be fairly simple, and will be along these lines (just tweak the code to get it work or let me know if there are any issues; I can't test it but should be able to fix them if I know what they are):
rem Usage: :killprocesswithwait [pid]
call :killprocesswithwait 1234
:killprocesswithwait
set pid=%1
taskkill /pid %pid%
:iloop
ping 127.0.0.1 -n 2 > nul
for /f "tokens=*" %%a in ('tasklist /fi "PID eq %pid%" ^| find /i %pid%') do (
if /i "%%a"=="" (
goto :eof
) else (
goto :iloop
)
)
This waits for a any and all programs to exit and checks if Notepad and restarts it if it is.
It surely would be better to wait for the three programs to start. Change Win32_ProcessStopTrace to Win32_ProcessStartTrace.
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM Win32_ProcessStopTrace")
Do
Set objReceivedEvent = objEvents.NextEvent
msgbox objReceivedEvent.ProcessName
If lcase(objReceivedEvent.ProcessName) = lcase("Notepad.exe") then
Msgbox "Process exited with exit code " & objReceivedEvent.ExitStatus
WshShell.Run "c:\Windows\notepad.exe", 1, false
End If
Loop
And this lists processes and terminate any called calculator.
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objItem in colItems
'msgbox objItem.ProcessID & " " & objItem.CommandLine
If objItem.name = "Calculator.exe" then objItem.terminate
Next
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q36241667.txt"
SET "filename2=%sourcedir%\q36241667_2.txt"
:dloop
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
tasklist|FIND "%%a" >NUL
IF ERRORLEVEL 1 timeout /t 1 >nul&GOTO dloop
)
FOR /f "usebackqdelims=" %%a IN ("%filename2%") DO ECHO(%%a
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used files named q36241667.txt & q36241667_2.txt containing some dummy data for my testing.
Suppose filename1 contains
processa.exe
processb.exe
processc.exe
processd.exe
processe.exe
then the for loop will wait until all of the processes are running before proceeding.
filename2 contains the kill commands required (echoed for demo purposes)
If this routine is simply started in your startup routine, then it could itself trigger start commands to kill any unwanted processes.
I use a similar routine to back up critical directories to a ramstick on start-up.
Thanks guys, I actually took Ruslan's answer and simplified and changed it a bit. This works great. Waits for exe3 to load since it's the last one to load, then kills all 3. Didn't need to set the variables so removed those and completely forgot about putting it in a loop.
:start
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq exe3.exe"') DO IF %%x == exe3.exe goto found
goto start
:found
taskkill /f /fi "blah1.exe"
taskkill /f /fi "blah2.exe"
taskkill /f /fi "blah3.exe"

Batch file to uninstall a program

I'm trying to uninstall a program EXE via batch file and am not having any success.
The uninstall string found in the registry is as follows:
C:\PROGRA~1\Kofax\Capture\ACUnInst.exe /Workstation
C:\PROGRA~1\Kofax\Capture\UNWISE.EXE /U
C:\PROGRA~1\Kofax\Capture\INSTALL.LOG
If I run that from CMD or batch it does nothing.
If I run C:\PROGRA~1\Kofax\Capture\UNWISE.EXE /U from CMD it will open up a dialog box to point to the INSTALL.LOG file and then proceed to uninstall.
At the end, it will ask me to click finish.
I need this to be silent, can you point me in the right direction? This is on XP and 7.
Every program that properly installs itself according to Microsoft's guidelines makes a registry entry in either HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall (for machine installs) or HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall (for user profile installs). Usually, the key for the program will be its GUID, or else the name of the program. Within that key will be an entry called UninstallString. This contains the command to execute to uninstall the program.
If you already know ahead of time what you will be uninstalling, it should be easy enough to just put that in your batch file. It gets tricky when you try to automate that process though. You can use the reg command to get data from the registry, but it returns a lot of text around the actual value of a given key, making it hard to use. You may want to experiment with using VBscript or PowerShell, as they have better options for getting data from the registry into a variable.
This might help you further.....
How to Create a script via batch file that will uninstall a program if it was installed on windows 7 64-bit or 32-bit
I've had the same problem and this is what I came up with.
Before you start using this method though, you might wanna look up the name of the application on WMIC using CMD so..
First you wanna do: WMIC product > C:\Users\"currentuser"\Desktop\allapps.txt
I'd recommend to output the command to an TXT file because it's really confusing to read it in the Cmd prompt, plus is easier to find the data you are looking for.
Now what you wanna do is find the actual name of the app... If you look at the code I put in, the app name says SkypeT because skype has "™" in the end of it and the command prompt can't interpretate that as it is.
After you got the app name, just put in the find in the 4th line and substitute, a few lines which contain my examples with skype...
Also you can probably creat a variable called %APP% and not worry as much, but at it's current it works just fine...
One thing to note! with me the msi /quiet command did not work, the program would not install or uninstall so I used /passive, which lets the users see what's going on.
#Echo off
CD %cd%
:VerInstall
for /f "tokens=12,*" %%a in ('wmic product list system ^| Find /I "SkypeT"') do (
if Errorlevel = 0 (
Echo Skype is installed! )
if Errorlevel = 1 ( Echo Skype is not installed, proceding to the installation!
Ping localhost -n 7 >nul
goto :Reinstall )
)
:Status
tasklist /nh /fi "IMAGENAME eq "APP.exe" | find ":"> nul
if errorlevel = 1 goto :force
goto :Uninstall
:Force
echo We are killing the proccess... Please do not use the application during this process!
Ping localhost -n 7 > nul
taskkill /F /FI "STATUS eq RUNNING" /IM APP* /T
echo The task was killed with success! Uninstalling...
Ping localhost -n 7 > nul
:Uninstall
cls
for /f "tokens=12,*" %%a in ('wmic product list system ^| Find /I "SkypeT"') do (
set %%a=%%a: =%
msiexec.exe /x %%a /passive /norestart
)
:DoWhile
cls
Tasklist /fi "IMAGENAME eq msi*" /fi "STATUS eq RUNNING" | Find ":" >nul
if errorlevel = 1 (
echo Installation in progress
Goto :DoWhile
)
echo Skype is Uninstalled
:Reinstall
msiexec.exe /i SkypeSetup.msi /passive /norestart
:reinstallLoop
Tasklist /fi "IMAGENAME eq msi*" /fi "STATUS eq RUNNING" | Find ":" >nul
if errorlevel = 1 (
echo Installation in progress
goto :reinstallLoop
)
echo Skype is installed
:end
cls
color 0A
Echo Done!
exit
One last thing. I used this as an Invisible EXE task, so the user couldn't interact with the command prompt and eventually close the window (I know, I know, it makes the whole echoes stupid, but it was for testing purposes).for that I used BAT to EXE converter 2.3.1, you can put everything to work on the background and it will work very nicelly. if you want to show progress to users just write START Echo "info" and replace the info with whatever you want, it will open another prompt and show the info you need.
Remember, Wmic commands sometimes take up to 20 seconds to execute since it's querying the conputer's system, so it might look like it's doing nothing at first but it will run! ;)
Good luck :)
We needed a batch file to remove a program and we couldn't use programmatic access to the registry.
For us, we needed to remove a custom MSI with a unique name. This only works for installers that use msi or integrate such that their cached installer is placed in the Package_Cache folder. It also requires a unique, known name for the msi or exe. That said, it is useful for those cases.
dir/s/b/x "c:\programdata\packag~1\your-installer.msi" > removeIt.bat
set /p RemoveIt=< removeIt.bat
echo ^"%RemoveIt%^" /quiet /uninstall > removeIt.bat
removeIt.bat
This works by writing all paths for 'your-installer.msi' to the new file 'removeIt.bat'
It then assigns the first line of that bat file to the variable 'RemoveIt'
Next, it creates a new 'removeIt.bat' that contains the path/name of the .msi to remove along with the needed switches to do so.
Finally, it runs the batch file which executes the command to uninstall the msi. This could be done with an .exe as well.
You will probably want to place the 'removeIt.bat' file into a known writable location, for us that was the temp folder.

Resources