简体   繁体   中英

Code works in CLR project but not Win32

I am trying to run

std::string exec(const char* cmd) {
    std::shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while (!feof(pipe.get())) {
         if (fgets(buffer, 128, pipe.get()) != NULL)
            result += buffer;
    }
    return result;
}

string domainNameList = exec("powershell.exe -Command \"$computers = Get-WsusComputer -All; $computers | foreach-object{ Write-Output $_.FullDomainName; }\"");

It seems to work fine in my pure CLR application but when I try to do it in a Win32 Application. I get a response saying that

foreach-object{ is not recognized as a batch command

I am not sure why the pipe is breaking the string in one but not the other but I would like for this to work in my Win32 application so I can link necessary DLLs.

As the documentation states:

The _popen function creates a pipe and asynchronously executes a spawned copy of the command processor with the specified string command .

So, in this case, your Win32 code is actually launching an instance of cmd.exe and then piping your string to it.

| has special meaning to cmd.exe . Because piping is involved to get the command into cmd.exe , it actually ends up interpreting the | as a command redirection operator (even though it is inside of quotes in your input string). It takes the output from the command on the left side and sends it to the input of the command on the right side. So, in your case, you are actually trying to execute the command:

powershell.exe -Command "$computers = Get-WsusComputer -All; $computers

and send its output to the input of this command:

foreach-object{ Write-Output $_.FullDomainName; }"

And that is why you get an error about foreach-object{ being an unknown command.

To do what you are attempting, try escaping the | character so it is treated as a normal character during parsing:

exec("powershell.exe -Command \"$computers = Get-WsusComputer -All; $computers ^| foreach-object{ Write-Output $_.FullDomainName; }\"");

See this page for more details:

Syntax : Escape Characters, Delimiters and Quotes

Escape Character

 ^ Escape character. 

Adding the escape character before a command symbol allows it to be treated as ordinary text. When piping or redirecting any of these characters you should prefix with the escape character: & \\ < > ^ |

  eg ^\\ ^& ^| ^> ^< ^^ 

Alternatively, consider using CreateProcess() directly instead of _popen() . You can run cmd.exe with your command string as a command-line parameter instead of piped input, then you don't have to escape the | character inside of quotations (but you would have to escape the extra quotes themselves):

std::basic_string<TCHAR> cmd = TEXT("cmd.exe /C \"powershell.exe -Command \"\"$computers = Get-WsusComputer -All; $computers | foreach-object{ Write-Output $_.FullDomainName; }\"\"\"");
CreateProcess(NULL, const_cast<TCHAR*>(cmd.c_str()), ...);

To read the output, you can tell CreateProcess() to redirect the launched process's STDOUT handle to an anonymous pipe from CreatePipe() and then you can read from it using ReadFile() :

Creating a Child Process with Redirected Input and Output

As to why everything works correctly in CLR, I do not know. I can only surmise that maybe CLR is using a different command processor than cmd.exe , and it is parsing your command string differently.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM