我正在尝试运行
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; }\"");
它似乎在我的纯CLR应用程序中工作正常,但是当我尝试在Win32应用程序中执行它时。我收到回复说
foreach-object{ is not recognized as a batch command
我不确定为什么管道会破坏一个字符串而不是另一个字符串,但我希望这可以在我的Win32应用程序中工作,所以我可以链接必要的DLL。
答案 0 :(得分:2)
正如documentation所述:
_popen 函数创建一个管道,并使用指定的字符串命令异步执行命令处理器的衍生副本。
因此,在这种情况下,您的Win32代码实际上是启动cmd.exe
的实例,然后将您的字符串传递给它。
|
对cmd.exe
有特殊意义。由于涉及将命令输入cmd.exe
所涉及的管道,它实际上最终将|
解释为command redirection operator(即使它在输入字符串中的引号内)。它从左侧的命令获取输出并将其发送到右侧命令的输入。因此,在您的情况下,您实际上是在尝试执行命令:
powershell.exe -Command "$computers = Get-WsusComputer -All; $computers
并将其输出发送到此命令的输入:
foreach-object{ Write-Output $_.FullDomainName; }"
这就是为什么你得到一个关于foreach-object{
是一个未知命令的错误。
要执行您尝试的操作,请尝试转义|
字符,以便在解析过程中将其视为普通字符:
exec("powershell.exe -Command \"$computers = Get-WsusComputer -All; $computers ^| foreach-object{ Write-Output $_.FullDomainName; }\"");
有关详细信息,请参阅此页:
Syntax : Escape Characters, Delimiters and Quotes
逃脱角色
^ Escape character.
在命令符号之前添加转义字符允许将其视为普通文本。 在管道或重定向任何这些字符时,您应该使用转义字符作为前缀:
& \ < > ^ |
e.g. ^\ ^& ^| ^> ^< ^^
或者,请考虑直接使用CreateProcess()
代替_popen()
。您可以使用命令字符串作为命令行参数而不是管道输入运行cmd.exe
,然后您不必转义引号内的|
字符(但您必须逃避额外的引用自己):
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()), ...);
要阅读输出,您可以告诉CreateProcess()
将已启动流程的STDOUT
句柄重定向到CreatePipe()
的匿名管道,然后您可以使用ReadFile()
从中读取:
Creating a Child Process with Redirected Input and Output
至于为什么一切都在CLR中正常工作,我不知道。我只能猜测CLR使用的命令处理器可能与cmd.exe
不同,而且它正在以不同的方式解析命令字符串。