I am coding a virus using some BSOD code (I didn't make that part of it) and I want the file to, one started, give itself admin privilages, set the date and time to a certain point, and once the system date and time hit a certain point, self destruct. The problem I'm coming accross is that, the file is stuck on the process of keeping the BSOD on the screen, so it never gets to the self destruct code. Any help would be greatly appreciated. Thanks.
I've tried looping it and putting the code to when the loop reaches a certain point, move on. Didn't work.
#echo off
set loopcount=1
:loop
(
echo ^<html^>^<head^>^<title^>Microsoft Windows^</title^>
echo.
echo ^<hta:application id="oBVC"
echo applicationname="BSOD"
echo version="1.0"
echo maximizebutton="no"
echo minimizebutton="no"
echo sysmenu="no"
echo Caption="no"
echo windowstate="maximize"/^>
(This is the beggining of the code. It should loop once, then self destruct itself)
start "" /wait "bsod.hta"
del /f /q "bsod.hta" > nul
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
del "%~f0" & exit
(This is the part where it should have made itself self destruct after the loop happened)
I expected it to loop once, the self destruct, ending all processes. It just stayed on the process of holding up the BSOD
I expected it to loop once, the self destruct, ending all processes.
It just stayed on the process of holding up the BSOD
Your start /wait command will most certainly wait until the hta file has been closed prior to continuing execution of the rest of the batch file. If you wish to have the hta display and continue execution, just remove the /wait
start "bsod.hta"
Related
I'm a computational biologist and I'm trying to run large batches of similar code with a single command, but my implementation has hit a brick wall.
I'm using the NEURON simulation environment, which uses MinGW for its Windows interface, which is where my research has shown my problem arises.
Currently, I am using a batch file to run all of these similar pieces of code, to iterate across the "collection" subfolders:
#echo off
for /D %%a in ("%cd%\all_cells\cell_*.*") do cd "%%a\sim1\" & START neuron sim.hoc
The problem arises when I have more than 32 subfolders; the additional instances won't run and will error with a "console device allocation failure: too many consoles" error.
My research has shown me that this is a known problem with Cygwin/MinGW.
However, working around this manually (ensuring that there is no more than 32 "collection" folders) is extremely time consuming when I am now dealing with hundreds of instances (each refers to a simulated cell and I want to gather statistics on hundreds of them), so I am trying to find a solution.
That said, I am terrible at writing batch files (I'm a terrible programmer who is used to scientific languages) and I can't figure out how to code around this.
It would be great if someone could help me either find a way around the 32 limit, or failing that, help me write a batch file that would do this:
-iterate over up to 32 folders
-wait for the instances to finish
-do it again for the next 32, until I reach the end of the folder.
I have tried using the /wait command to do them one at a time, but it still opens all 32. (And this wouldn't be ideal as I'd like to use all 16 cores I have.
The following is adapted from https://stackoverflow.com/a/11715437/1012053, which shows how to run any number of processes while limiting the total number run simultaneously in parallel. See that post for some explanation, though the code below is fairly well documented with comments.
I've eliminated the /O option and the code to work with PSEXEC from the original script.
The script below runs everything in one window - the output of each process is captured to a temporary lock file, and when finished, the full output of each process is typed to the screen, without any interleaving of process output. The start and end times of each process are also displayed. Of course you can redirect the output of the master script if you want to capture everything to a single file.
I've limited the total number of parallel processes to 16 - of course you can easily modify that limit.
The code will not work as written if any of your folder paths include the ! character. This could be fixed with a bit of extra code.
Other than that, the code should work, provided I haven't made any silly mistakes. I did not test this script, although the script it was derived from has been thoroughly tested.
#echo off
setlocal enableDelayedExpansion
:: Define the maximum number of parallel processes to run.
set "maxProc=16"
:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
set "lock="
for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
set "lock=%%T"
goto :break
)
:break
set "lock=%temp%\lock%lock%_%random%_"
:: Initialize the counters
set /a "startCount=0, endCount=0"
:: Clear any existing end flags
for /l %%N in (1 1 %maxProc%) do set "endProc%%N="
:: Launch the commands in a loop
set launch=1
for /D %%A in ("%cd%\all_cells\cell_*.*") do (
if !startCount! lss %maxProc% (
set /a "startCount+=1, nextProc=startCount"
) else (
call :wait
)
set "cmd!nextProc!=%%A"
echo -------------------------------------------------------------------------------
echo !time! - proc!nextProc!: starting %%A
2>nul del %lock%!nextProc!
cd "%%A\sim1\"
%= Redirect the output to the lock file and execute the command. The CMD process =%
%= will maintain an exclusive lock on the lock file until the process ends. =%
start /b "" cmd /c 1^>"%lock%!nextProc!" 2^>^&1 neuron sim.hoc
)
set "launch="
:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
:: redirect stderr to null to suppress any error message if redirection
:: within the loop fails.
for /l %%N in (1 1 %startCount%) do 2>nul (
%= Redirect an unused file handle to the lock file. If the process is =%
%= still running then redirection will fail and the IF body will not run =%
if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" (
%= Made it inside the IF body so the process must have finished =%
echo ===============================================================================
echo !time! - proc%%N: finished !cmd%%N!
type "%lock%%%N"
if defined launch (
set nextProc=%%N
exit /b
)
set /a "endCount+=1, endProc%%N=1"
)
)
if %endCount% lss %startCount% (
timeout 1 /nobreak >nul
goto :wait
)
2>nul del %lock%*
echo ===============================================================================
echo Thats all folks^^!
You could install screen or tmux in cygwin.
Then you can start all neuron instances in a screen/tmux session.
They will not open a new window, so there is no limit anymore.
My click.bat file:
:main
#start /wait cmd.exe -/c ""C:\Users\MY_USER_NAME\Desktop\2.bat" "
goto :main
My 2.bat file:
#echo off
echo Hello World!
#pause
I am clicking Click.bat and they are both opening (no problem in here).
After that I am closing the Hello World! prompt (2.bat).
and prompt of the Click.bat, ask me ^CTerminate batch job (Y/N)?
I want to auto answer at here (as N).
(When the answer is N, 2.bat opening again like as I want).
I agree with Mofi that addressing the real issue is always better than to work around it, but sometimes this isn't possible or you need a quicker solution.
Instead of passively waiting, until the second process finishes, just actively watch it. If it isn't alive anymore, restart it. That way, it doesn't matter, how the second process finishes/exits/crashes:
test1.bat
#echo off
:main
if exist MyCommand.flag goto :eof
start test2.bat
:wait
timeout 1 >nul
tasklist /fi "Windowtitle eq MyCommand"|find "cmd.exe" >nul || #goto :main
goto :wait
test2.bat
#echo off
title MyCommand
echo Hello World!
#pause
break>MyCommand.flag
You don't have to start cmd /c, because start alone already starts a new cmd process. Give the process a unique title, so you can check, if it is still running.
|| works as "if previous command (find) fails then"
find is neccessary, because tasklist does not provide a helpful errorlevel.
Note: you also need a method to stop, when the second process finishes its task.
Test2.bat writes an empty file when finished. Obviously the file wouldn't be created, when the process crashes before (or is forcefully terminated).
test1.bat simply checks for the existence of the file before restarting the second process.
I am coding a batch file and it needs some more files. But they files should only be able to run using the call function from another batch file. My code looks like this:
call compileData.bat
pause
I want the compilerData.bat just starts when it's called from this one, not if its just started from Explorer or something other.
Can you please help me?
I have tried to find a solution on this problem in a whole hour!
You can use a parameter.
compileData.bat:
if "%1" neq "somestring" exit /b
REM rest of your code
Another.bat:
call compileData.bat somestring
pause
I cannot think of any way that would prevent the bare "run" of the called script. Possibly that might only be done using NTFS permissions.
What you can do quickly is something like this:
MOTHERBATCH.bat
call compileData.bat SomePASSPHRASE
compileData.bat
#echo off
if not "%1"=="SomePASSPHRASE" (
echo "You can not run this script directly, please run MOTHERSCRIPT.bat."
exit /B 1
)
echo "Passphrase is correct, code is executed..."
Set an environment variable in the parent script, then if that variable is not set or doesn't have the correct value in the children, they just exit with an error message explaining they aren't intended for standalone use. You really can't prevent someone from reverse engineering the code and forcing it to run.
You could put the children in a password protected zip file and have the parent unpack it just before calling them. Then when the parent is done, it deletes the unpacked scripts.
Do all of the above.
You can use a not so well known system variable named cmdcmdline.
I will explain a brief usage for you.
For brevity's sake we will have two very simple batch files.
Parent.bat
#echo off
call compiledata.bat
And compiledata.bat
#echo off
echo %cmdcmdline%
pause
When compiledata.bat is executed on its own this variable's value is the batch file itself.
C:\WINDOWS\system32\cmd.exe /c ""C:\Batch\CALL\compiledata.bat" "
But when compiledata.bat is called from parent.bat the variable's value is that of the calling parent.bat.
C:\WINDOWS\system32\cmd.exe /c ""C:\Batch\CALL\parent.bat" "
My suggestion is putting all your batch code into a single batch file and use subroutines. Open a command prompt window and run call /? for help on how to use subroutines which is nothing else than calling a batch file being embedded in current batch file.
A simple example:
#echo off
echo Running %~f0 %*
call :compileData %*
call :WaitForUser
rem The next line results in exiting processing of this batch file
goto :EOF
:compileData
echo/
echo Running subroutine compileData with the arguments: %*
rem Exit processing subroutine compileData and continue above
rem after the command line calling the subroutine compileData.
goto :EOF
:WaitForUser
echo/
pause
rem Exit processing subroutine WaitForUser and continue above
rem after the command line calling the subroutine WaitForUser.
goto :EOF
See also Where does GOTO :EOF return to? And take a look on DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the explanation on using echo/ to output an empty line.
Here's my solution:
when launched from the command line, %cmdcmdline% inherits the name from the base calling program, so it wouldn't be the name of the "middle man" calling your batch file
this is what I came up with. I had to use the "subroutine" method to get the variables properly expanded
Note: Edge Case: if you use complex paths with the batch files having the same name in different folders, you could run into an "Edge Case". If that is important to you, then you might have to further parse the file names. I'm not totally sure, it wasn't my use case so I didn't go further.
#echo OFF
setlocal EnableDelayedExpansion
call :myGetFileName "%CmdCmdLine%"
if /I "%sRet%"=="%~nx0" (
echo ************** Pause
) else (
echo ************** NO Pause
)
echo finished test
pause
exit
:myGetFileName
set "sRet=%~nx1"
exit /b
I worked with 4DOS a lot decades ago, and bash more recently, but don't have experience with plain Windows batch. I'm trying to make something to conveniently kill the firefox.exe processes that sometimes misfire and never show Firefox but persist and eat my resources.
Trying to make a query-to-user that defaults to kill the processes.
The first problem is the "if %REPLy%==SOMETHING (goto SOMEWHERE)" statements.
The explicit ones work fine but I want to kill the firefoxes if none of them are true. I thought I'd just put the code after the "if...goto"s but that didn't work. So I tried an additional if based on the variable REPLy equaling nothing. That didn't work. So I thought maybe a variable equaling nothing ("") might not be the same as being undeclared and maybe the reply stuff was simply removing the variable rather than giving the value "" and added an if for that. That didn't work either. So I thought maybe I had to put the kill code under a label and send execution there with a goto like the I did in the statements that work, but that doesn't work either. If I enter SOMETHING other than the explicit variations of NO or no, full or truncated, it works, kinda. The taskkill command reports success but it still fails in reality. But I'll work on that bridge when I get there. The immediate problem is how to get NO entry (in other words, just hit the enter key) to goto the kill code just like a non-no string does. What am I doing wrong here?
#echo off
REM All this stuff with the path is because I can't reboot this system right now (long story) and I can not seem to make the amended path stick. So for now, I set it each time. I presume I just need to reboot to make the path setting I changed under computer properties, etc, stick.
echo "This is the path:"
path
PATH=%PATH%;C:\Program Files\GnuWin32\bin
echo "This is the path now:"
path
echo "All these path setting and testing commands and remarks can be cleaned up after I figure out if the new path becomes permanent after reboot."
REM Here ends the stuff I expect to delete after I can reboot.
REM Here begins the part I do not expect to change and that works fine.
tasklist | findstr /B firefox.exe | wc -l > kill_firefox.bat_var.tmp
set /p NUMBER_OF_PROCESSEs=<kill_firefox.bat_var.tmp
del kill_firefox.bat_var.tmp
IF NOT DEFINED NUMBER_OF_PROCESSEs (goto ERROR - NUMBER_OF_PROCESSEs not set)
if %NUMBER_OF_PROCESSEs%==0 (goto NO_PROCESSES)
REM Since the contrary conditions lead to gotos, if processing gets to here, there are 1 or more firefox.exe processes.
echo The number of firefox.exe processes running is:
echo .
echo %NUMBER_OF_PROCESSEs%
echo .
tasklist | findstr /B firefox.exe
set /p REPLy= "Kill these? Y/n"
echo "REPLy is %REPLy%"
pause
if %REPLy%==n (goto USER DECLINED TO KILL)
if %REPLy%==N (goto USER DECLINED TO KILL)
if %REPLy%==no (goto USER DECLINED TO KILL)
if %REPLy%==NO (goto USER DECLINED TO KILL)
REM Here is where the problems start. By my reasoning, I shouldn't need any if/then here, nor even a goto, just the code that is now in the part labeled KILL. The ifs and the goto and putting the code in the labeled section are the result of many attempts to get that code to run with various constructions.
if [%REPLy%] == [] goto KILL
IF NOT DEFINED REPLy (goto KILL)
goto KILL
:NO_PROCESSES
echo There are no firefox.exe processes running.
pause
exit
:ERROR - NUMBER_OF_PROCESSEs not set
echo Logic error - The variable is not defined. This script must be repaired.
pause
exit
:USER DECLINED TO KILL
echo User declined to kill processes.
pause
exit
:KILL
REM I am not sure if ANY of this is running because the pause command is not working and the terminal disappears to fast to see. What am I doing wrong here?
echo killing . . .
taskkill /IM firefox.exe
pause
exit
Added by edit:
OK, I musta confused my smart pills with my dumb pills. Here is how I fixed the part that I was stuck on:
I changed
set /p REPLy= "Kill these? Y/n"
to
set /p REPLy= "Kill these? Y/n" || set REPLy=Y
and that did the trick. I see why that works, but I don't quite see why the ways I tried before don't. Apparently Batch treats variables set (unset? cleared? nulled?) by "set /p somemessage" with just a plain enter key as a response in some way I don't understand. But anyway, I don't have to understand it, just accept it. The construction with the "||" above works. Anyway this was the part of the problem I asked about and it's solved. If I can't get the rest of it working I'll post again after cleaning this batch file up a bit.
use setx to set a permanent variable (see setx/?, the syntax is different from set).
set /p leaves the variable unchanged, if input is empty. So you can predefine a variable:
set "REPLy=Y"
set /p "REPLy=Kill these? Y/n"
echo %REPLy%
echo first letter of REPLy is %REPLy:~0,1%
but instead of set /p, I would use choice.
There is no "empty" variable. If it has no value, the variable is not defined.
if has a /i switch to ignore capitalization.
To get the number of processes I would use (no need for an external utility):
for /f %%i in ('tasklist ^| find /c "firefox.exe"') do set NUMBER_OF_PROCESSEs=%%i
and as SomethingDark already mentioned:
run the script from the command prompt instead of double clicking it (and use exit /b instead of exit)
don't use spaces in labels.
Yes, I know you are probably going to complain saying it's a bad thing to do, but I want to do it anyway!
I am creating a batch program and at the end, I need it to hang and not accept user input. I know one method is just creating an infinite loop of:
:pause
pause > nul
goto pause
but I don't think that's a great choice. Although I need it to hang, I need to to be able to be closed via the red 'X' close button at the top of the window.
Any ideas?
This works for me. It redirects < NUL into self to prevent Ctrl+C from breaking, and uses start /b /wait to suppress the "Terminate batch job (Y/N)?" prompts.
#echo off
setlocal
>NUL (echo(%* | findstr "\<hang\>" && waitfor redX)
rem // *** PUT YOUR MAIN SCRIPT HERE ***
echo End of line.
rem // ******* END MAIN SCRIPT *********
call :hang
goto :EOF
:hang
start /b /wait "" "%~f0" hang ^<NUL
On the initial launch of the script, the echo(%* | findstr "\<hang\>" >NUL line looks for a script argument of "hang". If found, the script executes the waitfor command.
Normally, waitfor can be broken with Ctrl+C. But since the usual behavior of Ctrl+C is defeated by start /b and <NUL, the hanging effect is achieved unless a user does Ctrl+Break or sends the answering waitfor signal.
The red X still works, though.