c++ createprocess powershell as admin, hidden and dont wait for it - c++

This is what I have, starting powershell.exe without the command and closing directly after it.
why doesnt it work?
int main(int argc, char *argv[])
{
[...]
CreateProcess( NULL, // No module name (use command line)
"powershell.exe -command \".C:\\test\\t.ps1\" ",
[...]
&si, // Pointer to STARTUPINFO structure
&pi ); // Pointer to PROCESS_INFORMATION structure
return 0;
}
in normal cmd the command would look like this:
powershell -command ".c:\test\t.ps1"
and in the file this one-liner, if you want to test it:
write-host "hello world" |out-file C:\test\hi.txt
should write hello world in the console and create hi.txt in the folder

The command line should be either:
CreateProcess(NULL, // No module name (use command line)
"powershell.exe -command \"& {C:\\test\\t.ps1}\"",
or
CreateProcess(NULL, // No module name (use command line)
"powershell.exe -file C:\\test\\t.ps1",
In general, for executing scripts use -File unless the exit code is important to you. If it is, use -Command because there is a bug with -File where it always returns 0 (success) even if there is an error.
If you want the execution of powershell.exe to prompt for elevation, use the ShellExecute API instead. Pass in "RunAs" for lpOperation and you can specify a hidden window with the nShowCmd parameter.

Related

failing to execute a shell command in windows using WindowsAPI

I am trying to execute a ping command in windows via their ShellExecute function.
ShellExecute(0, L"open", L"cmd.exe", normToWide(command).c_str(), 0, SW_HIDE);
This is how i call the Function.
to get the wide string i use this function
std::wstring normToWide(std::string str)
{
std::wstring str2(str.length(), L' ');
std::copy(str.begin(), str.end(), str2.begin());
return str2;
}
the command is this:
ping 127.9 -l 4 -n 300 > output.txt
Although the ip is invalid it should not matter as output.txt should still be populated with some sort of error message at hte least. What is going on with my function?
I expected there to be a output.txt file with the output of the command
I also tried hardcoding my command to make sure it was not a widestr issue
The problem is ping is not a built in command in cmd.exe and it will not automatically execute the command you pass to it, thus ping even if it is installed and in the command path will not be executed. To fix this you have two choices.
The first is to prefix the command string with the /C option which "Carries out the command specified by string and then terminates" like so
/C ping 127.9 -l 4 -n 300 > output.txt
This will force cmd.exe to execute ping if it is in installed and in the command path.
The second is just as easy - just specify ping.exe as the command for ShellExecute to execute instead of cmd.exe.
ShellExecute(0, L"open", L"ping.exe", normToWide(command).c_str(), 0, SW_HIDE);
If you want to execute ping.exe and capture the output it produces, it'll be much cleaner to use something on this order:
FILE *f = _popen("ping 127.9 -l 4 -n 300");
char buffer[256];
while (fgets(buffer, sizeof(buffer), f) {
// `buffer` contains a line of output from `ping`
}
ShellExecute(NULL,NULL,L"cmd.exe", L"/K ping 127.9 -l 4 -n 300 > d://test.txt",NULL, SW_SHOWNORMAL);
/k: end cmd window does not disappear
/c: end cmd window disappear

Running powershell script through the system command - output creates a file that is empty

I am attempting to run a powershell script through the system command.
This is the code I am using
status = system("start powershell.exe Set-ExecutionPolicy RemoteSigned \n");
status = system("start powershell.exe D:\\foo\\tempFilePShellCommand.ps1 > D:\\foo\\MyFile.txt");
Now the problem with the above code is that MyFile.txt gets created but its empty.
If I run the file through powershell the file gets created and contains the correct data.
Any suggestions on why the file is empty and how I can fix this /
You need to specify that the parameter is a file. Otherwise, it is treated as a parameter to "PowerShell.exe" instead of a file you want to run using PowerShell.
status = system("start powershell.exe -File D:\\foo\\tempFilePShellCommand.ps1 > D:\\foo\\MyFile.txt");

Creating a command prompt process that opens at a chosen directory

Need help here, I'm trying to create a process in c++ with the windows api, whats happening is the process is being created which is cmd.exe however I want cmd.exe to open cd'd at a certain directory i.e. root c:\, however the process is opened at the dir of the executable.
I tried passing in "cd \" as the second argument of the CreateProcess function to no avail
Here's a snippet of the code:
TCHAR program[] = TEXT("C:/Windows/System32/cmd.exe");
TCHAR command[] = TEXT("cd /");
STARTUPINFO info;
PROCESS_INFORMATION processInfo;
ZeroMemory(&info,sizeof(STARTUPINFO));
ZeroMemory(&processInfo,sizeof(PROCESS_INFORMATION));
BOOL processResult =
CreateProcess(program,
command, NULL, NULL,
TRUE, CREATE_NEW_CONSOLE,
NULL, NULL,
&info,
&processInfo);
if(!processResult){
std::cerr << "CreateProcess() failed to start program \""
<< program << "\"\n";
exit(1);
}
std::cout << "Started program \""
<< program << "\" successfully\n";
Help would be extremely appreciated!
Thanks
If you want the cd / (or any other command) to have any effect, you need to use either the /k or /c flags for the command prompt. You can look these switches up in the documentation for cmd.exe, but basically, /c runs the command and then terminates, while /k runs the command and keeps the console session open. You almost certainly want /k here.
But really, you should be specifying the directory as the working directory for the process, not executing a change-directory command.
You can do this easily by calling the ShellExecute function, as Raw N suggested. The working directory is one of its parameters. ShellExecute (or ShellExecuteEx) is easier to use than CreateProcess, and should be preferred unless you need some special low-level behavior that you can only get with CreateProcess.
This works with CreateProcess too: pass the path as the lpCurrentDirectory parameter.
Whatever you do, don't hard-code paths! Use the %comspec% environment variable on Windows NT. It would also work to just execute cmd, letting the default search paths do their job.

viewing output of system() call in C++

How can I view the output of a system command. Ex:
int _tmain(int argc, _TCHAR* argv[]) {
system("set PATH=%PATH%;C:/Program Files (x86)/myFolder/bin");
system("cd C:/thisfolder/");
std::cin.get();
return 0;
}
when I run the program in Visual Studio it give me a black screen and I cannot see the command being run. I need it so I can view whether it worked or not. Thanks!
Use popen instead of system. See example here https://msdn.microsoft.com/en-us/library/96ayss4b.aspx
char psBuffer[128];
FILE *pPipe;
if( (pPipe = _popen( "set PATH=%PATH%;C:/Program Files (x86)/myFolder/bin", "rt" )) == NULL )
exit( 1 );
then
while(fgets(psBuffer, 128, pPipe)) {
printf(psBuffer);
}
if (feof( pPipe))
printf( "\nProcess returned %d\n", _pclose( pPipe ) );
The output of a system call should show up on stdout.
I do not think those commands generally have any output to display if they are successful. Try adding a dir or pwd after to list the directory you are in.
If you want to get the output from the commands into the program for processing that is another issue. You will have to use os specific api, or maybe redirect the output into a file you can read.
Try adding pause as below to wait after each command. On failure, error message will be displayed. On success, actual output from the command, if any, will be displayed.
system("set PATH=%PATH%;C:/Program Files (x86)/myFolder/bin & pause");
system("cd C:/thisfolder/ & pause");
Note that each call to system uses cmd.exe( as cmd /c [command] ) to execute your command and env variables like PATH in one command won't effect another.
cmd.exe /c set PATH=%PATH%;C:/Program Files (x86)/myFolder/bin
cmd.exe /c cd C:/thisfolder/

Why child process returns exit status = 32512 in unix?

In my program I'm executing given command and getting result (log, and exit status). Also my program have to support shell specific commands (i.e. commands which contains shell specific characters ~(tild),|(pipe),*). But when I try to run sh -c ls | wc in my home directory via my program it failed and its exit status was 32512, also in stderr stream "sh: ls | wc: command not found" was printed.
But the interesting thing is that the command sh -c ls | wc works correct if I run it in shell.
What is the problem? Or more preferable how can I run shell specific commands via my program (i.ec which command with which parameters should I run)?
The code part bellow is in child part after fork(). It executs the command.
tokenized_command is std::vector<std::string> where in my case "sh", "-c", "ls", "|", "wc" are stored, also I have tried to store there "sh", "-c", "\"ls | wc\"" but result is same. command is char * where full command line is stored.
boost::shared_array<const char *> bargv(new const char *[tokenized_command.size() + 1]);
const char **argv = bargv.get();
for(int i = 0; i < tokenized_command.size(); ++i)
{
argv[i] = tokenized_command[i].c_str();
printf("argv[%d]: %s\n", i, argv[i]); //trace
}
argv[tokenized_command.size()] = NULL;
if(execvp(argv[0], (char * const *)argv) == -1)
{
fprintf(stderr, "Failed to execute command %s: %s", command, strerror(errno));
_exit(EXIT_FAILURE);
}
P.S.
I know that using system(command) instead execvp can solve my problem. But system() waits until command is finished, and this is not good enough for my program. And also I'm sure that in implementation of system() one of exec-family functions is used, so the problem can be solved via exec as well, but I don't know how.
execvp takes a path to an executable, and arguments with which to launch that executable. It doesn't take bourne shell commands.
ls | wc is a bourne shell command (among others), and it can't be broken down into the path to an executable and some arguments due to the use of a pipe. This means it can't be executed using execvp.
To execute a bourne shell command using execvp, one has to execute sh and pass -c and the command for arguments.
So you want to execute ls | wc using execvp.
char *const argv[] = {
"sh",
"-c", "ls | wc", // Command to execute.
NULL
};
execvp(argv[0], argv)
You apparently tried
char *const argv[] = {
"sh",
"-c", "ls", // Command to execute.
"|", // Stored in called sh's $0.
"wc", // Stored in called sh's $1.
NULL
};
That would be the same as bourne shell command sh -c ls '|' wc.
And both are very different than shell command sh -c ls | wc. That would be
char *const argv[] = {
"sh",
"-c", "sh -c ls | wc", // Command to execute.
NULL
};
You seem to think | and wc are passed to the sh, but that's not the case at all. | is a special character which results in a pipe, not an argument.
As for the exit code,
Bits 15-8 = Exit code.
Bit 7 = 1 if a core dump was produced.
Bits 6-0 = Signal number that killed the process.
32512 = 0x7F00
So it didn't die from a signal, a core dump wasn't produced, and it exited with code 127 (0x7F).
What 127 means is unclear, which is why it should accompanied by an error message. You tried to execute program ls | wc, but there is no such program.
You should execute sh -c 'ls | wc'.
Option -c expects a command in form of string. In shell of course it is working, because there is no difference between spawning ls and redirecting output to wc and launching ls | wc in separate shell.