'Why is %random% in Windows time based and how to get a real random number?
I use the following script:
set /a num=%random% %%1000 +3000
timeout /T %num%
taskkill /F /IM chrome.exe
I trigger it using Windows task scheduler on multiple virtual machines at the exact same time.
The problem is: The value is not really random. It feels like it is Windows time based. I get the same value on every machine.
Solution 1:[1]
Use vbscript to get random number & enter your number in max
and Min
value :
@echo off
cd /d "%~dp0"
set /a max=3000
set /a min=1
(
Echo max=%max%:min=%min%:Randomize
Echo WSH.Echo ^(Int^(^(max-min+1^)^*Rnd+min^) + max^) ) >> Vbscript.vbs
FOR /F %%A IN ('cscript //nologo Vbscript.vbs') DO Set RAND=%%A
Del "Vbscript.vbs"
Echo %RAND%
timeout /T %RAND%
taskkill /F /IM chrome.exe
pause>nul
Solution 2:[2]
Use powershell to get the random numbers in a range:
@Echo Off
For /F %%a in ('Powershell -Command "& {[math]::Floor(Get-Random -Maximum 3000 -Minimum 1000)}"') Do Set rand=%%a
Echo %rand%
Timeout /T %rand%
Taskkill /F /Im chrome.exe
Pause >nul
Solution 3:[3]
Below is a pure batch solution without any VBS, JScript or PowerShell, but it's highly recommended to just avoid cmd with nasty legacy things and just use PowerShell. Things like this never happen on PowerShell
Why is %random% Windows time based and how to get a real random number?
%random%
is a special variable in cmd.exe. It has nothing to do with Windows itself. It's seeded by the famous classic srand((unsigned)time(NULL));
1 like most naive/simple C or C++ code so it can't provide proper random sequences if all of them start in the same second (which is the resolution of time()
function). There are so many related issues:
- Run rand() in C language and loop with Shell Scripts
- Is it possible to increase the refresh speed of srand(time(NULL)) in C?
- srand(time(NULL)) doesn't change seed value quick enough
The common solution is to use a high resolution time value like nanosecond because it's extremely unlikely for 2 processes to start in the same millisecond or nanosecond. That's still "time-based" but almost all random numbers are pseudo-random and seeded with time like that. There aren't any other good way to get a different seed that changes every time in cmd. You can never get a real random number in computers without a real entropy source
You can do a similar workaround by modifying the value with centisecond like this:
set /a "num=(random ^ %time:~-2%) %% 1000 + 3000"
Or get millisecond like this
for /F "usebackq tokens=2 delims==" %%i in (
`wmic os get LocalDateTime /VALUE`
) do @set ctime=%%i
set /a "num=(random ^ %ctime:~15,3%) %% 1000 + 3000"
For better results some programs combine the time with the process ID so that no two processes have the same seed. You can also do that
for /f "usebackq tokens=2 delims==; " %%a in (
`wmic process call create '"cmd.exe" "/c exit"' ^| find "ProcessId"`
) do @set PID=%%a
for /F "usebackq tokens=2 delims==" %%i in (
`wmic os get LocalDateTime /VALUE`
) do @set ctime=%%i
set /a "num=(random ^ %ctime:~15,3%*31 ^ PID) %% 1000 + 3000"
Here a child's PID is used instead of the current PID, but it's the same for this purpose
1As random as I wanna be: Why cmd.exe's %RANDOM% isn't so random
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | phuclv |
Solution 2 | Wasif |
Solution 3 |