I have a hardware (battery controller) that send battery voltage over a serial port. It's just 4-digit value+endline ('1232\r\n') every 5 seconds.
I need to read that value and if it's below a treshold shut PC down. It's old WinXP machine where I'm allowed to use CMD only without creating temporary files.
On my home PC I created a test environment with two virtual ports (with com2com utility) and powershell script that emulates hardware:
cls
$port = New-Object System.IO.Ports.SerialPort
$port.PortName = "COM4"
$port.open()
while (1) {
$port.Write("1000"+[char]13+[char]10)
$port.close()
Start-Sleep -Seconds 5
$port.open()
}
Script below has to recieve data and shut down PC if value below treshold. But it doesn't work.
# ECHO OFF
MODE COM5 BAUD=9600 PARITY=n DATA=8 > nul
set tr=1100
FOR /F "usebackq" %%i IN (`TYPE COM5`) DO set x=%%i
IF %x% lss %tr% (ECHO System will shutdown
rem shutdown /s
)
When I run script It's just waits endlessly.
The for /f loop does not output the results of the command line-by-line as received. It waits for the command to complete so, by using type COM5 you will have a running command that does not exit, unless it experiences EOF.
To do this you can redirect its output as input to the for loop
<COM5 (for /L %%i in (0) do set x=%%i)
You have to note though that this will not run as a permanent loop and you'll have to create a permanent loop if you plan on running it continually.
Related
I have a cmd file 'D:\ProgramFiles\test.cmd'.
I want to write a script which would execute this test.cmd in a loop n times, also, after each execution, I want a delay/timeout of 5 seconds.
How should I go about this?
The timeout command is not always available. For example when executing a batch file on a build server like Jenkins or when running on an older version of Windows. However, there is a way that will always work:
#ECHO OFF
FOR %%i IN (1,1,5) do (
CALL "D:\ProgramFiles\test.cmd"
ping 127.255.255.255 -n 1 -w 5000> nul
)
Here we are using the ping command. ping 127.255.255.255 -n 1 -w 5000> nul will ping the IP address 127.255.255.255. This address won't be reachable but -w 5000 will make the command "wait" for 5000ms = 5s for a response. The only limitation is that you can't go below 500 ms with this method. Any number below 500 will result in a delay of 500 ms.
You can use ping -n 6 localhost>nul as well. This will repeat the ping six times. Notice that you will need 6 repetitions to achieve a delay of 5 seconds as the first ping will be launched immediately so six pings mean 5 seconds delay. Don't fall victim to the famous "fencepost error"
For further information check this website.
a For loop is what you want. in this instance, we tell it to start counting by 1, steps of 1, end at 5, which means you will be running 5 loops. For more on the for run from cmd.exe for /?
Timeout, depends on your OS version. Older OS's does not have it, then perhaps look at the older version called sleep or alternatively use the command ping with a count of timeout you want, +1. timeout On some Windows versions you do not like the /t and therefore can be used without it. i.e timeout 5
#echo off
for %%i in (1,1,5) do (
echo We do something here..
timeout /t 5
)
To learn about Windows cmd/batch commands, and how to use them in a batch files you can open cmd and type help which will list loads of commands. each of them can then be run followed by the /? switch to get full help on each command.
Example (n = 200):
FOR /L %%A IN (1,1,200) DO (
D:/ProgramFiles/test.cmd
timeout /t 5
)
I am trying to write a batch script that is as universal across Windows versions as possible (or at least from XP to 10). Everything is compatible so far (just some echoes and variable setting), except it uses the TIMEOUT.EXE command, which isn't available in XP or below.
I tried copying the exe over to no success. I was wondering if, through some clever coding, if this is possible. I basically need it to wait X amount of seconds before continuing, or allow a keypress to continue.
I tried using sleep.exe from the server 2003 utilities pack while piping it to set /p "=" and vice versa, but that didn't work either.
Any help is appreciated.
There is the choice command command that offers a default option together with a timeout.
For instance:
rem /* Wait for 10 seconds and take the default choice of `0`;
rem you can interrupt waiting with any of the keys `0` to `9` and `A` to `Z`;
rem you cannot use punctuation characters or white-spaces as choices: */
choice /C 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ /D 0 /T 10
rem // The `ErrorLevel` value is going to be set to a non-zero value.
Not the greatest of tools, but using choice with a custom message and a timeout of (5 seconds in this demo), with keystroke interrupt (any key, besides Enter esc etc.)
#echo off
choice /c qwertyuiopasdfghjklzxcvbnm1234567890 /cs /n /M "Timeout is 5 seconds.. press any key to Continue." /D c /T 5
echo 1 > null
there are a lot of ways. PING seems to be the most popular. You can try also
with w32tm
w32tm /stripchart /computer:localhost /period:5 /dataonly /samples:2 1>nul
or wtih typeperf:
typeperf "\System\Processor Queue Length" -si 5 -sc 1 >nul
with mshta:
start "" /w /b /min mshta "javascript:setTimeout(function(){close();},5000);"
I want to know if it is possible (and how) to detect if the network connection has been crashed down any time. I've created a little script with checks it but it is checking the network through a ping every few seconds and it is not working fine. I've been told that the microcuts are not detected.
This is the source:
#echo off
:: Interval of time the network is checked: 30 seconds
set delay_time=30
:: Delay between the kill and the start of the process
set delay_time_kill_start=5
:: Example process to kill and start
set process_to_kill=calc.exe
set process_to_start=calc.exe
:: local network to ping to check the connection
set ping_url=10.51.111.223 -n 1 -w 1000
:test-connection
Ping %ping_url%
if errorlevel 1 (
echo No hay conexión
:is-connected
Ping %ping_url%
if errorlevel 1 (
#echo on
echo trying to connect
#echo off
timeout 10
goto :is-connected
) else (
#echo on
echo kill the process
#echo off
taskkill /IM %process_to_kill% /f
timeout %delay_time_kill_start%
#echo on
echo start the process
#echo off
%process_to_start%
goto test-connection
)
) else (
timeout %delay_time%
goto test-connection
)
pause
Basically what I want is to kill a process and start it again when the network connection has been lost at any time, because that process freezes when the connection crashes.
So I would like to check, for instance, every 30 minutes if the network connection was lost at any time in the past half hour and, if yes, then kill and start the process.
Is it possible without doing the ping strategy every few seconds?
I am trying to get data from a sql server and ldap server for multiple clients. I need to get the sql data first and then the ldap data. In Unix shell it was straight forward to make a loop around a sub process with both retrievals going on for each client and then wait for it to complete. As a windows batch file however it happens sequentially. I.e. until I retrieve the data for one client, it won't go to the next. How can I get each client's data simultaneously? Here's what I have:
REM Get DB and client info. from config file
for /F "tokens=1,2,3,4,5,6 delims=| eol=#" %%G in (%cfg%\%env%.data) do (
REM Mark file as being in process of receiving data
type nul > %%K.tmp
REM Get data and remove tmp file to indicate completion
start cmd /C sqlcmd .... -Q "A long query" ^> %%K.dat1 && "c:\Program Files\Softerra\LDAP Administrator 4\laimex.exe" ... /sql "Another query" > %%K.dat2 && del %%K.tmp
)
For some reason, I need to do the first redirect escaped as ^> while the later one doesn't need that. At this point I am assuming that everything will be retrieved in the background and that I will need to check afterwards for when the processes are complete which I would do by checking the existence of the zero byte temp files I create. What happens though is that each iteration through the loop only starts when the prior one completes rather than occurring straight away by being placed in the background. Can anyone suggest how I can fix this?
You need to escape the && as well (^&^&), otherwise it executes everything after it as soon as start is fired. Example:
1 gets executed in a new shell correctly, while 2 takes over the main window (not what you want).
start cmd /C ping 127.0.0.1 && ping 127.0.0.2
Both get executed one after the other in a new window.
start cmd /C ping 127.0.0.1 ^&^& ping 127.0.0.2
Same as above, another way to do it.
start cmd /C "ping 127.0.0.1 && ping 127.0.0.2"
Also escape the other >'s, this might work:
start cmd /C sqlcmd .... -Q "A long query" ^> %%K.dat1 ^&^& "c:\Program Files\Softerra\LDAP Administrator 4\laimex.exe" ... /sql "Another query" ^> %%K.dat2 ^&^& del %%K.tmp
Essentially we have 2 batch files, one which is the "wrapper" if you will, calling another batch file so it starts as /min (minimized). This batch file then ends once it has launched the 2nd batch file.
This contains a loop, which keeps spawning an RDP session after it is closed.
The problem is, if the user ALT-TABs and closes the batch, they are just left with an empty desktop (as we task kill explorer). Is there a way of force rebooting the machine if that batch loop ends?
Thanks!
There is a standard cmd command:
shutdown /r
Usage: shutdown [/i | /l | /s | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/f]
[/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]
No args Display help. This is the same as typing /?.
/? Display help. This is the same as not typing any options.
/i Display the graphical user interface (GUI).
This must be the first option.
/l Log off. This cannot be used with /m or /d options.
/s Shutdown the computer.
/r Full shutdown and restart the computer.
/g Full shutdown and restart the computer. After the system is
rebooted, restart any registered applications.
/a Abort a system shutdown.
This can only be used during the time-out period.
/p Turn off the local computer with no time-out or warning.
Can be used with /d and /f options.
/h Hibernate the local computer.
Can be used with the /f option.
/hybrid Performs a shutdown of the computer and prepares it for fast startup.
Must be used with /s option.
/e Document the reason for an unexpected shutdown of a computer.
/o Go to the advanced boot options menu and restart the computer.
Must be used with /r option.
/m \\computer Specify the target computer.
/t xxx Set the time-out period before shutdown to xxx seconds.
The valid range is 0-315360000 (10 years), with a default of 30.
If the timeout period is greater than 0, the /f parameter is
implied.
/c "comment" Comment on the reason for the restart or shutdown.
Maximum of 512 characters allowed.
/f Force running applications to close without forewarning users.
The /f parameter is implied when a value greater than 0 is
specified for the /t parameter.
/d [p|u:]xx:yy Provide the reason for the restart or shutdown.
p indicates that the restart or shutdown is planned.
u indicates that the reason is user defined.
If neither p nor u is specified the restart or shutdown is
unplanned.
xx is the major reason number (positive integer less than 256).
yy is the minor reason number (positive integer less than 65536).
My suggestions:
Do you really need batch to be visible (minimized) or can it be hidden?
If it can be hidden, just use VBScript to launch it hidden:
With CreateObject("W"&"Script.Shell")
.Run "LongRun.bat", 0
End With
If you really need batch to be shown, you could make a hidden script which will wait for batch to terminate and reboot.
Step 1: Launch script hidden (Start.vbs):
Set WsShell = CreateObject("W"&"Script.Shell")
WsShell.Run "Hidden.vbs", 0
Step 2: Hidden.vbs will launch batch and wait it to return:
'This script is supposed to start hidden!
Set WsShell = CreateObject("W"&"Script.Shell")
WsShell.Run "LongRun.bat", 7, True
'WsShell.Run "REBOOT.EXE ..." 'Must remove comment and complete command line
MsgBox "Rebooting..."
Now LongRun.bat is running, Hidden.vbs also (but not visible).
If somehow LongRun.bat is terminated, Hidden.vbs will continue its execution and reboot.
(WScript.Shell.Run documentation)
EDIT: Notice "W"&"Script.Shell" is same as "WScript.Shell" but StackOverflow doesn't allow me to write it!