使用JSch在远程Windows系统执行PowerShell命令的问题
解决JSch连接Win32-OpenSSH时PowerShell交互问题
我明白你遇到的棘手问题了——用JSch的exec通道启动PowerShell会直接退出,shell通道默认进入CMD环境,没法直接和PowerShell的流交互执行后续命令。下面给你两种针对性的解决方案,分别对应一次性命令执行和交互式会话场景:
方案1:用exec通道直接执行PowerShell命令(非交互式)
如果你的需求是一次性执行单条或多条PowerShell命令,不需要后续交互,这种方式最简单直接。核心思路是让PowerShell通过-Command参数直接执行指定命令,执行完成后返回输出再退出,不需要保持会话。
修改你的代码如下:
private Streams executePowershell(Session session, String powershellCommand) throws JSchException, IOException { Channel channel = session.openChannel("exec"); // 直接通过PowerShell参数传递要执行的命令 ((ChannelExec) channel).setCommand("powershell -Command \"" + powershellCommand + "\""); ((ChannelExec) channel).setErrStream(System.err); channel.connect(); InputStream in = channel.getInputStream(); OutputStream out = channel.getOutputStream(); Streams streams = new Streams(); streams.setInputStream(in); streams.setOutputStream(out); streams.setChannel(channel); return streams; } // 调用时直接传入PowerShell命令,比如"dir" public String executeCommand(String powershellCommand) { String output = null; try { Session session = getSession(); Streams streams = executePowershell(session, powershellCommand); output = Util.readStream(streams.getInputStream()).toString(); streams.getChannel().disconnect(); session.disconnect(); } catch (Exception e) { e.printStackTrace(); } return output; }
方案2:用shell通道进入PowerShell并保持交互
如果需要在同一个PowerShell会话中执行多条命令,就得用shell通道,先切换到PowerShell环境,再处理命令输入和输出。这里的关键是要识别PowerShell的提示符(默认是PS C:\> 这类格式),确保在PowerShell准备好之后再发送命令。
修改代码如下:
private Streams startInteractivePowershell(Session session) throws JSchException, IOException { ChannelShell channel = (ChannelShell) session.openChannel("shell"); channel.setErrStream(System.err); // 必须启用PTY,确保Win32-OpenSSH正确处理交互式会话 channel.setPty(true); channel.connect(); InputStream in = channel.getInputStream(); OutputStream out = channel.getOutputStream(); Streams streams = new Streams(); streams.setInputStream(in); streams.setOutputStream(out); streams.setChannel(channel); // 发送powershell命令进入PowerShell环境,等待提示符确认 Util.writeToStream(out, "powershell\n"); StringBuffer buffer = new StringBuffer(); int read; // 读取输出直到出现PowerShell特征提示符,确认环境切换完成 while ((read = in.read()) != -1) { char c = (char) read; buffer.append(c); // 根据实际环境调整判断条件,比如可能是"PS C:\Users\XXX> " if (buffer.toString().endsWith("PS ")) { break; } } return streams; } // 可传入多条命令依次执行 public String executeInteractiveCommands(String... commands) { String output = null; try { Session session = getSession(); Streams streams = startInteractivePowershell(session); InputStream in = streams.getInputStream(); OutputStream out = streams.getOutputStream(); StringBuffer totalOutput = new StringBuffer(); for (String cmd : commands) { // 发送命令时必须加换行,PowerShell才会执行 Util.writeToStream(out, cmd + "\n"); // 读取命令输出直到下一个PowerShell提示符出现 StringBuffer cmdOutput = new StringBuffer(); int read; while ((read = in.read()) != -1) { char c = (char) read; cmdOutput.append(c); if (cmdOutput.toString().endsWith("PS ")) { break; } } totalOutput.append(cmdOutput); } // 退出PowerShell并断开会话 Util.writeToStream(out, "exit\n"); output = totalOutput.toString(); streams.getChannel().disconnect(); session.disconnect(); } catch (Exception e) { e.printStackTrace(); } return output; }
关键注意事项:
- 启用PTY:
channel.setPty(true)是必须的,否则Win32-OpenSSH无法正确识别交互式会话。 - 提示符匹配:不同用户的PowerShell提示符可能有差异,需要根据实际环境调整判断逻辑,避免提前终止读取。
- 命令换行:发送命令时一定要加
\n,否则PowerShell会认为命令未输入完成,不会执行。
为什么你的原代码会失效?
你的原代码用exec通道启动powershell,但exec通道的进程没有绑定交互输入源,PowerShell启动后发现没有输入就会直接退出,所以后续写入command2时,已经没有进程接收命令了,自然得不到输出。而shell通道默认启动的是Windows CMD,所以你看到的是CMD的系统信息,需要手动发送powershell命令切换环境并等待提示符确认。
内容的提问来源于stack exchange,提问作者Ankit Jain
相关产品推荐
相关产品推荐

