0

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.

modemman11
  • 1
  • 1
  • 3
  • You may want to look at SysInternals `PsKill` utility: `-t Kill the process and its descendants.` Link: https://technet.microsoft.com/en-us/sysinternals/pskill – Severin Pappadeux Mar 26 '16 at 22:37
  • `taskkill` can already kill a process and it's decendants with the /t switch. Process C is the actual program and would need to remain open. Furthermore, after all is loaded, there is no task hierarchy remaining. – modemman11 Mar 27 '16 at 01:18
  • `Process C is the actual program and would need to remain open.` ok. `there is no task hierarchy remaining.` Isn't D,E,F form a hierarchy? Or i misunderstood the question? – Severin Pappadeux Mar 27 '16 at 02:59
  • Perhaps I was incorrect about what starts process D, E, and F (maybe it's actually B that starts them?), but when using Process Explorer to see the process hierarchy, it shows no active parent process for C, D, E, F after the program is up and running, so there's no tree to kill. – modemman11 Mar 27 '16 at 04:10

4 Answers4

0

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
    )
)
Ruslan
  • 2,691
  • 1
  • 19
  • 29
0

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
0
@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.

Magoo
  • 77,302
  • 8
  • 62
  • 84
0

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"
modemman11
  • 1
  • 1
  • 3