Save the result of a command in variable, Windows batch - windows

I am trying to write a batch script that saves the result of a command in a variable. so I can use it later.
For example I am tryin to run this on the script:
sc queryex "Service" |find /i "pid"
but I want to save this result in a variable.
set PIDRS=sc queryex "Themes" |find /i "pid"
ECHO "%PIDRS%
Any Ideas?

for /f "tokens=* delims=" %%# in ('sc queryex "Themes" ^|find /i "pid"') do set "PIDRS=%%#"
echo %PIDRS%
This will set the entire line to PIDRS
here's how to get only the pid:
#echo off
set "rspid="
for /f "skip=9 tokens=2 delims=:" %%# in ('sc queryex "Themes"') do (
if not defined rspid set /a rspid=%%#
)
the second does not use additional FIND which in theory should make it faster.

Related

Batch error "( unexpected" if statement nested inside for loop

I wrote this small script to kill Spotify whenever the title of the window is "Advertisement". For now, it just looks for the spotify.exe process and, if the name of the window matches, kills it (next step is executing it every second). However, I get an error every time I execute it, telling me that there's an unexpected ( in IF /i "%A:~0,4" (, but such statement is not in my code: it seems like Windows modifies IF /i "%%A:~0,4%"=="PID:" ( before executing it.
Here's the script:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
tasklist /fi "imagename eq spotify.exe" /fo list /v > tmp.txt
FOR /F "usebackq tokens=*" %%A IN ("tmp.txt") DO (
SET test=%%A
echo %%A
IF /i "%%A:~0,4%"=="PID:" (
SET "pid=%%A:PID: =%"
echo %pid%
)
IF /i "%%A:~0,13%"=="Window Title:" (
SET "wintitle=%%A:Window Title: =%"
echo %wintitle%
)
IF "%wintitle%"=="Advertisement" (
taskkill /F /PID %pid%
)
)
PAUSE
Error message (with echo on):
C:\Users\marco\Desktop>antispotify.bat
C:\Users\marco\Desktop>tasklist /fi "imagename eq spotify.exe" /fo list /v 1>tmp.txt
( was unexpected at this time.
C:\Users\marco\Desktop> IF /i "%A:~0,4" (
Does anyone know what's wrong with my code?
The task to force a real kill of Spotify process running for advertisement can be done also by using following batch file without using delayed expansion.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1* delims=:" %%I in ('%SystemRoot%\System32\tasklist.exe /FI "imagename eq spotify.exe" /FO LIST /V 2^>nul') do (
if /I "%%~I" == "PID" (
for /F %%K in ("%%~J") do set "ProcessIdentifier=%%~K"
) else if /I "%%~I" == "Window Title" (
for /F "tokens=*" %%K in ("%%~J") do if /I "%%~K" == "Advertisement" call %SystemRoot%\System32\taskkill.exe /F /PID %%ProcessIdentifier%%
)
)
endlocal
The same code with using delayed environment variable expansion:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=1* delims=:" %%I in ('%SystemRoot%\System32\tasklist.exe /FI "imagename eq spotify.exe" /FO LIST /V 2^>nul') do (
if /I "%%~I" == "PID" (
for /F %%K in ("%%~J") do set "ProcessIdentifier=%%~K"
) else if /I "%%~I" == "Window Title" (
for /F "tokens=*" %%K in ("%%~J") do if /I "%%~K" == "Advertisement" %SystemRoot%\System32\taskkill.exe /F /PID !ProcessIdentifier!
)
)
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
if /?
setlocal /?
taskkill /?
tasklist /?
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
As noted in the comments, substring manipulation doesn't work on for variables (%%a type). Instead, you need an ordinary variable and of course delayed expansion.
But may I suggest another approach:
#ECHO OFF
SETLOCAL
for /f "tokens=2,9 delims=," %%a in ('tasklist /fi "imagename eq notepad.exe" /fo csv /v /nh') do (
set "pid=%%~a"
set "wintitle=%%~b"
)
set pid
set wintitle
IF "%wintitle%"=="Advertisement" taskkill /F /PID %pid%
Here we use the command directly with the for loop instead of using a temporary file. Besides that, we change the output format to csv (easier to parse) with no header line ( /nh)
( I used notepad.exe, because I don't have spotify, but that's easy to adapt)

Path over registry (windows)

I try to get a path over the regestry of windows. My Problem now is how do I get the Path out of MATLAB_ROOT_32?
for /F "tokens=* delims='C'" %%i IN ('reg query HKLM\SOFTWARE\WOW6432NODE\Mathworks\Matlab\7.9.1 /v MATLABROOT') do (set MATLAB_ROOT_32=%%i)
echo %MATLAB_ROOT_32%
set i=
rem GOTO Split1
rem :Split1
REM -- Split the result into MATLABROOT, REG_SZ and Folder using space as delimiter
for /f "tokens=1,2,3 delims='C'" %%a in ("%MATLAB_ROOT_32%") do set useless1=%%a&set useless2=%%b&set MATLAB_x32=%%c
echo %Matlab_x32%
The plan is to get the MATLAB Path in the Matlab_x32 variable.
This works for me:
#echo off
setlocal ENABLEEXTENSIONS
set MATLAB_VERSION=8.3
set KEY_NAME=HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\MathWorks\MATLAB\%MATLAB_VERSION%
set VALUE_NAME=MATLABROOT
for /F "usebackq tokens=2*" %%A IN (`reg query "%KEY_NAME%" /v "%VALUE_NAME%" 2^>nul ^| find "%VALUE_NAME%"`) do (
set MATLABROOT=%%B
)
echo %MATLABROOT%
Just change the Matlab version to whatever you're using and it should be fine. There are variations in the output from reg depending on the OS version, but this should cope (I think!)

windows 7 not generating txt report

I want to generate a txt file with my dns history. Although the batch script executes just fine on windows 8, when i run it on windows 7 it simply creates a blank txt file. Does anyone knows why this is happening?
Here's the batch script
#echo off
setlocal enableextensions
set "baseName=dnshistory"
set "count=0"
for /f "delims=%baseName%." %%a in (
'dir /b /o-d "%baseName%*.txt" 2^>nul'
) do ( set /a "count=%%a+1" & goto saveData )
:saveData
ipconfig /displaydns | find "Record Name" > "%baseName%%count%.txt"
Is you Windows 7 version in English too ?
Open a CMD windows and test just the command :
ipconfig /displaydns | find /i "Record Name"
and look if something is displayed.
If not, try just the command :
ipconfig /displaydns
and look the language used Then correct your code with the correct words.
IE in Portuguese it will be :
ipconfig /displaydns | find /i "Nome do Registro"
try this for a language independent solution:
:saveData
(for /f "tokens=2 delims=:" %%a in ('ipconfig /displaydns') do (
echo %%a| find "." |findstr /v /r "[0-9]$"
))>file.txt
(take every line, filter those, that have a . after a : (second token) and filter out all lines that end with a number)
EDIT another approach (because the above gives some unwanted lines):
find the first line after every ----------------- line:
#echo off
setlocal enabledelayedexpansion
ipconfig /displaydns |findstr /n "^" >a.txt
for /f "tokens=1 delims=:" %%a in ('findstr /c:" --------------" a.txt') do (
set /a line=%%a+1
for /f "tokens=1,2,* delims=:" %%i in ('findstr /B "!line!:" a.txt') do echo(%%k
)

Find text in file and set it as a variable. Batch file

I try to find one line in whole text file. Next I need to set this line as a variable.
When I try do this:
set MY_VARIABLE=findstr /I "MY_TEXT" MY.FILE
echo %MY_VARIABLE%
The result of echo is findstr /I "MY_TEXT" MY.FILE, but I want to see result of this command line instead.
When I try do this – first enter in cmd:
for /F "delims=" %%a in ('findstr /I "MY_TEXT" MY.FILE') do set "batToolDir=%%a"
then enter in cmd:
echo "%batToolDir%"
I see an error:
the %%a variable is unsuspected
When I make a file SCRIPT.bat:
#echo off
for /F "delims=" %%a in ('set MY_VARIABLE=findstr /I "MY_TEXT" MY.FILE') do set "batToolDir=%%a"
echo "%batToolDir%"
I get this:
""
What is wrong? How to make this?
Almost done
For command line
for /F "delims=" %a in ('findstr /I "MY_TEXT" MY.FILE') do set "batToolDir=%a"
For batch file double the percent signs
for /F "delims=" %%a in ('findstr /I "MY_TEXT" MY.FILE') do set "batToolDir=%%a"

How to get PID of process just started from within a batch file?

In Windows batch scripting there is start command which starts a new process.
Is it possible to get PID of the process just started?
This is an old post but I think that it worth to share the following 'easy to use' solution which works fine nowadays on Windows.
Start multiple processes in parallel:
start "<window title>" <command will be executed>
Example:
start "service1" mvn clean spring-boot:run
start "service2" mvn clean spring-boot:run
Obtain the PID of the processes (optional):
tasklist /V /FI "WindowTitle eq service1*"
tasklist /V /FI "WindowTitle eq service2*"
Kill the processes:
taskkill /FI "WindowTitle eq service1*" /T /F
taskkill /FI "WindowTitle eq service2*" /T /F
You can in batch but not directly per say. You need to either parse the output of tasklist.exe or use wmic.exe. Both require you to know what you just started which of course you will.
Using tasklist.exe:
for /F "TOKENS=1,2,*" %a in ('tasklist /FI "IMAGENAME eq powershell.exe"') do set MyPID=%b
echo %MyPID%
To use this in a batch script double up the percent signs.
Using wmic.exe:
for /f "TOKENS=1" %a in ('wmic PROCESS where "Name='powershell.exe'" get ProcessID ^| findstr [0-9]') do set MyPID=%a
echo %MyPID%
If there are processes already running with the same name, you first need to get a list of the current pids, than start your local process(es) and then check the pids again. Here is a sample code that starts 3 process and kills them at the end (specifically the ones started locally):
#echo off
set PROCESSNAME=notepad.exe
::First save current pids with the wanted process name
setlocal EnableExtensions EnableDelayedExpansion
set "RETPIDS="
set "OLDPIDS=p"
for /f "TOKENS=1" %%a in ('wmic PROCESS where "Name='%PROCESSNAME%'" get ProcessID ^| findstr [0-9]') do (set "OLDPIDS=!OLDPIDS!%%ap")
::Spawn new process(es)
start %PROCESSNAME%
start %PROCESSNAME%
start %PROCESSNAME%
::Check and find processes missing in the old pid list
for /f "TOKENS=1" %%a in ('wmic PROCESS where "Name='%PROCESSNAME%'" get ProcessID ^| findstr [0-9]') do (
if "!OLDPIDS:p%%ap=zz!"=="%OLDPIDS%" (set "RETPIDS=/PID %%a !RETPIDS!")
)
::Kill the new threads (but no other)
taskkill %RETPIDS% /T > NUL 2>&1
endlocal
you can try with
wmic process call create "notepad"
which will return the pid of the created process.
Processing this with FOR
setlocal
set "ReturnValue="
set "ProcessId="
for /f "eol=} skip=5 tokens=1,2 delims=;= " %%a in ('wmic process call create "notepad"') do (
set "%%a=%%b"
)
echo %ReturnValue%
echo %ProcessId%
endlocal
PowerShell can be used for this:
powershell -executionPolicy bypass -command "& {$process = start-process $args[0] -passthru -argumentlist $args[1..($args.length-1)]; exit $process.id}" notepad test.txt
echo Process ID of new process: %errorlevel%
This is the code that i use to get a PID
for /f "tokens=2 delims=," %%a in ('tasklist /FO CSV ^| findstr /I /C:"entertheprocess.here"') do (
echo PID:%%a
)
#ECHO OFF
SETLOCAL EnableDelayedExpansion EnableExtensions
::
::weil es mehrere Sessions für UltraCompare gleichzeitig geben kann, es wird hier die
::neueste Instanz (soeben gestartet) ermittelt, um später mit ProcessId diese Instanz
::aktivieren zu können...
::
set "CreationDate="
set /A "ProcessIdUltraCompare=0"
::
set /A "lineno=0"
FOR /F %%T IN ('Wmic process where^(Name^="uc.exe"^) get CreationDate^|sort /r') DO (
set /A lineno+=1
rem echo %%T
rem echo !lineno!
if !lineno! equ 2 (
rem ECHO %%T
set CreationDate=%%T
rem echo !CreationDate!
set /A "lineno=0"
FOR /F %%P IN ('Wmic process where^(CreationDate^="!CreationDate!"^) get ProcessId') DO (
set /A lineno+=1
rem echo %%P
if !lineno! equ 2 (
set "ProcessIdUltraCompare=%%P"
rem echo ProcessIdUltraCompare=!ProcessIdUltraCompare!
goto :l_pid_uc_got
)
)
)
)
:l_pid_uc_got
echo ProcessIdUltraCompare=!ProcessIdUltraCompare!
PAUSE

Resources