You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向CreateProcess创建的PowerShell进程写入可执行命令

问题:通过C++创建PowerShell进程并执行传入命令

现有代码通过CreateProcess启动PowerShell窗口,尝试用cout输出命令并模拟回车,但PowerShell仅将内容显示为普通文本,不执行命令。原代码如下:

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
#include <string>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    char myCommand[] = "cmd /c powershell.exe -NoExit";

    CreateProcess(NULL,      // No module name (use command line)
                  myCommand, // Command line
                  NULL,      // Process handle not inheritable
                  NULL,      // Thread handle not inheritable
                  FALSE,     // Set handle inheritance to FALSE
                  0,         // No creation flags
                  NULL,      // Use parent's environment block
                  NULL,      // Use parent's starting directory
                  &si,       // Pointer to STARTUPINFO structure
                  &pi);      // Pointer to PROCESS_INFORMATION structure

    Sleep(5000);

    string strMytestString("ls");
    cout << strMytestString.c_str();

    Sleep(2000);

    // ENTER key down
    keybd_event(VK_RETURN, 0x9C, 0, 0);

    // ENTER key up
    keybd_event(VK_RETURN, 0x9C, KEYEVENTF_KEYUP, 0);
    return 0;
}

原代码问题在于:cout是向当前程序的控制台输出,而非PowerShell窗口;keybd_event是全局模拟按键,但PowerShell窗口未获得焦点,导致按键未生效到目标窗口。

以下是三种可行的解决方案:

方法一:直接通过PowerShell命令行参数执行命令

这是最简单的方式,启动PowerShell时直接通过-Command参数指定要执行的命令,结合-NoExit保持窗口不关闭。

修改CreateProcess的命令行参数:

char myCommand[] = "powershell.exe -NoExit -Command \"ls\"";

无需模拟输入,启动后PowerShell会直接执行ls命令并保留窗口。

方法二:激活PowerShell窗口后模拟输入

先找到PowerShell窗口句柄,将其置为前台,再用SendInput(替代过时的keybd_event)模拟字符输入和回车。

修改后的代码示例:

#include <cstdio>
#include <windows.h>
#include <string>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // 直接启动PowerShell,无需通过cmd中转
    char myCommand[] = "powershell.exe -NoExit";

    CreateProcess(NULL, myCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

    Sleep(2000); // 等待窗口创建完成

    // 查找PowerShell窗口(标题可能因版本不同变化,需根据实际调整)
    HWND psWindow = FindWindow(NULL, L"Windows PowerShell");
    if (psWindow == NULL) {
        cout << "无法找到PowerShell窗口" << endl;
        return 1;
    }

    // 将窗口置为前台,确保输入生效
    SetForegroundWindow(psWindow);
    Sleep(500); // 等待窗口激活

    // 准备要发送的输入内容:"ls" + 回车
    string cmd = "ls";
    INPUT input[2 * cmd.size() + 2];
    ZeroMemory(input, sizeof(input));

    int idx = 0;
    // 逐个发送字符的按下和释放事件
    for (char c : cmd) {
        input[idx].type = INPUT_KEYBOARD;
        input[idx].ki.wVk = 0;
        input[idx].ki.wScan = c;
        input[idx].ki.dwFlags = KEYEVENTF_UNICODE;
        idx++;

        input[idx].type = INPUT_KEYBOARD;
        input[idx].ki.wVk = 0;
        input[idx].ki.wScan = c;
        input[idx].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
        idx++;
    }

    // 发送回车按下事件
    input[idx].type = INPUT_KEYBOARD;
    input[idx].ki.wVk = VK_RETURN;
    idx++;

    // 发送回车释放事件
    input[idx].type = INPUT_KEYBOARD;
    input[idx].ki.wVk = VK_RETURN;
    input[idx].ki.dwFlags = KEYEVENTF_KEYUP;
    idx++;

    // 执行输入
    SendInput(idx, input, sizeof(INPUT));

    return 0;
}

方法三:通过标准输入管道写入命令

创建进程时重定向标准输入,通过管道向PowerShell发送命令,无需依赖窗口界面,可靠性更高。

代码示例:

#include <cstdio>
#include <windows.h>
#include <string>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HANDLE hStdinRead, hStdinWrite;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags |= STARTF_USESTDHANDLES;

    // 创建管道,用于向子进程发送标准输入
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&hStdinRead, &hStdinWrite, &saAttr, 0)) {
        cout << "创建管道失败" << endl;
        return 1;
    }

    // 设置子进程的标准输入为管道读端
    si.hStdInput = hStdinRead;

    // 启动PowerShell进程
    char myCommand[] = "powershell.exe -NoExit";
    if (!CreateProcess(NULL, myCommand, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
        cout << "创建进程失败" << endl;
        CloseHandle(hStdinRead);
        CloseHandle(hStdinWrite);
        return 1;
    }

    // 关闭父进程不需要的管道读端
    CloseHandle(hStdinRead);

    Sleep(2000); // 等待进程初始化完成

    // 向管道写入命令和换行(PowerShell需要换行触发执行)
    string cmd = "ls\n";
    DWORD bytesWritten;
    WriteFile(hStdinWrite, cmd.c_str(), cmd.size(), &bytesWritten, NULL);

    // 关闭管道写端,否则PowerShell可能不会立即处理输入
    CloseHandle(hStdinWrite);

    // 可选:等待进程结束
    // WaitForSingleObject(pi.hProcess, INFINITE);

    // 清理句柄
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

三种方法对比

  • 方法一:实现最简单,适合执行已知的单次命令,但无法后续动态输入。
  • 方法二:适合模拟用户交互场景,但依赖窗口标题和焦点,环境变化时可能失效。
  • 方法三:最可靠,不依赖GUI界面,适合后台执行或需要多次输入的场景。

内容的提问来源于stack exchange,提问作者p3ppi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 06:45:56