如何向PowerShell的[System.Diagnostics.Process]子进程发送按键(无需WinForms)
解决方案
优先方案:通过标准输入流发送回车(推荐)
既然你已经重定向了CLI程序的标准输出,最原生且无干扰的交互方式是同时重定向标准输入流,直接向程序输入回车,完全不需要模拟系统按键,也不会影响游戏或其他进程。
修改后的PowerShell代码
- 启动进程时开启标准输入重定向:
$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo $processStartInfo.FileName = "theCli.exe" $processStartInfo.RedirectStandardOutput = $true $processStartInfo.RedirectStandardInput = $true # 启用标准输入重定向 $processStartInfo.UseShellExecute = $false $process = [System.Diagnostics.Process]::Start($processStartInfo)
- 读取输出并匹配后发送回车:
# 用ReadLine()循环读取输出,避免ReadToEnd()阻塞到进程退出 while ($line = $process.StandardOutput.ReadLine()) { if ($line -match $pattern) { # WriteLine()会自动发送回车+换行(符合CLI程序的输入习惯) $process.StandardInput.WriteLine() # 若需单独发送回车键,可替换为: # $process.StandardInput.Write([char]13) break } }
这个方法是CLI程序交互的标准设计,可靠性最高,且完全不会干扰其他应用。
备选方案:通过Windows API发送窗口消息(仅当程序不读取标准输入时使用)
如果目标CLI程序不支持通过标准输入接收指令,必须通过按键消息触发,可注入C#类型调用Windows API发送按键消息,这种方式仅向目标进程的窗口发送消息,不会全局模拟按键,因此不会干扰游戏。
实现代码
# 注入C#代码调用Windows API Add-Type @" using System; using System.Runtime.InteropServices; public class KeySender { [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); public const uint WM_KEYDOWN = 0x0100; public const uint WM_KEYUP = 0x0101; public const int VK_RETURN = 0x0D; } "@ # 获取目标进程的控制台窗口句柄(仅当程序有控制台窗口时有效) $windowHandle = [KeySender]::FindWindow("ConsoleWindowClass", $process.MainWindowTitle) if ($windowHandle -ne [IntPtr]::Zero) { # 发送回车键的按下+释放消息 [KeySender]::PostMessage($windowHandle, [KeySender]::WM_KEYDOWN, [IntPtr][KeySender]::VK_RETURN, [IntPtr]0) [KeySender]::PostMessage($windowHandle, [KeySender]::WM_KEYUP, [IntPtr][KeySender]::VK_RETURN, [IntPtr]0) }
注意事项
- 仅当目标CLI程序有可见的控制台窗口时有效,完全无窗口的进程无法通过此方法发送消息;
- 若进程的窗口标题为空,可尝试通过进程ID查找窗口(需额外编写API调用逻辑)。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

