I believe the following is bulletproof, provided the user has access to WMIC and TEMP points to a valid path where the user has write privileges. This is the end result of some collaborative work at http://www.dostips.com/forum/viewtopic.php?f=3&t=6133.
:: Store the Process ID (PID) of the currently running script in environment variable RtnVar.
:: If called without any argument, then simply write the PID to stdout.
endlocal & set "uid=%uid%"
2>nul ( 9>"%lock%" (
for /f "skip=1" %%A in (
'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
) do for %%B in (%%A) do set "PID=%%B"
del "%lock%" 2>nul
endlocal & if "%~1" equ "" (echo(%PID%) else set "%~1=%PID%"
The script establishes an exclusive lock on a temporary file that incorporates the current time into the name. There can only be a collision if two like named batch processes attempt to get the PID within the same 0.01 second time interval, in which case only one will succeed.
Any process that fails will repeatedly loop back and try again with a new lock file path until it succeeds.
The full path to the lock file is transformed into a unique ID that can be used in the WMIC query. WMIC is run within a FOR /F command, which means it is running in a child cmd.exe process. That is why the ParentProcessID of the cmd.exe process is retrieved.