batch - simple shutdown script - windows

I wanted to write a simple batch script to shutdown my own computer which will be used when I'm in bed watching a DVD or something.
UPDATE: fixed the code, any other suggestions?
setlocal
#echo off & break off
:input
set /p "minutes=Enter number of minutes to wait until shutdown: "
set "numcheck="&for /f "delims=0123456789" %%i in ("%minutes%") do set "numcheck=%%i"""
if defined numcheck (
echo ERROR: Sorry "%minutes%" is not numeric, please try again & echo.
goto input
)
if %minutes% gtr 315360000 (
echo ERROR: Sorry your input is greater then 10 years, I can't handle that & echo.
goto input
)
set /a "seconds=%minutes%*60"
shutdown.exe /s /f /t "%seconds%"
if errorlevel 1 (
echo ERROR: Could not set shutdown, try again & echo.
goto input
)
:abort
set /p "continue=Your computer is about to shutdown in %minutes% minutes, do you want to abort? (yes/no): "
if %continue% equ yes (
echo Aborting...
shutdown.exe /a
if errorlevel 1 (
echo ERROR: Could not stop shutdown, try again & echo.
goto abort
)
timeout.exe /t 5 /NOBREAK
endlocal
exit /b
) else (
timeout.exe /t 10 /NOBREAK
endlocal
exit /b
)

The most common ways to use the shutdown command are:
shutdown -s — Shuts down.
shutdown -r — Restarts.
shutdown -l — Logs off.
shutdown -h — Hibernates.
Note: There is a common pitfall wherein users think -h means "help" (which it does for every other command-line program... except shutdown.exe, where it means "hibernate"). They then run shutdown -h and accidentally turn off their computers. Watch out for that.
shutdown -i — "Interactive mode". Instead of performing an action, it displays a GUI dialog.
shutdown -a — Aborts a previous shutdown command.
The commands above can be combined with these additional options:
-f — Forces programs to exit. Prevents the shutdown process from getting stuck.
-t <seconds> — Sets the time until shutdown. Use -t 0 to shutdown immediately.
-c <message> — Adds a shutdown message. The message will end up in the Event Log.
-y — Forces a "yes" answer to all shutdown queries.
Note: This option is not documented in any official documentation. It was discovered by these StackOverflow users.
I want to make sure some other really good answers are also mentioned along with this one. Here they are in no particular order.
The -f option from JosephStyons
Using rundll32 from VonC
The Run box from Dean
Remote shutdown from Kip

Shutdown -s -t100
Save it with .bat extenstion
Shutsdown in 100 secx

Related

Waiting for Process to terminate on a remote PC using for loop

Should be able to sort this but I'm going round in circles. I know this has to do with setlocal
EnableDelayedExpansion, but I'm missing something.
Goal:
Execute a windows (cleanmgr.exe) script on a remote machine, wait till Cleanmgr.exe closes then have
the initiating script "type" the resultant log file (generated via cleanup script) from the remote
system in the CMD window.
What's working:
The script running on the remote machine runs fine, it echo's C: free drive space into a log file,
then cleans up the PC, and then re runs the disk space report and echo's result into same log file,
so the user can see (/have transparency of) the reclaimed space via the before & after results.
What's Broken:
The WMIC command to check for Cleanmgr.exe on the target PC, only works once, when it waits to retry
the variable containing the Hostname has been wiped out. I can see the behavior by echoing the
variable back.
Fix Attempts:
I have a hunch this has to do with the variable being lost once the if statement is ran within the
Parentheses. I have tried lots of options but they all behave the same. I have tried jumping the
process out to loop outside the original code using %1 instead of %%i but just cant quite get there.
Thanks for any improvements.
#echo off
pushd %~dp0
color 1e
setlocal EnableDelayedExpansion
title HDD Space Checker...
for /f %%i in (hostnames.txt) do (
xcopy /y cleanupwindows-sfd.bat \\%%i\C$\IT
WMIC /node:"%%i" process call create "C:\IT\cleanupwindows-sfd.bat"
echo Waiting For Processes...
timeout -t 10 /nobreak >nul
:loop
WMIC /node:"%%i" process where name="cleanmgr.exe" get name |find "cleanmgr.exe">nul
IF "!errorlevel!"=="0" set running=var
IF "!running!"=="var" timeout -t 4 >nul & echo Still Running & goto :loop
IF "!running!"=="" timeout -t 4 >nul & type \\%%i\C$\IT\%%i_HHD_Space.log
)
pause
exit
There is at least two points to see.
Your running variable, once set, is never reset, triggering an infinite loop
Your goto statement inside the enclosing parenthesis drives the command interpreter (cmd.exe) to stop evaluating the block, thus your script loose the %%i and leave the for loop, thus when terminating the :loop cycle your script will leave the for loop without cycling to other values in hostnames.txt.
To address that, put your process code in a subroutine called with CALL and reset the running variable at each :loop cycle :
#echo off
pushd %~dp0
color 1e
setlocal EnableDelayedExpansion
title HDD Space Checker...
for /f %%i in (hostnames.txt) do (
CALL:Process "%%i"
)
pause
exit
:Process
xcopy /y cleanupwindows-sfd.bat \\%~1\C$\IT
WMIC /node:"%~1" process call create "C:\IT\cleanupwindows-sfd.bat"
echo Waiting For Processes...
timeout -t 10 /nobreak >nul
:loop
set "running="
WMIC /node:"%~1" process where name="cleanmgr.exe" get name |find "cleanmgr.exe">nul
IF "!errorlevel!"=="0" set "running=var"
IF "!running!"=="var" timeout -t 4 >nul & echo Still Running & goto :loop
IF "!running!"=="" timeout -t 4 >nul & type \\%~1\C$\IT\%~1_HHD_Space.log
GOTO:EOF
Explanations: The CALL statement implies that the command interpreter will store the current executed line of your script and its state before executing the associated subprocess/command/etc.. When the subprocess/command/etc.. finishes, the command interpreter resumes its execution of the script to the next line with a restored context. This avoids then the loose of the for loop context.

Execute multiple batch files concurrently and monitor if their process is completed

I have a main batch file which calls multiple batch files. I want to be able to execute all these batch files at the same time. Once they are all done, I have further processes that needs to carry on in the main batch file.
When I use 'Start' to call the multiple batch files, I'm able to kick off all batch files concurrently but I lose tracking of them. (Main batch file thinks their processes are done the moment it executes other batch files).
When I use 'Call', I'm able to monitor the batch file process, but it kicks off the batch files sequentially instead of concurrently.
Is there a way around this? I have limited permissions on this PC and I'm trying to accomplish this using Batch only.
Main Batch file
call first.bat
call second.bat
call third.bat
:: echo only after all batch process done
echo done!
first.bat
timeout /t 10
second.bat
timeout /t 10
third.bat
timeout /t 10
This is the simplest and most efficient way to solve this problem:
(
start first.bat
start second.bat
start third.bat
) | pause
echo done!
In this method the waiting state in the main file is event driven, so it does not consume any CPU time. The pause command would terminate when anyone of the commands in the ( block ) outputs a character, but start commands don't show any output in this cmd.exe. In this way, pause keeps waiting for a char until all processes started by start commands ends. At that point the pipe line associated to the ( block ) is closed, so the pause Stdin is closed and the command is terminated by cmd.exe.
This will generate a temporary file and lock it by creating a redirection to it, starting the batch subprocesses inside this redirection. When all the subprocesses end the redirection is closed and the temporary file is deleted.
While the subprocesses are running, the file is locked, and we can test this trying to rename the file. If we can rename the file, subprocesses have ended, else some of the processes are still running.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%t in ("%temp%\%~nx0.%random%%random%%random%.tmp") do (
echo Starting subprocesses
9> "%%~ft" (
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
)
echo Waiting for subprocesses to end
break | >nul 2>nul (
for /l %%a in (0) do #(ren "%%~ft" "%%~nxt" && exit || ping -n 2 "")
)
echo Done
) & del "%%~ft"
note: any process started inside the subprocesses will also hold the redirection and the lock. If your code leaves something running, this can not be used.
#ECHO Off
SETLOCAL
:: set batchnames to run
SET "batches=first second third"
:: make a tempdir
:maketemp
SET /a tempnum=%random%
SET "tempdir=%temp%\%tempnum%"
IF EXIST "%tempdir%*" (GOTO maketemp) ELSE (MD "%tempdir%")
FOR %%a IN (%batches%) DO START "%%a" %%a "%tempdir%\%%a"
:wait
timeout /t 1 >nul
FOR %%a IN (%batches%) DO IF exist "%tempdir%\%%a" GOTO wait
RD "%tempdir%" /S /Q
GOTO :EOF
Where the batches are constructed like
#ECHO OFF
:: just delay for 5..14 seconds after creating a file "%1", then delete it and exit
SETLOCAL
ECHO.>"%~1"
SET /a timeout=5+(%RANDOM% %% 10)
timeout /t %timeout% >NUL
DEL /F /Q "%~1"
EXIT
That is, each called batch first creates a file in the temporary directory, then deletes it after the required process is run. The filename to create/delete is provided as the first parameter to the batch and "quoted" because the temp directoryname typically contains separators.
The mainline simply creates a temporary directory and invokes the subprocedures, then repeatedly waits 1 second and checks whether the subprocedures' flagfile have all been deleted. Only if they have all been deleted with the procedure continue to delete the temporary directory
Adding to the answer by Aacini. I was also looking for similar task. Objective was to run multiple commands parallel and extract output (stdout & error) of all parallel processes. Then wait for all parallel processes to finish and execute another command. Following is a sample code for BAT file, can be executed in CMD:
(
start "" /B cmd /c ping localhost -n 6 ^>nul
timeout /t 5 /nobreak
start "" /B /D "C:\users\username\Desktop" cmd /c dir ^> dr.txt ^2^>^&^1
start "" /B cmd /c ping localhost -n 11 ^>nul
timeout /t 10 /nobreak
) | pause
Echo waited
timeout /t 12 /nobreak
All the statements inside () are executed first, wait for them to complete, then last two lines are executed. All commands begining with start are executed simultaneously.

What's the best way to stop a batch script after a specified amount of time?

I'm writing a batch script where I want the user to be able to control how long the script runs. When running it from the command line, the user will pass in a switch like this:
./myscript --stop-after 30
which means that the script will keep doing its job, and check every iteration how much time has passed. If more than a half a minute has passed, then it'll quit. How would I implement this in a batch script?
For reference, here is the code I have so far:
:parseArgs
if "%~1" == "" goto doneParsing
if /i "%~1" == "--stop-after" (
shift
set "duration=%~1"
)
:: Parse some other options...
shift
goto parseArgs
:doneParsing
:: Now do the actual work (psuedocode)
set "start=getCurrentTime"
set "end=%start% + %duration%"
while getCurrentTime < %end% (
:: Do some lengthy task...
)
How would I go about implementing the latter part of the script, after parsing the options?
Thanks for helping.
This is not that trivial. You'll have to do a lot of calculation within your script to cover all cases of full minute, full hour, or even new day. I can think of two different ways. Both are based on two batch files:
1. Termination via taskkill
starter.bat:
#echo off
if "%1"=="" (
set duration=5
) else (
set duration=%1
)
start "myscript" script.bat
ping 127.0.0.1 -n %duration% -w 1000 > nul
echo %duration% seconds are over. Terminating!
taskkill /FI "WINDOWTITLE eq myscript*"
pause
script.bat:
#echo off
:STARTLOOP
echo doing work
ping 127.0.0.1 -n 2 -w 1000 > nul
goto STARTLOOP
For this solution, it's important that you give the window executing your script a unique name inside the line start "myscript" script.bat. In this example, the name is myscript. taskkill /FI "WINDOWTITLE eq myscript*" uses myscript to identify which process to terminate.
However, this might be a bit dangerous. Your script will be killed after x seconds, no matter if an iteration is done or not. So, e.g., write access would be a bad idea.
2. Termination via flag file
starter.bat:
#echo off
if "%1"=="" (
set duration=5
) else (
set duration=%1
)
if exist terminationflag.tmp del terminationflag.tmp
start script.bat
ping 127.0.0.1 -n %duration% -w 1000 > nul
echo %duration% seconds are over. Setting termination flag!
type NUL>terminationflag.tmp
script.bat:
#echo off
:STARTLOOP
echo doing work
ping 127.0.0.1 -n 2 -w 1000 > nul
if not exist terminationflag.tmp goto STARTLOOP
del terminationflag.tmp
echo terminated!
Here, it's important to ensure that your script is allowed to create/delete a file at the current location. This solution is safer. The starter script will wait the given amount of time and then create the flag file. Your script will check after each full iteration whether the flag is there or not. If it's not, it will go on—if it is, it will delete the flag file and terminate safely.
In both solutions ping is used as timeout function. You could also use timeout/t <TimeoutInSeconds> if you are on Windows 2000 or later. However, timeout doesn't always work. It will fail in some scheduled tasks, on build servers, and many other cases. You'd be well advised to stick to ping.

Batch File - Shutdown Computer after X Minutes

I want to make a batch file that takes a user input in minutes, and will shutdown the computer after the time is up.
I know how to shutdown the computer after a set amount of time is up, I've just been having trouble setting that time to the user input.
I think this will do what you want.
#echo off
set /p mins=Enter number of minutes to wait until shutdown:
set /a mins=%mins%*60
shutdown /s /t:%mins%
According to http://ss64.com/nt/shutdown.html the most you can wait is 10 minutes, so if you need to wait longer you would need to add some sort of artificial timer, most likely using something like TIMEOUT if your system supports it (mine doesn't) or ping.
#echo off
set /p mins=Enter number of minutes to wait until shutdown:
for /L %%a in (0,1,%mins%) do (
PING -n 60 127.0.0.1>nul
)
shutdown /s
Check out this thread.
https://superuser.com/questions/215531/windows-7-shut-down-pc-after-specified-amount-of-time
Put this code in it after the #echo off line:
shutdown -s -t 1800
#echo off
title Shutdown Input
set /p mins=Enter number of minutes to wait until shutdown:
set /a mins=%mins%*60
shutdown.exe -s -t %mins%
Create a file with bat as extension (such as delayed.bat).
You can use the Editor under Accessoires for that.
Write the following lines into the file and save it (The file has to end with .bat) :
#echo off
set /p time=minutes:
set /a time=%time%*60
shutdown /a
shutdown /s /f /t %time%
set /p lets the user input something
set /a interprets expressions (calculations)
/a aborts earlier shutdown (counter)
/s stands for shutdown
/f stands for force programs to close (optional).
/t stands for the time in seconds. (for example: 60s * 10 = 10 min)
Doubleclick the file and enter after how many minutes you computer shuts down.
To abort shutdown: enter a big number (such as 10000000).
Create a batch file, and put this code in it after the #echo off line:
shutdown -s -t 1800
The computer will shutdown 30 minutes (1800 seconds) after running the batch file.
To cancel a shutdown initiated by that batch file, you can go to Start → Run and type:
shutdown -a
Or put that in its own separate batch file, then run it to cancel a shutdown.
Referred From Here
Put this in a batch file and run.
#echo off
#setlocal
color 1E
echo ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
echo Ý ÚÄÄÄ¿Þ
echo Ý SHUTDOWN COMPUTER WITH TIMER ³ û ³Þ
echo Ý ÀÄÄÄÙÞ
echo. ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
echo.
echo.
echo ----------------------------------------
Set /P _abort=abort shutdown? (y, *):
echo ----------------------------------------
If /i "%_abort%"=="y" shutdown /a
If /i "%_abort%"=="y" goto step1
Set /P _timer=shutdown computer after minutes:
echo ------------------------
set /a _result= _timer * 60
shutdown /s /t %_result%
:step1
echo Job Done!
pause
If you're on Windows 10, use this simple script:
shutdown -s -t 100
Note: Set the "100" to whatever you want etc. 40

Windows batch: sleep [duplicate]

This question already has answers here:
Sleeping in a batch file
(34 answers)
Closed 9 years ago.
How do I get a Windows batch script to wait a few seconds?
sleep and wait don't seem to work (unrecognized command).
You can try
ping -n XXX 127.0.0.1 >nul
where XXX is the number of seconds to wait, plus one.
I don't know why those commands are not working for you, but you can also try timeout
timeout <delay in seconds>
timeout /t 10 /nobreak > NUL
/t specifies the time to wait in seconds
/nobreak won't interrupt the timeout if you press a key (except CTRL-C)
> NUL will suppress the output of the command
To wait 10 seconds:
choice /T 10 /C X /D X /N
Microsoft has a sleep function you can call directly.
Usage: sleep time-to-sleep-in-seconds
sleep [-m] time-to-sleep-in-milliseconds
sleep [-c] commited-memory ratio (1%-100%)
You can just say sleep 1 for example to sleep for 1 second in your batch script.
IMO Ping is a bit of a hack for this use case.
For a pure cmd.exe script, you can use this piece of code that returns the current time in hundreths of seconds.
:gettime
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
set cc=%time:~-2%
set /A %1=hh*360000+mm*6000+ss*100+cc
goto :eof
You may then use it in a wait loop like this.
:wait
call :gettime wait0
:w2
call :gettime wait1
set /A waitt = wait1-wait0
if !waitt! lss %1 goto :w2
goto :eof
And putting all pieces together:
#echo off
setlocal enableextensions enabledelayedexpansion
call :gettime t1
echo %t1%
call :wait %1
call :gettime t2
echo %t2%
set /A tt = (t2-t1)/100
echo %tt%
goto :eof
:wait
call :gettime wait0
:w2
call :gettime wait1
set /A waitt = wait1-wait0
if !waitt! lss %1 goto :w2
goto :eof
:gettime
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
set cc=%time:~-2%
set /A %1=hh*360000+mm*6000+ss*100+cc
goto :eof
For a more detailed description of the commands used here, check HELP SET and HELP CALL information.
Heh, Windows is uhm... interesting. This works:
choice /T 1 /d y > NUL
choice presents a prompt asking you yes or no. /d y makes it choose yes. /t 1 makes it wait a second before typing it. > NUL squashes output.
The Windows 2003 Resource Kit has a sleep batch file. If you ever move up to PowerShell, you can use:
Start-Sleep -s <time to sleep>
Or something like that.
I rely on JScript. I have a JScript file like this:
// This is sleep.js
WScript.Sleep( WScript.Arguments( 0 ) );
And inside a batch file I run it with CScript (usually it is %SystemRoot%\system32\cscript.exe)
rem This is the calling inside a BAT file to wait for 5 seconds
cscript /nologo sleep.js 5000
I just wrote my own sleep which called the Win32 Sleep API function.
RJLsoftware has a small utility called DelayExec.exe. With this you can execute a delayed start of any program in batches and Windows registry (most useful in ...Windows/.../Run registry).
Usage example:
delayexec "C:\WINDOWS\system32\notepad.exe" 10
or as a sleep command:
delayexec "nothing" 10
Personally I use a Perl one-liner:
perl -e "sleep 10;"
for a 10-second wait. Chances are you'll already have Perl installed on a development machine as part of your git installation; if not you will have to install it, for example, from ActiveState or Strawberry, but it's one of those things I install anyway.
Alternatively, you can install a sleep command from GnuWin32.

Resources