Closing a windows application after bat file runs - windows

In my batch file I opened a file and printed its contents. Now I am trying to close the application. I used taskkill /f /im Ptedit50.exe from the cmd line and the program closes. I am having trouble getting it to work in the batch file. When I add that line after the print command they program exits and the print command never executes. If I insert the line at the end of the batch file the program does not exit. Where should I place the taskkill /f /im Ptedit50.exe line?
#echo off
setlocal
title My First batch file
echo Hello!
start Ptedit50.exe "c:\My Labels\PraxisBadge.lbx"
call :SendCtrlP "Name in Windowtitle"
exit /b
:SendCtrlP <app>
setlocal
set vbs=%Temp%\_.vbs
>%vbs% echo set s = CreateObject("Wscript.Shell")
>>%vbs% echo s.appactivate "%~1"
>>%vbs% echo s.sendkeys "^p"
>>%vbs% echo s.sendkeys "{ENTER}"
cscript //nologo %vbs%
if exist %vbs% del /f /q %vbs%
exit /b
taskkill /f /im Ptedit50.exe
exit /b
enter code here

Here is a Batch + JScript Hybrid example. I added a couple 2 second sleeps to allow the target program time to process the requests. Usually, applications launch a separate Print dialog, so I changed it to send the enter keypress to the Print dialog.
#if (#CodeSection == #Batch) #then
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The first line in the script is...
:: in Batch, a valid IF command that does nothing.
:: in JScript, a conditional compilation IF statement that is false.
:: So the following section is omitted until the next "[at]end".
:: Note: the "[at]then" is required for Batch to prevent a syntax error.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Batch Section
#echo off
:: Open Labels
start Ptedit50.exe "c:\My Labels\PraxisBadge.lbx"
:: Wait 2 Seconds
ping 192.0.2.2 -n 1 -w 2000 >nul
:: Send Ctrl+P and Enter
CScript //E:JScript //Nologo "%~f0" "Name in Windowtitle" "^p"
CScript //E:JScript //Nologo "%~f0" "Print" "~"
:: Wait 2 Seconds
ping 192.0.2.2 -n 1 -w 2000 >nul
:: Kill Program
taskkill /f /im Ptedit50.exe
exit /b 0
:: End of Batch
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#end
////////////////////////////////////////////////////////////////////////////////
// JScript Section
try
{
var WshShell = WScript.CreateObject('WScript.Shell');
var Title = WScript.Arguments.Item(0);
var Message = WScript.Arguments.Item(1);
WshShell.AppActivate(Title);
WshShell.SendKeys(Message);
WScript.Quit(0);
}
catch(e)
{
WScript.Echo(e);
WScript.Quit(1);
}
WScript.Quit(2);

What you want to achieve is from my perspective straight forward, so I would avoid usage of those setlocal, call and exit /b parts of your code as there is no real need in this code to jump there and back again rather than executing codes line by line.
I don't have your application to fully test it, but if I try it with notepad and text file following code is working for me:
#echo off
title My First batch file
echo Hello!
start notepad.exe test.txt
REM call :SendCtrlP "Name in Windowtitle"
:SendCtrlP <app>
REM setlocal
set vbs=%Temp%\my.vbs
>%vbs% echo set s = CreateObject("Wscript.Shell")
>>%vbs% echo s.appactivate "Name in Windowtitle"
>>%vbs% echo s.sendkeys "^p"
>>%vbs% echo s.sendkeys "{ENTER}"
cscript //nologo %vbs%
ping -n 5 localhost > NUL
if exist %vbs% del /f /q %vbs%
REM exit /b
taskkill /f /im notepad.exe
REM exit /b
echo enter code here
pause
I have REM'd your code intentionally for easier view what was removed.
This part is there in order to simulate wait/sleep on older or desktop OS systems.
ping -n 5 localhost > NUL
On server system this can be replaced by command sleep.
Seems that reason why it was not working for you is that you have actually killed your program before .vbs was able to print it out, therefore the sleep put in place and additionally as stated in the beginning usage of setlocal is not really necessary in such straight forward and simple batch files.
Hope this helps

Related

Call Waiting Spinner Via Arguments In Batch Script

I wanted to call waiting spinner on my batch script like this is my code:
#echo off
::-----------------------------Waiting-Spinner-------------------------------
:spinner
set mSpinner=%mSpinner%.
if %mSpinner%'==....' (set mSpinner=.)
cls
::----------------------------Subdomain-Script-------------------------------
echo Enumerating Subdomains From Script1 %mSpinner%
python2 enumsubdomain.py google.com > google.txt
SLEEP 1
goto spinner
echo Enumerating Subdomains From Script2 %mSpinner%
python2 enumsubdomain2.py yahoo.com > yahoo.txt
SLEEP 1
goto spinner
#pause
And this spinner text output should be something like this:
Enumerating Subdomains From Script1 ...<Here this dot will be animated]
Enumerating Subdomains From Script2 ...<Here this dot will be animated]
But it only outputs first line(Script1) and the 2nd script stops and doesn't outputs the 2nd line as well, i guess it's because of goto line in batch script and i have no idea what can be done here to make it work!
After clarification in your comment, you'd probably want something like this.
We start the commands in separate windows with new window titles per window, then we use tasklist to determine of either are still running. So both results will be echo if both run, or only one will be echod if only one runs.
#echo off
set done1=1
set done2=1
start "enum1" /min cmd.exe /C ^(python2 enumsubdomain.py google.com ^> google.txt^)
start "enum2" /min cmd.exe /C ^(python2 enumsubdomain2.py yahoo.com ^> yahoo.txt^)
:spinner
set mSpinner=%mSpinner%.
if "%mSpinner%"=="...." (set mSpinner=.)
cls
(tasklist /FI "WINDOWTITLE eq enum1" | findstr /i "cmd")>nul && echo Enumerating Subdomains From Script1 %mSpinner% || set done1=0
(tasklist /FI "WINDOWTITLE eq enum2" | findstr /i "cmd")>nul && echo Enumerating Subdomains From Script2 %mSpinner% || set done2=0
if %done1% equ 0 if %done2% equ 0 goto :eof
(sleep 1)>nul
goto :spinner
You want to use the spinner several times, so using a subroutine for the spinner is a good idea.
The main problem is: batch waits for a command to end before continuing with the next one, so you can't include the python command into the loop. Solution: start the command as an independent process and then start the "spinning loop". Break it, when the independent process does not exist anymore.
Here the subprocess :spinner takes a string as parameter (the message), making it flexible.
Instead of clearing the screen (cls) for each iteration of the loop, I took a different approach: overwriting the line over and over (less flickering and keeping the previous screen intact)
#echo off
setlocal EnableDelayedExpansion
REM create a CariageReturn:
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
cls
start /min "MySpinnerProcess" cmd /c "timeout 8 >google.txt"
call :spinner "Enumerating Subdomains From Script1"
start /min "MySpinnerProcess" cmd /c "timeout 5 >yahoo.txt"
call :spinner "Enumerating Subdomains From Script2"
echo finished.
goto :eof
:spinner
tasklist /fi "WindowTitle eq MySpinnerProcess" 2>nul | findstr /bilc:"cmd.exe" >nul || (
echo %~1 done.
goto :eof
)
set "mspinner=%mspinner%."
if %mspinner% == .... set "mspinner=."
<nul set /p ".=%~1 %mspinner% !CR!"
timeout 1 >nul
goto :spinner
For completeness my script for running the two scripts simultaneously. (very similar to Gerhard's solution, but keeping two spinners) (in my defense: I already had it ready when I asked you if you want them one after the other or simultaneously, but I just had to spend the sunny Sunday Afternoon outside)
#echo off
setlocal
::---------Waiting-Spinner---------
start /min "MyPhytonProcess1" cmd /c "timeout 8 >google.txt"
start /min "MyPhytonProcess2" cmd /c "timeout 5 >yahoo.txt"
:spinner
set mSpinner1=%mSpinner1%.
set mSpinner2=%mSpinner2%.
if %mSpinner1%==.... (set mSpinner1=.)
if %mSpinner2%==.... (set mSpinner2=.)
cls
::----------------------------Subdomain-Script-------------------------------
echo Enumerating Subdomains From Script1 %mSpinner1%
echo Enumerating Subdomains From Script2 %mSpinner2%
if "%mSpinner1%%mSpinner2%" == "Done.Done." goto :done
tasklist /FI "WindowTitle eq MyPhytonProcess1" 2>nul |find "cmd.exe" >nul || set "mSpinner1=Done"
tasklist /FI "WindowTitle eq MyPhytonProcess2" 2>nul |find "cmd.exe" >nul || set "mSpinner2=Done"
timeout 1 >nul
goto :spinner
:done
echo finished.
#pause

Batch file that deletes itself and folder that contains it

I'm trying to do the following but deleting the downloaded folder which contains the batch file fails:
NOTE: All exe's, apps, batch file etc. are contained in file.zip.
User downloads file.zip to any directory and unzips.
User runs an exe which is located in the unzipped folder.
This in turn runs two portable apps and some other things.
Once duties are performed, I remote in and run the same exe but this time I select an option that runs a batch file (located in unzipped folder) that starts a 30 second timer then is supposed to stop the apps and delete file.zip and the unzipped folder including the batch file itself.
Below is the batch file:
#echo off
mode con: cols=32 lines=7
color 4f
title
echo 30 Second Delay
echo Close window to abort
echo/
echo/
echo 0%% 100%%
SET /P var= <NUL
set count=0
:loop
PING -n 2 127.0.0.1 >NUL 2>&1
call :printline _
set /a count=count+1
if %count%==30 goto finish
goto loop
:printline
REM Print text passed to sub without a carriage return.
REM Sets line variable in case %1 intereferes with redirect
set line=%1
set /p var=%line%<NUL
exit /b
:finish
cls
color 0f
title Finished
mode con: cols=80 lines=25
echo Do NOT close this window!
echo/
echo Killing processes...
echo/
echo/
echo/
taskkill /t /f /im app1mainprocess.exe >nul
timeout /t 5 >nul
taskkill /t /f /im app2mainprocess.exe >nul
timeout /t 5 >nul
echo Do NOT close this window!
echo/
rem echo Restarting Windows Explorer...
rem timeout /t 10 >nul
rem taskkill /f /im explorer.exe >nul
rem start explorer.exe
echo Do NOT close this window!
echo/
echo Deleteing files and folders...
echo/
rem timeout /t 10 >nul
Set "Folder2Del=%~dp0"
cd ..
IF EXIST "file.zip" DEL "file.zip" /s /q >nul
rem echo %scrptDir%
echo Do NOT close this window!
echo/
echo Still working...
timeout /t 10 >nul
rd %Folder2Del% /s /q
(goto) 2>Nul & RD /S /Q "%Folder2Del%" & exit
The problem I encounter is that the folder never gets deleted. I realize my code is not correct but another reason is because one of the dll files in the unzipped folder is sometimes still in use by the dllhost.exe process.
I'm not sure if it is safe to add a line that kills the dllhost.exe process or not but my code still won't work because I have something wrong with how it deletes the batch file itself and the folder that contains it.
What lines do I need to edit and is it safe to kill dllhost.exe?
According to a link from dbenham
This does the trick:
#Echo off
Echo Ref: "http://www.dostips.com/forum/viewtopic.php?f=3&t=6491"
Set "Folder2Del=%~dp0"
cd "%~d0"
pause
(goto) 2>Nul & RD /S /Q "%Folder2Del%"
Take care the folder containing the batch is deleted
including any other files/folders without any further question!
Ok... I THINK I figured out how to do what I want by trying to delete the dll file, first, before trying to delete the entire directory. The code below looks for the problem dll and tries to delete it. If it still exists, it will try to delete the file every 30 seconds for up to 15 minutes. As soon as the dll gets deleted, the entire folder will also be deleted. If after 15 minutes the dll cannot be deleted, the remaining files in the folder will be deleted.
I still have a small issue. If I add code that kill/restarts Windows Explorer, the folder does not get deleted. Why and is there a workaround?
Below is the latest code:
#echo off
mode con: cols=32 lines=7
color 4f
title
echo 30 Second Delay
echo Close window to abort
echo/
echo/
echo 0%% 100%%
SET /P var= <NUL
set count=0
:loop
PING -n 2 127.0.0.1 >NUL 2>&1
call :printline _
set /a count=count+1
if %count%==30 goto finish
goto loop
:printline
REM Print text passed to sub without a carriage return.
REM Sets line variable in case %1 intereferes with redirect
set line=%1
set /p var=%line%<NUL
exit /b
:finish
cls
color 0f
title Uninstall
mode con: cols=80 lines=25
echo Do NOT close this window!
echo/
echo Killing processes...
tasklist /fi "imagename eq app1mainprocess.exe" |find ":" > nul
if errorlevel 1 taskkill /t /f /im "app1mainprocess.exe" > nul
tasklist /fi "imagename eq app2mainprocess.exe" |find ":" > nul
if errorlevel 1 taskkill /t /f /im "app2mainprocess.exe" > nul
timeout /t 5 >nul
rem echo Do NOT close this window!
rem echo/
rem echo Restarting Windows Explorer...
rem timeout /t 10 >nul
rem taskkill /f /im explorer.exe >nul
rem start explorer.exe
echo/
echo Deleteing file.zip if it exists...
timeout /t 5 >nul
Set "Folder2Del=%~dp0"
cd ..
IF EXIST "file.zip" DEL "file.zip" /s /q >nul
rem echo %Folder2Del%
rem Loops for 30 times in 30 second intervals (Total 15 minutes) to confirm deletion. Loop will exit after 30 loops and move on if dll cannot be deleted.
for /l %%i in (1,1,30) do (
del "%Folder2Del%name*.dll"
if not exist "%Folder2Del%name*.dll" goto Folder2Del
echo/
echo File locked! May take up to 15 minutes to delete.
echo Will stop trying 15 minutes after first attempt.
timeout /t 30 >nul
)
:Folder2Del
echo/
echo Attempting to delete the Connector folder and it's contents...
timeout /t 5 >nul
rd "%~dp0" /s /q & exit

Running two command prompt terminals in native windows, how can I redirect the output of one to the input of the other?

I have one Windows 10 command prompt running and awaiting input, and I wish to automate continuous and live input with a second command prompt. I have gotten the second command prompt to extract the desired variable, and I wish to send it to the other command prompt that is waiting for input.
The "awaiting input" command prompt must run in real time because it is connected to Plink (not an SSH session so no use of the -m command here) which is connecting to a microcontroller. So it cannot be accomplished (at least I don't think) with function calls.
I see that it can be done in UNIX environments: https://askubuntu.com/questions/496914/write-command-in-one-terminal-see-result-on-other-one
Thanks in advance and please advise,
--A hopeful beginner
Batch code starts 2 piped processes, one for getting keyboard input and writing to a file, and the other reading the data written. Note there isn't a cmd window for each process, but there are two new processes running. You may use cmd /c or start if you need two consoles.
Does it help?
#echo off
set "pipefile=pipefile.txt"
if "%~1" neq "" goto %1
copy nul "%pipefile%" >nul
"%~F0" getInput >>"%pipefile%" | "%~F0" readInput <"%pipefile%"
echo(
echo(Batch end...
ping localhost -n 1 >nul
del /F /Q "%pipefile%" 2>nul
exit/B
:getInput
set "input="
set/P "input="<CON
echo(%input%
if /I "%input%" equ "EXIT" exit
goto:getInput
:readInput
setlocal enableDelayedExpansion
set/P="enter some data [EXIT to exit] "
for /l %%. in () do (
set "input="
set/P "input="
if defined input (
if /I "!input!" equ "EXIT" exit
set/P="enter some data [EXIT to exit] "
)
ping 1.1.1.1 -w 10 -n 1 >nul 2>nul & rem avoid processor load (may be removed)
)
Running two console windows
#echo off
set "pipefile=pipefile.txt"
if "%~1" neq "" goto %1
del /F /Q "%pipefile%" 2>nul
copy nul "%pipefile%" >nul
start "writer" cmd /c ^""%~f0" readInput ^<"%pipefile%" ^"
start "reader" cmd /c ^""%~f0" getInput ^"
echo(
Echo batch end...
ping localhost -n 1 >nul
goto :EOF
:getInput
set "input="
set/P "input=enter some data [EXIT to exit] "
echo(%input%>>"%pipefile%"
if /I "%input%" equ "EXIT" exit
goto:getInput
:readInput
setlocal enableDelayedExpansion
for /l %%. in () do (
set "input="
set /p "input="
if defined input (
if /I "!input!" equ "EXIT" exit
echo(!input!
)
ping 1.1.1.1 -w 10 -n 1 >nul 2>nul & rem avoid processor load (may be removed)
)

Stop Music Once Playing

I am trying to get a song to play in the background of Windows, after a little looking I found this:
#echo off
set file=RRLJ.mp3
( echo Set Sound = CreateObject("WMPlayer.OCX.7"^)
echo Sound.URL = "%file%"
echo Sound.Controls.play
echo do while Sound.currentmedia.duration = 0
echo wscript.sleep 100
echo loop
echo wscript.sleep (int(Sound.currentmedia.duration^)+1^)*1000) >sound.vbs
start /min sound.vbs
This works well for starting the song but I have no way of stopping it from a .bat file. The only way I found to cut it short is to open task manager and close it from the processes.
I have tried:
taskkill /im wscript.exe
But I keep getting something in the window saying:
Success: Sent termination sidnal to the process "wscript.exe" with PID 185448
but the music continues to play until I manually end it with task manager
I'd use /T switch (Tree kill): terminates the specified process and any child processes which were started by it.
Here is a script to find ProcessID to terminate exactly needed process only using PID:
#ECHO OFF >NUL
for /F "usebackq tokens=*" %%G in (
`wmic process where "CommandLine like '%%sound.vbs%%' AND Caption like '%%script.exe%%'" get ProcessID/value ^|find /I "="`
) do (
rem echo %%G
for /F "tokens=2 delims==" %%H in ("%%~G") do echo taskkill /T /F /PID %%H
)
Note taskkill command is echoed merely... Remove echo when debugged.
This work for me, and is only one line.
Taskkill /IM "wscript.exe" /F>nul 2>&1

Using Sleep with findstr in a .bat

I created a .bat file with the below lines
cd C:\MyFolder
d:
findstr "Apple" C:\log.txt |findstr "red" > red_apples.txt
SLEEP 3600
GOTO START
When the bat is executed, the SLEEP is not working and the commands are running continously.
Is there anything wrong with the code? Please help !
I don't believe Windows has a sleep, you can emulate it with ping, as shown in this example chkwait.cmd script:
#setlocal enableextensions enabledelayedexpansion
#echo off
echo %time%
call :waitfor 20
echo %time%
endlocal
goto :eof
:waitfor
setlocal
set /a "t = %1 + 1"
>nul ping 127.0.0.1 -n %t%
endlocal
goto :eof
The call :waitfor 20 in the above script will wait for twenty seconds:
pax> chkwait
10:18:13.42
10:18:33.51
SLEEP does not exist in windows batch script. You would have create your own Sleep wrapper EXE and call that from the batch. Or use the clever trick from #paxdiablo above.

Resources