【发布时间】:2019-08-22 05:25:41
【问题描述】:
我正在为一个 powershell 客户端编写一个实现。这个实现是在java中。 JVM 在 UNIX 系统上运行。我需要能够创建一个对象PowerShellClient 并让它生成一个打开powershell 并允许我访问其stdin、stdout 和stderr 的进程,以便我可以在所述powershell 会话中调用命令并观察它们的输出。
我已经尝试过jpowershell,这个实现效果很好,但有一个限制:如果您尝试调用多次写入输出的cmdlet,则不会获得所有输出,并且不会完全读取输出。好像在第一个Write-Output之后就终止了
PowerShell pwsh = PowerShell.openSession();
String out = pwsh.executeCommand(
"for($i=0; $i -lt 10; $i++){Write-Output $i; Start-Sleep -Seconds 1}")
.getCommandOutput();
System.out.println(out);
产生以下内容:
0
所以。我自己实现了一些东西,我决定以这样的方式实现它,它会等待提示 >>> 出现在 STDOUT 中。只有看到提示时才会停止读取,并允许执行另一个命令。但是,我已经有一个问题: 在标准输出中甚至看不到输出 powershell 对象的 cmdlet 输出。这是一些代码
import java.io.*;
import java.util.concurrent.Semaphore;
public class PowerShellClient {
private PrintWriter stdin;
private BufferedReader stderr;
private BufferedReader stdout;
private Process powerShellProcess;
private Thread readErrThread;
private Thread readOutThread;
public PowerShellClient() throws IOException {
powerShellProcess = new ProcessBuilder("powershell", "-nol", "-noe").start();
stdout = new BufferedReader(
new InputStreamReader(powerShellProcess.getInputStream()));
stderr = new BufferedReader(
new InputStreamReader(powerShellProcess.getErrorStream()));
stdin = new PrintWriter(
new OutputStreamWriter(
new BufferedOutputStream(
powerShellProcess.getOutputStream())),
true);
readOutThread = new Thread(() -> {
String line;
try {
while ((line = stdout.readLine()) != null)
System.out.println("[STDOUT]: " + line);
} catch (IOException e) {
e.printStackTrace();
}
});
readErrThread = new Thread(() -> {
String line;
try {
while(null != (line = stderr.readLine()))
System.out.println("[STDERR]: " + line);
} catch (IOException e) {
e.printStackTrace();
}
});
readErrThread.start();
readOutThread.start();
}
public void executeCommand(String aRawCmd) {
stdin.println(aRawCmd);
}
}
以及用例:
PowerShellClient client = new PowerShellClient();
client.executeCommand("Get-Process");
产生以下内容:
[STDOUT]: >>> Get-Process
[STDOUT]:
[STDOUT]:
虽然这个用例:
PowerShellClient client = new PowerShellClient();
client.executeCommand("for($i=0; $i -lt 10; $i++) { Write-Output $i; Start-Sleep 1}");
产生以下内容:
[STDOUT]: >>> for($i=0; $i -lt 10; $i++) { Write-Output $i; Start-Sleep 1}
[STDOUT]: 0
[STDOUT]: 1
[STDOUT]: 2
[STDOUT]: 3
[STDOUT]: 4
[STDOUT]: 5
[STDOUT]: 6
[STDOUT]: 7
[STDOUT]: 8
[STDOUT]: 9
我的问题是这样的:
为什么会这样?是什么导致无法从通常产生 10 行输出的 cmdlet 中观察到输出?我认为这与 cmdlet 的输出被传递到 powershell 对象引擎这一事实有关,该引擎以某种方式确定终端的大小并格式化输出。我已经尝试过管道到Out-String、Write-Out 和Write-Host。我什至尝试将输出重定向到一个文件,然后cating 该文件。没有雪茄,文件没有内容(除了一个新的\n)。
我是否缺少一些配置或什么?
UNIX系统上安装的powershell版本: PowerShell 6.2.2
【问题讨论】:
-
如果你想让 powershell 使用与 Java 相同的控制台,请使用
processBuilder.inheritIO(true),并且不要在 Java 中处理这 3 个流。 -
你为什么要这样做? java 和 linux 上的 powershell 听起来很糟糕。
-
用于自动化目的。我需要远程进入 Windows 机器以执行来自 Linux 环境的命令,来自 java 中的应用程序
-
通过管道发送到
Out-String是否有效? -
不,这也不起作用。但是我能够解决问题。它在其他环境中不容易重现,解决方案是重新安装一些依赖项
标签: java powershell