Querying process by CommandLine - wmi

I'm trying to do the following query in WMI:
SELECT ProcessID from Win32_Process where CommandLine='C:\Windows\system32\calc.exe'
But I got an "Invalid query" error. I also tried with:
SELECT ProcessID from Win32_Process where CommandLine='C:\\Windows\\system32\\calc.exe'
And still get the same error, also I tried to change the single quotes to double quotes but it didn't work.
Does anybody know if its possible to do that query?

Yes and No. Depends on how calc.exe is spawned. For instance, when I type calc into cmd.exe window, my calc gets a commandline of 'calc'. When I type calc into powershell.exe console, it get's a full path. The Win32_Process 'commandline' variable is not reliable IMO. Here are some differing result to prove my point.
cmd.exe 4028 C:\Windows\system32\cmd.exe /K set
calc.exe 2580 "C:\Windows\system32\calc.exe"
notepad.exe 3612 "C:\Windows\system32\notepad.exe"
cmd.exe 2864 "C:\Windows\system32\cmd.exe"
conhost.exe 480 \??\C:\Windows\system32\conhost.exe
WMIC.exe 3596 wmic
WmiPrvSE.exe 2272 C:\Windows\system32\wbem\wmiprvse.exe
cmd.exe 2296 "C:\Windows\system32\cmd.exe"
conhost.exe 3708 \??\C:\Windows\system32\conhost.exe
notepad.exe 1284 "C:\Windows\system32\notepad.exe"
calc.exe 1736 calc
powershell.exe 3136 "C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe"
So to make it work you will need an OR clause in your SQL statement, matching 'calc' or "C:\Windows\system32\calc.exe"

In addition Windows adds sometimes an additional whitespace into the command line after the ExecutablePath and before the first parameter.
Even if there is no paramter and the Executable was lanched with quotes (because of whitespaces in the path) then in most cases the command line is the ExecutablePath and a final whitespace at the end.
That cost me some hours to find this.
Cheers!

Related

Why cannot execute "taskkill" from cmd in c++?

I want to execute taskkill from cmd in c++ code. I have tried two forms:
Simple form:
system("taskkill /IM 'example.exe' /F");
With administrative privilege (because one of my processes has high privilege):
system("runas / profile / user:administrator \"taskkill /IM 'exmaple.exe' /F\"");
Also my c++ program was run as administrator.
But none of these commands executed successfully. What is the problem?
An immediate fix could be to remove the single quotes (') enclosing example.exe.
E.g. instead of:
system("taskkill /IM 'example.exe' /F");
Use:
system("taskkill /IM example.exe /F");
Using double quotes (" - escaped in this case with \) is also OK:
system("taskkill /IM \"example.exe\" /F");
However -
As commented above by #PepijnKramer, you can use dedicated windows API functions to do the same.
This requires a bit more code, but offers much better control and feedback of errors.
Here's an outline of what you need to do:
Get the process PID from its name (see below).
Open the process using OpenProcess API to aqcuire a handle to it, with PROCESS_TERMINATE access right (see below).
An example of getting PID and then a handle to a process by its name: How can I get a process handle by its name in C++?.
Use the handle with TerminateProcess API to kill the process.
Note that in order to use it:
The handle must have the PROCESS_TERMINATE access right.
(this should be passed to OpenProcess via the dwDesiredAccess parameter).

Batch File If Statements causing close of CMD and not working

I am creating a should-be-simple batch file that will allow me to input a class name and it will take me to the correct google classroom. However, my if statement doesn't work, even when I input the word "Social Studies". It does not take me to my classroom, and on top of that, the CMD is just closed. When I remove the If Statement line, the code works fine and the cmd just stays open after inputting a class.
set /p class="Enter Class: "
IF "%class%" /I EQU "Social Studies" (START https://classroom.google.com)
cmd /k
IF /I "%class%" EQU "Social Studies"...
The parsing logic for an if statement is very specific; if [/i][NOT] arg1 op arg2 where /i and not are optional, but must if used, be used in that order.
Your code sees /i where it expects a comparison-operator and generates a syntax-error.
When you use the point-click-and-giggle method of executing a batch, the batch window will often close if a syntax-error is found. You should instead open a 'command prompt' and run your batch from there so that the window remains open and any error message will be displayed.
You can write #echo off whice prevents the prompt and contents of the batch file from being displayed.
I replaced the your EQ with == and now it works:
#echo off
set /p class="Enter Class: "
IF "%class%"=="Social Studies" (START https://classroom.google.com)
PAUSE
The PAUSE at the end will make the CMD remain open after it's done

Windows Batch - how to add timestamp while redirecting stdout to file

I'm doing make all -d --trace
How do I get Gnu Make to output timestamps for every line it outputs?
More generally, how do I add a timestamp to every STDOUT and STDERR statement?
There is a solution for Linux/Bash but I'm on Windows.
I created a one line batch file add_ts.bat : echo %time% %1
I tried the following but I only got one timestamp (without the lines that were output):
make all --trace -d 2>&1 | add_ts.bat
To a first approximation you need a batch file like:
add_ts.bat
#for /F "usebackq delims==" %%i in (`%1`) do #echo %time% %%i
which you would run like:
add_ts.bat "make all -d --trace" > buildlog.txt
This however isn't good enough if you want to capture and
timestamp STDERR as well as STDOUT from the command passed as
%1, because the backticks operator around %1 will only capture STDOUT
To fix this you'll need to capture STDERR as well as STDOUT within the backticks, by using redirection in there, which in turns means
you need to run a subshell to understand the redirection, and you need to
escape the redirection operators so they're not interpreted by the toplevel
shell. Which all comes to:
#for /F "usebackq delims==" %%i in (`cmd /C %1 2^>^&1`) do #echo %time% %%i
Run just the same way.
Later
what I don't get is why the | itself wasn't enough to send STDOUT and STDERR to STDIN of add_ts.bat
It is. I think you are labouring under the combination of two misconceptions.
One: You believe that a program's commandline arguments are the same as its standard
input, or that it gets it commandline arguments from its standard input. It doesn't.
A program's commandline arguments, if any, are passed to it as a fixed list
of strings in the program-startup protocol. Its standard input is an input stream made
available to it at the same time by the OS and connected by default to the console in which the program
starts. This default can be overridden in the shell by redirection operators. The contents of that input stream are not fixed in advance. It will feed to the
the program whatever is input to the console, or from its redirected proxy, as long as the program is running, as and when the program reads it. The program
can parse or ignore its commandline arguments and, quite independently of that, it can read or ignore its standard input.
Your program add_ts.bat is a program that parses the first of its commandline arguments
- it uses %1 - and ignores any more. And it ignores its standard input entirely.
Two: You believe that the effect of a pipeline, e.g.
a | b
is to start an a process and then, for each line that it writes to the standard output, start
a distinct b process which will automatically receive that one line written by a as
a single commandline argument (no matter who many words are in the line) and do its stuff
with that single commandline argument.
That's not what happens. The OS starts one a process and one b process, and connects the
standard output of the one a process to the standard input of the one b process. For the
pipeline to work at all, b has got to be a program that reads its standard input. Your
add_ts.bat is not such a program. It's only a program that parses its first commandline
argument: the | doesn't give it any, and the commandline:
make all --trace -d 2>&1 | add_ts.bat
doesn't give it any either. The commandline:
make all --trace -d 2>&1 | add_ts.bat "Hello World"
would give it one commandline argument and:
make all --trace -d 2>&1 | add_ts.bat Hello World
would give it two, not one, commandline arguments, the second being ignored. But in any case
it doesn't read its standard input so piping to it is futile.
The site ss64.com is perfectly good about CMD redirection and piping
but it assumes you know what a program has to do to be a pipeline-able command: To be an upstream command,
it has to write its standard output; to be a downstream command it has to read its standard input.
Using a batch file wrapper is a clever solution if you don't mind the extra overhead. Otherwise I think you'll have to modify GNU make itself to have it print out this data.
If that's not palatable for some reason, you can get that information by using ElectricMake, a GNU-make-compatible implementation of make that includes lots of enhancements, including annotated build logs that have microsecond-resolution timestamps for every job in the build. ElectricMake is part of ElectricAccelerator Huddle.
Here's a bit of the annotation for a trivial "echo Hello World!" job:
<job id="J00007fb820002000" thread="7fb82f7fe700" start="3" end="4" type="rule" name="all" file="
Makefile" line="1">
<command line="2">
<argv>echo Hello, world!</argv>
<output src="prog">Hello, world!
</output>
</command>
<commitTimes start="0.291693" wait="0.296587" commit="0.296628" write="0.296680"/>
<timing invoked="0.291403" completed="0.296544" node="ecdroid3a-59"/>
</job>
Here, the <timing> tag shows the start time (0.291403 seconds) and end time (0.296544 seconds) of the job relative to the start of the build.
These annotated build logs can be viewed and analysed graphically with ElectricInsight, a companion tool for ElectricMake.
ElectricAccelerator Huddle is the freemium version of ElectricAccelerator -- usage is entirely free up to a point, with modest pay-as-you-go fees beyond that
Disclaimer: I'm the architect of ElectricAccelerator.

How can I find why system can not run my application?

I have a c++ program that run a command and pass some arguments to it. The code is as follow:
int RunApplication(fs::path applicationPathName,std::string arguments)
{
std::string applicationShortPath=GetShortFileName(applicationPathName);
std::string cmd="\""+applicationShortPath +"\" "+ arguments+" >>log.txt 2>&1 \"";
std::cout<<cmd<<std::endl;
int result=std::system(cmd.c_str());
return result;
}
When I run system command, the cmd window appears shortly and then closes, but the result is 1 and the cmd was not run (the command should generate output which is not generated).
To check that the cmd is correct, I stopped the application just before system line and copy/ paste cmd content to a cmd window and it worked.
I am wondering how can I find why application is not run in system()?
the cmd has this value just before running it:
"D:/DEVELO~3/x64/Debug/enfuse.exe" -w --hard-mask --exposure-weight=1 --saturation-weight=0.328 --contrast-weight=0.164 -o "C:/Users/m/AppData/Local/Temp/1.tif" "C:/Users/m/AppData/Local/Temp/1.jpg" "C:/Users/m/AppData/Local/Temp/2.jpg" >>log.txt 2>&1 "
How can I find why it is not working?
Is there any way that I set the system so it doesn't close cmd window so I can inspect it?
is there any better way to run a command on OS?
Does Boost has any solution for this?
Edit
After running it with cmd /k, I get this error message:
The input line is too long.
How can I fix it other than reducing cmd line?
There are two different things here: if you have to start a suprocess, "system" is not the best way of doing it (better to use the proper API, like CreateProcess, or a multiplatform wrapper, but avoid to go through the command interpreter, to avoid to open to potential malware injection).
But in this case system() is probably the right way to go since you in fact need the command interpreter (you cannot manage things like >>log.txt 2>&1 with only a process creation.)
The problem looks like a failure in the called program: may be the path is not correct or some of the files it has to work with are not existent or accessible with appropriate-permission and so on.
One of the firt thing to do: open a command prompt and paste the string you posted, in there. Does it run? Does it say something about any error?
Another thing to check is how escape sequence are used in C++ literals: to get a '\', you need '\\' since the first is the escape for the second (like \n, or \t etc.). Although it seems not the case, here, it is one of the most common mistakes.
Use cmd /k to keep the terminal: http://ss64.com/nt/cmd.html
Or just spawn cmd.exe instead and inspect the environment, permissions, etc. You can manually paste that command to see whether it would work from that shell. If it does, you know that paths, permssions and environment are ok, so you have some other issue on your hands (argument escaping, character encoding issues)
Check here How to execute a command and get output of command within C++ using POSIX?
Boost.Process is not official yet http://www.highscore.de/boost/process/

Windows Command Line Processor: Multiple and Nested IF Statements

Intended software: windows command line processor (version 6.1.7601.17514)
Hi,
I've been trying to build a multiple-statement command line that runs within a short-cut. My goal is to be able to click one short-cut that checks if my hosted network is started or not, and then takes appropriate action based on the check. The code that starts and stops the hosted network is fine, and for the most part, the logic works, but I notice odd behavior when I check the outputs of the logic. I suspect that my problem has to do with the way I structured the statements, but I'm having difficulty properly interpreting the built-in documentation and the documentation I can find in the MSDN library. If it's possible, I want to avoid using batch files for this solution.
To keep things simple, I've substituted my lengthy "netsh" commands with "echo" commands that show the errorcode. The code below is what I'm using to test my logic:
Test Code
netsh wlan show hostednetwork | find "Not" && echo found %errorlevel% || echo lost %errorlevel%
Currently, the way I'm reading this is:
Show me hostednetwork's status and send the output to input
Attempt to find the string "Not" in the input
If the attempt succeeds, output "found" and the errorcode to the screen
If the attempt fails, then output "lost" and the errorcode to the screen
Notice that I'm not using any flags on the find command. I'm doing this because I want to reduce the chance of finding a false match. To clarify what I mean, I'll show the output if I just put in
netsh wlan show hostednetwork:
Sample Output of Hostednetwork Status
C:\Windows\system32>netsh wlan show hostednetwork
Hosted network settings
-----------------------
Mode : Allowed
SSID name : "TestHost"
Max number of clients : 100
Authentication : WPA2-Personal
Cipher : CCMP
Hosted network status
---------------------
Status : Not started
If I search for the string "Not", then that's sufficient to tell me that the hosteadnetwork is not started, because when the hosteadnetwork is started, the output shows "Started".
The way I'm simulating the conditions of the hostednetwork is with the following commands:
netsh wlan start hostednetwork
netsh wlan stop hostednetwork
I expect that when I open a command prompt (as an administrator):
If the hostednetwork is not started, I should see a "found 0" in the output, meaning that the string was found and that there were no errors.
If the hostednetwork is started, I should see a "lost 1" in the output, meaning that the string was not found and that there was an error.
Case #1 works, but case #2 doesn't work on the first try. Here's my output when the hostednetwork is already started:
Output With Hostednetwork Started
C:\Windows\system32>netsh wlan start hostednetwork
The hosted network started.
C:\Windows\system32>netsh wlan show hostednetwork | find "Not" && echo found %er
rorlevel% || echo lost %errorlevel%
lost 0
C:\Windows\system32>netsh wlan show hostednetwork | find "Not" && echo found %er
rorlevel% || echo lost %errorlevel%
lost 1
Other Attempted Solutions
The way I've written the test code is the best I could come up with so far. In previous attempts, I've tried:
Setting a custom variable instead of using the errorlevel variable, but I get the same output on case #2.
Changing the code into an if else equivalent, but that didn't pan out very well.
Wrapping the conditional statements in brackets "()" after the pipe and using different combinations of the special symbols "&" and "|".
Other Questions
This question is related to another that I've been trying to figure out. If I wanted to search for three different strings in a command's output and exit on a different error code for each string, how can I do this? The syntax below is my starting point:
myCommand [/options] | ((find "string1" && exit /b 2 || ver>nul) &&
(find "string2" && exit /b 3 || ver>nul) && (find "string3" && exit /b 4 || ver>nul))
For the same reasons above, I didn't use any flags on the "find" commands. Also, I used "ver>nul" in an attempt to keep the syntax correct since I know the "ver" operation succeeds.
Any assistance is appreciated.
I don't understand why you want to avoid use of a batch script. Your shortcut can simply point to a small batch script, and life will be much easier.
But it is possible to do what you want. The value of %errolevel% is determined during parsing, and the entire shortcut is parsed in one pass, so you get the value that existed prior to execution of your FIND commands. You need delayed expansion !errorlevel! to get your desired results.
In batch you use setlocal enableDelayedExpansion, but that does not work from the command line (or a shortcut). Instead you must instantiate an extra CMD.EXE with the /V:ON option.
netsh wlan show hostednetwork | cmd /v:on /c "find "Not" && echo found !errorlevel! || echo lost !errorlevel!"
There are multiple levels of quoting going on, and that can sometimes cause problems. You can eliminate the quotes enclosing the command if you escape the special characters.
netsh wlan show hostednetwork | cmd /v:on /c find "Not" ^&^& echo found !errorlevel! ^|^| echo lost !errorlevel!
Regarding your 2nd question, I see 2 problems.
1) I don't understand the point of having a shortcut designed to exit with different error codes. How can you possibly make use of the returned error code?
2) You cannot pipe content into multiple FIND commands. The first FIND command will consume all the content and close the pipe, and then subsequent FIND commands will wait indefinitely for content from the keyboard.
You would have to redirect your command output to a temp file, and then redirect input of each FIND command to the temp file.
You cannot evaluate a variable in the same line. It needs delayed expansion and !errorlevel! to be used.
Do it in a batch file and you won't have a problem using delayed expansion.