This is a working SetMyPrio.bat
MyPrio.bat
that you can use from another to set the priority of your batch. If you copy it to a directory in your %PATH%
you can call it anytime you need it, etc. as usual. Thanks to TOOGAM, that gave me the tools and method to write this. The variable UniqueString
ensures that the pinpointed process is exactly which you need and not any other instance of your batch (improbable, but possible scenario).
@echo off
GOTO :EndOfReminder
<HELP>
USAGE:
From any batch file or command prompt, write
CALL MyPrio [/?|/h] [<priority>|get]
to set the priority of the caller cmd. Default for <priority> is idle.
/?, /h This help.
<priority> If you want your priority change to
idle -- no parameter, 64, idle or "idle"
below normal -- 16384 or "below normal"
normal -- 32, normal or "normal"
above normal -- 32768 or "above normal"
high priority -- 128 or "high priority"
real time -- 256, realtime or "realtime"
get Returns current priority as errorlevel
TO DO
- Parameter error control.
- Support for Unicode characters in help.
</HELP>
:EndOfReminder
setlocal
set Priority=%~1
if /I ["%Priority%"]==["/h"] ( call :PrintHelp & exit /b )
if ["%Priority%"]==["/?"] ( call :PrintHelp & exit /b )
set UniqueString=%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%
if ["%Priority%"]==["get"] for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get Priority /format:LIST`) do exit /b %%a
if not defined Priority set Priority=idle
for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get ParentProcessID /format:LIST`) do set myPID=%%a
wmic process where "ProcessId='%myPID%'" CALL setpriority "%Priority%" > nul 2>&1
endlocal
goto :eof
:PrintHelp
setlocal DisableDelayedExpansion
call :eln 0
set "levelerror=^%%errorlevel^%%"
for /F "delims=" %%a in ('find /v /n "" "%~f0"') do (
set "line=%%a"
REM We store errorlevel in tmpel because setlocal will set errorlevel to 0...
call set tmpel=%levelerror%
setlocal EnableDelayedExpansion
REM ... and now we restore it
REM %levelerror% was expanded to %errorlevel% before running the iteration
REM and the CALL SET allows actual errorlevel be stored in tmpel
REM Finally, we set errorlevel again
call :eln !tmpel!
set "line=!line:*]=!"
if /i "!line!"=="</HELP>" exit /b 0
if errorlevel 1 echo(!line!
if /i "!line!"=="<HELP>" call :eln 1
REM errorlevel is the only value that survives the following endlocal
endlocal
)
exit /b 1
:eln
REM Sets errorlevel to %1
exit /b %1
Edit (2018-06-12)
- Changed the name to MyPrio, added options
/?
, /h
and get
.
- Options
/?
and /h
print the text you write in the reminder
between <HELP>
and </HELP>
. This method can be reused in any other batch you need it.
If you make a call to MyPrio.bat
at the beginning of a batch, anytime you start it, no matter from a command line or dragging and dropping files from Windows Explorer (that become parameters), every part of it (and child processes) will run with your desired priority.
For example:
@echo off
call MyPrio
REM Here comes a set of commands that will run with idle priority.
call MyPrio normal
REM Here may come some interactive part to request information needed to continue.
call MyPrio
REM Back to idle (or put any other priority you prefer).
call MyPrio normal
REM You may want to set the priority to normal at the end just in case you call the batch from a command line.
COMMENTS
I made a batch named PrioTest.bat
to test MyPrio.bat
with every possible option, and ordered them so any call would change the priority to a different one. I made a subroutine (:test1
) that:
1. Gets current priority and save it to myPrioBefore
.
2. Calls MyPrio
with the test parameter.
3. Gets new priority and save it to myPrioAfter
.
4. Starts a hidden ping -t localhost
.
5. Gets priority and PID of the ping
process and saves them to
pingPrio
and pingPID
.
6. Prints the values of myPrioBefore
, the call to MyPrio
,
myPrioAfter
and pingPrio
.
7. Kills the started ping
(being sure it's not another one).
@echo off
setlocal
set UniqueString=%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%
for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get ParentProcessID /format:LIST`) do set myPID=%%a
for %%a in (64 16384 32 32768 128 256 idle "below normal" none normal "idle" "normal" "above normal" realtime "high priority" "realtime") do call :test1 %%a
CALL MyPrio normal
endlocal
goto :eof
:test1
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "ProcessID='%%myPID%%'" Get Priority /format:LIST`) do set myPrioBefore=%%b
if [%1]==[none] ( call MyPrio ) else ( call MyPrio %1 )
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "ProcessID='%%myPID%%'" Get Priority /format:LIST`) do set myPrioAfter=%%b
start "" /b ping -t localhost > nul
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "name='ping.exe' AND ParentProcessID='%%myPID%%'" Get Priority /format:LIST`) do set pingPrio=%%b
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "name='ping.exe' AND ParentProcessID='%%myPID%%'" Get ProcessID /format:LIST`) do set pingPID=%%b
echo myPrioBefore==%myPrioBefore% / CALL MyPrio %1 / myPrioAfter==%myPrioAfter% / pingPrio==%pingPrio%
taskkill /f /pid %pingPID% > nul
exit /b
This is the output of the tester batch:
myPrioBefore==4 / CALL MyPrio 64 / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio 16384 / myPrioAfter==6 / pingPrio==6
myPrioBefore==6 / CALL MyPrio 32 / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio 32768 / myPrioAfter==10 / pingPrio==8
myPrioBefore==10 / CALL MyPrio 128 / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio 256 / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio idle / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio "below normal" / myPrioAfter==6 / pingPrio==6
myPrioBefore==6 / CALL MyPrio none / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio normal / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio "idle" / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio "normal" / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio "above normal" / myPrioAfter==10 / pingPrio==8
myPrioBefore==10 / CALL MyPrio realtime / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio "high priority" / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio "realtime" / myPrioAfter==13 / pingPrio==8
As you can see, myPrioAfter
does not match the requested in the call and sometimes, the priority of the ping
is not equal to the parent cmd
so there must be more to the values (look at fifth line: current priority is 10, you request 128, new priority is 13 and child process' 8, sorry?). Also, realtime
seems not have effect (admin rights required I assume).