I was looking for a script to get PID of a java process based on CommandLine value of task manager. ALl these java processes have similar COmmandLine value but differ in a keyword within the CommandLine. The process can't be identified by the image name because they all have same java.exe. Is there a way? I've placed below code based on npocmaka's answer
#echo off
setlocal enableDelayedExpansion
set "command_line="%1""
set "command_line=!command_line:"=%%!"
echo ~~!command_line!~~
for /f "usebackq tokens=* delims=" %%# in (
`wmic process where 'CommandLine like "%command_line%"' get /format:value`
) do (
for /f %%$ in ("%%#") do (
set "%%$"
)
)
echo %ProcessId%
I'm using a keyword in CommandLine to identify the PID. Yet when I execute this script, I get the wrong PID. I'm assuming its returning the scripts PID as the script may also contain the keyword. The argument while executing the script is taken as keyword
WMIC PROCESS is what you need.Though you'll need some tricks to use it from batch.I've used more complex command line which contains quotes ,brackets,spaces, file separators.... You'll need to change it and set the value you want.
First you'll need to double every backslash in the command line(the script should do it I mean).Quotes also can be a problem and need to be replaced with % or escaped with \" (WMIC uses WQL a subset of SQL commands and % is used as wildcard).Another thing is you need to process the result twice with FOR loop to rid-off unwanted special characters./Format:Value can be used for direct declaring variable/value pairs.So here it is:
#echo off
setlocal enableDelayedExpansion
:: !!!!!!!!!
set "command_line="C:\Program Files (x86)\Dropbox\Client\Dropbox.exe" /systemstartup"
:: !!!!!!!!
set "command_line=!command_line:\=\\!"
set "command_line=!command_line:"=%%!"
::or
::set "command_line=!command_line:"=\"!"
rem echo ~~!command_line!~~
for /f "usebackq tokens=* delims=" %%# in (
`wmic process where 'CommandLine^="!command_line!"' get /format:value`
) do (
for /f %%$ in ("%%#") do (
set "%%$"
)
)
echo %ProcessId%
wmic process where name='explorer.exe' get commandline, pid /format:list
is one way. Also see tasklist /v.
Related
I'm getting a weird behaviour calling wmic inside a batch file, im trying to get the id of a process but when i set %% at the beginning of the string in the like command, it returns random numbers, but when i use them at the end its behaviour is normal
i have tried %%, %, ^%, \% and none of them works. all i have read indicates that i need to escape the % using a %% but i can't make it work at the start of the string
#echo off
setlocal EnableDelayedExpansion
FOR /F %%i in ('dir /b/a-d/od/t:c omcp_*.log') do set "FILENAME=%%i"
FOR /F "usebackq" %%A IN ('%FILENAME%') DO set "SIZE=%%~zA"
set commie=0
IF DEFINED LASTFILENAME (
IF "%FILENAME%" == "%LASTFILENAME%" (
if DEFINED LASTSIZE (
IF "%SIZE%"=="%LASTSIZE%" (
->->-> for /f "UseBackQ tokens=2 delims==" %%f in (`wmic PROCESS WHERE "COMMANDLINE LIKE '%%winlog%%'" GET ProcessID /value ^| find "="`) do set "commie=%%f"
echo !commie!
IF !commie! equ 0 echo "subir monitor"
) else (
echo "re subir monitor"
)
)
)
)
set LASTFILENAME=%FILENAME%
set LASTSIZE=%SIZE%
REM setx LASTFILENAME FILENAME
REM setx LASTSIZE SIZE
when i use only the last %% it work and return the id of the winlogon process, and that should happen if i use the start %%, the actual output is random, at least i think are random, numbers; for example:8260,11576,8596 and this is independent of the value that is searched
This is an answer to your specific issue, it does not deal with the other problems with your code, see my comment, or take account of whether, once fixed, the overall task does as you intend it to.
As well as the problematic wmic line ending issue, also implied in the comments, you need to take account of the fact that when you run the WMIC command, you're doing so with the string winlog included. That means the wmic.exe process CommandLine will match the string winlog too and you'll need to filter against this. It gets more complicated though because the parenthesised WMIC command to For is also run in a separate instance of cmd.exe so the cmd.exe process CommandLine will contain the WMIC command and therefore the string winlog too. You would therefore need to additionally filter against this in your WMIC command as well.
In summary, of the three ProcessID outputs you've shown in your question, 8260,11576 and 8596 one is for the winlogon process, one the cmd.exe process and the other for the wmic.exe process.
I'd therefore suggest you change your specifically indicated problematic line to:
For /F EOL^=P %%A In ('WMIC Process Where "Name<>'cmd.exe' And Name<>'wmic.exe' And CommandLine Like '%%winlog%%'" Get ProcessID 2^>Nul')Do For %%B In (%%A)Do Set "commie=%%B"
I generally prefer to use !=, or this format, Not Name=, but as you've enabled delayed expansion, I decided to steer clear of exclamation points chose the shorter <> alternative.
Please note that this answer cannot be expected to isolate a specific instance of CommandLine should there be more than one matching process. It also does not account for the possibility that your target CommandLine containing the string winlog could have been run through another instance of cmd.exe. If either of those two are possibilities, then your entire methodology needs a rethink.
I am basically trying to write a script on WIN10 that will allow me to start a python script, monitor for it to complete before moving on the next step. This looks like it should work but it just loops at the 2s timer, even after I close the notepad windows. This is kind of a combination of 2 scripts I found on here so I may be way out to lunch on my methods.
#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%
::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!")
)
:check
set stillalive=no
for /f "tokens=2" %%b in ('tasklist') do (
set pid=%%b
if !pid! == %RETPIDS% (
set stillalive=yes
)
)
if %stillalive% == yes (
cls
echo/Oh! He's still there, I'll wait.
timeout /t 2 /nobreak
goto check
) else (
echo/He's not there anymore, start the party!!
)
pause>nul
If there is a simpler way of doing this that's fine, if I can get this working with notepad, it should be easy to adapt to suit my needs.
Thanks in advance.
It's necro, I know, but I looked for something similar and just ended up here. This did a trick and fixed the script:
Replace
(set "RETPIDS=/PID %%a !RETPIDS!")
with
(set "RETPIDS=%%a!RETPIDS!")
The thing is that RETPIDS value looked like /PID 18465 and pid value was like 18465 and there also was a mess up with !!, %%, "%%" stuff and condition therefore strangely triggered every time although it obviously shouldn't.
Also seems that yours RETPIDS implies a possibility of several PIDs in one string like "5147 8463 6521" but it defenitely won't work with your single !pid! comparison in a loop.
I have two .txt files. One contains numbers, and the other one contains filepaths. I want to combine these two files to a .csv. The combination is based on wether the number (from nrs.txt) is in the string of the filepath (nodups.txt).
Now I have the following code for this:
#setlocal enableextensions enabledelayedexpansion
for /F %a IN (Output\nrs.txt) DO (
SET "nrs=%a"
for /F %b IN (Output\nodups.txt) DO (
SET "pathstring=%b"
SET csvdelim=,
IF NOT x!pathstring:%nrs%=""!==x%pathstring% %nrs%,%pathstring%>>new2017.txt
)
)
#endlocal
However, I keep having the following issues with the code:
The pathstring never seems to get set. (when I run the code without the if statement, The nrs variable gets set but the pathstring is set to %b). I've seen a lot of possible solutions on here already but none seem to work for me (setting variables like !var! and using usebackq).
The IF statement in the second for loop gets the following error message =""!==x%pathstring% was unexpected at this time. The ="" should remove the nr. from the path (if its there). When I replace "" with something else it still does not work.
The file contents are:
File nrs.txt:
12345
12245
16532
nodubs.txt:
C:\tmp\PDF_16532_20170405.pdf
C:\tmp\PDF_1234AB_20170405.pdf
C:\tmp\PDF_12345_20170506.pdf
Desired output:
12345, C:\tmp\PDF_12345_20170506.pdf
16532, C:\tmp\PDF_16532_20170405.pdf
I really hope someone can help me out with this !
This solution use a different approach, based on arrays:
#echo off
setlocal EnableDelayedExpansion
rem Load array from nodubs.txt file
pushd "Output"
for /F "tokens=1,2* delims=_" %%a in (nodubs.txt) do set "nodubs[%%b]=%%a_%%b_%%c"
rem Process nrs.txt file and show output
(for /F %%a in (nrs.txt) do (
if defined nodubs[%%a] echo %%a, !nodubs[%%a]!
)) > new2017.txt
In a batch file for variables need two percent signs.
There is no need to put %%A into a variable, use it directly.
#setlocal enableextensions enabledelayedexpansion
for /F %%a IN (Output\nrs.txt) DO (
findstr /i "_%%a_" Output\nodups.txt >NUL 2>&1 || >>new2017.txt Echo %%a
)
#endlocal
Instead of a second for, I'd use findstr to search for the entry of nrs.txt enclosed in underscores.
if no find use condiotonal execution on failure || to write to the new file.
According to changed preliminaries another answer.
#Echo on
Pushd Output
for /F "tokens=1-3 delims=_" %%A IN (
' findstr /G:nrs.txt nodubs.txt'
) DO >>"..\new2017.txt" Echo %%B, %%A_%%B_%%C
Popd
sample output:
> type ..\new2017.txt
16532, C:\tmp\PDF_16532_20170405.pdf
12345, C:\tmp\PDF_12345_20170506.pdf
What I'm trying to do is suspend multiple processes from a single folder in Windows 7. I can get a list of such proccessses using the following commands:
WMIC PROCESS WHERE 'ExecutablePath like "c:\\users%"' GET
or
WMIC PROCESS WHERE 'ExecutablePath like "c:\\users%"' LIST
Then I need to suspend the proccesses that are returned by those commands. I can do that by using PsSuspend software. So, the only thing I have troubles with is looping through the list and executing this command for each process. It's rather easy to do in bash scripts, but how do I do it easily in Windows? I would prefer to use a .bat file or something similar, so it won't get overly complicated.
Here's an example:
#Echo Off
SetLocal EnableExtensions
Rem Command
(Set WC=Process)
Rem Filter
(Set WF=ExecutablePath Like)
Rem Value
(Set FV=%UserProfile%)
Rem Output
(Set RO=ProcessID)
Rem Run
(Set RC=PsSuspend)
For /F "UseBackQ Skip=1" %%A In (
`WMIC %WC% Where "%WF% '%FV:\=\\%%%'" Get %RO%`) Do For %%B In (%%A
) Do %RC% %%B
I changed line 9 to %UserProfile% you can change it back to C:\Users if you think I've assumed wrongly.
I am creating an MS DOS batch script that needs to list every .bat file in the current directory, but not show autoexec.bat or other utilities or systems .bat files that shouldn't be run by the user.
I currently have DIR "*.bat" /B /P
This lists all .bat files appropriately, but it shows autoexec.bat. How would I exclude that from the list? Also slightly important, how could I chop off the file extensions and show more than the 7-characters DOS limits files to?
Constraints: I am not able to use a DOS version above WinME. That is the version I am using.
Thanks for any help.
EDIT:
There is plenty of information on the internet about doing this, but it is all in the windows command processor, not MS DOS. Please understand that DOS and the Command Prompt are not the same thing.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
echo %%~Na
)
)
EDIT: Some explanations added
Batch file processing is slow, so you should use techniques that allows a Batch file to run faster. For example:
Try to use the minimum lines/commands to achieve a certain result. Try to avoid external commands (*.exe files) like find, findstr, fc, etc. specially if they work on small amounts of data; use if command instead.
Use for %%a in (*.bat)... instead of for /F %%a in ('dir /B *.bat').... The second method requires to execute cmd.exe and store its output in a file before for command can process its lines.
Avoid pipes and use redirections instead. A pipe require the execution of two copies of cmd.exe to process the command at each side of the pipe.
A simple way to check if a variable contain a given string is trying to delete the string from the variable: if the result is different then the string exists in the variable: if "!variable:%string%=!" neq "%variable%" echo The string is in the variable.
Previous method may also be used to check if a variable have anyone of a list of values: set list=one two three, if "!list:%variable%=!" neq "%list%" echo The variable have one value from the list. If the values of the list may have spaces, they must be separated by another delimiter.
EDIT: New version added as answer to new comments
The easiest way to pause one page at a time is to use more filter this way:
theBatchFile | more
However, the program must reorder the output in order to show it in columns. The new version below achieve both things, so it does not require more filter; you just need to set the desired number of columns and rows per page.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
rem Set the first two next variables as desired:
set /A columns=5, rows=41, wide=(80-columns)/columns, col=0, row=0
rem Create filling spaces to align columns
set spaces=
for /L %%a in (1,1,%wide%) do set spaces= !spaces!
set line=
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
rem If this column is less than the limit...
set /A col+=1
if !col! lss %columns% (
rem ... add it to current line
set name=%%~Na%spaces%
set "line=!line!!name:~0,%wide%! "
) else (
rem ... show current line and reset it
set name=%%~Na
echo !line!!name:~0,%wide%!
set line=
set /a col=0, row+=1
rem If this row is equal to the limit...
if !row! equ %rows% (
rem ...do a pause and reset row
pause
set row=0
)
)
)
)
rem Show last line, if any
if defined line echo %line%
Antonio
attrib +h autoexec.bat
should hide autoexec.bat and it should thus not appear in the list
DIR "*.bat" /B /P | find /v "autoexec" | for %i in (*.bat) do #echo %~ni
Using for to process each file name individually:
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.bat" /b') do (
set system=0
if "%%i"=="autoexec.bat" set system=1
if "%%i"=="somesystem.bat" set system=1
if !system!==0 echo %%i
)
Another method without variables:
for /f %%i in ('dir "*.bat" /b') do call :test %%i
goto continue
:test
if "%1"=="autoexec.bat" goto :eof
if "%1"=="somesystem.bat" goto :eof
echo %1
goto :eof
:continue
For both, you can add new filenames to exclude from the list.