Java中如何委託執行 PowerShell 代碼
遇到的情形是PowerShell中有現成的函式庫可以用Java中似乎沒有,不想自己實現直接套過去用的話可以暫時先這樣擋著。
廢話不多說直接上代碼
package com.excucmd;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class App {
public static void main(String[] args) {
System.out.println("Hello executeCommand!");
int exitCode = -1;
// 執行 PowerShell 測試1
String program = "PowerShell";
String[] params = {"-nop", "(Get-Date); 1..3 | ForEach-Object { Write-Host Counting down: $_; Start-Sleep -Seconds 1 }; 0/0"};
exitCode = executeCommand(program, params);
System.out.println("Exit code: " + exitCode);
// 執行 PowerShell 測試2
String[] params2 = {"powershell", "-nop", "Write-Error 'Pwsh:: throw a Exception' -EA 1; Write-Host Pwsh:: After the Exception"};
try {
exitCode = executeCommand2(params2);
} catch (Exception e) { e.printStackTrace(); }
System.out.println("Exit code: " + exitCode);
}
/**
* 執行指定的命令並返回結果
*
* @param program 要執行的程序名稱,例如 "powershell"
* @param params 可變參數,傳遞給程序的參數
* 例如,對於 PowerShell 命令,可以是 "-nop", "您的 PowerShell 命令"
* @return 程序執行後的退出碼。通常,0 表示正常結束,非0 表示有錯誤發生
*
* @throws IllegalArgumentException 如果程序名稱為空或 null,或者參數為空或 null。
*/
private static int executeCommand(String program, String... params) {
// 檢查參數
if (program == null || program.trim().isEmpty()) {
throw new IllegalArgumentException("Program cannot be null or empty.");
}
if (params == null || params.length == 0) {
throw new IllegalArgumentException("Arguments cannot be null or empty.");
}
// 設定基本參數
int exitCode = -1;
final String encoding = "BIG5"; /* [UTF-8, Shift_JIS, BIG5] */
final String workDir = System.getProperty("user.dir"); /* 獲取Java當前工作路徑 */
// 構建輸入參數
List<String> commandList = new ArrayList<>();
commandList.add(program);
Collections.addAll(commandList, params);
// 構建處理程序
ProcessBuilder processBuilder = new ProcessBuilder(commandList);
processBuilder.environment().remove("PSModulePath");
processBuilder.directory(new File(workDir));
try {
// 執行命令
Process process = processBuilder.start();
// 處理輸出流
try (
BufferedReader stdoutReader = new BufferedReader(
new InputStreamReader(process.getInputStream(), encoding));
BufferedReader stderrReader = new BufferedReader(
new InputStreamReader(process.getErrorStream(), encoding));
) {
String line;
// 讀取標準輸出流
while ((line = stdoutReader.readLine()) != null) {
System.out.println(line);
}
// 讀取錯誤輸出流
while ((line = stderrReader.readLine()) != null) {
final String ANSI_RESET = "\u001B[0m";
final String ANSI_RED = "\u001B[31m";
System.out.println(ANSI_RED + line + ANSI_RESET);
}
}
// 獲取錯誤代碼
exitCode = process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
return exitCode;
}
/**
* 執行指定的命令並返回結果
* 這是一個簡化版本的方法,將錯誤輸出重定向至標準輸出,只用一個進程監控打印的內容
*
* @param command 命令和其參數,作為可變長度參數傳入。例如:"cmd.exe", "/c", "dir"
* @return 命令執行後的退出碼。通常,0 表示正常結束,非0 表示有錯誤發生。
* @throws Exception 如果退出碼非0,則拋出異常。
*/
private static int executeCommand2(String... command)
throws Exception
{
int exitCode = -1;
final String encoding = "BIG5"; /* [UTF-8, Shift_JIS, BIG5] */
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // 將錯誤輸出重定向至標準輸出
try { // 啟動進程
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), encoding))) {
String line;// 使用 BufferedReader 逐行讀取進程的輸出並打印到控制台
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
exitCode = process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
// 退出代碼不為零則拋出例外
if (exitCode != 0) {
throw new Exception("PowerShell command execution failed with exit code " + exitCode);
}
return exitCode;
}
}
這裡面解決的一個問題是 PowerShell 被這樣委託執行貌似會出錯PS環境變數的問題,解決辦法就是清空他自己會重新讀取
這個問題我記得我在別的情況下也遇過,具體錯誤大概會長這樣子
ConvertTo-SecureString : 已在模組 'Microsoft.PowerShell.Security' 上找到 'ConvertTo-SecureString'
命令,但無法載入該模組。如需詳細資訊,請執行 'Import-Module Microsoft.PowerShell.Security'。
位於 線路:1 字元:22
+ Get-ExecutionPolicy; ConvertTo-SecureString $password -AsPlainText -F ...
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (ConvertTo-SecureString:String) [], CommandNotFoundE
xception
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
寫得很不清不楚就是了,總的來說就是很多內建的函式變得不可使用,但明明就有找到模組
沒有留言:
張貼留言