Skip to content

Commit 22ddfbb

Browse files
committed
Merge branch 'feature/linux_support'
2 parents db9bbef + 74892e0 commit 22ddfbb

File tree

2 files changed

+153
-105
lines changed

2 files changed

+153
-105
lines changed

README.md

+88-86
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,88 @@
1-
# PowerShellLibJava
2-
3-
A simple library for using PowerShell from Java.
4-
5-
## Usage
6-
7-
`PowerShell.open()` opens a new PowerShell session. You can execute a PowerShell command with `psSession.executeCommands(command)`. It will return the output of the command as a string:
8-
```java
9-
try (PowerShell psSession = PowerShell.open()) {
10-
System.out.println(psSession.executeCommands("Write-Output 'hello Java'"));
11-
} catch (IOException | PowerShellExecutionException ex) {
12-
ex.printStackTrace();
13-
}
14-
```
15-
```
16-
hello Java
17-
```
18-
19-
---
20-
21-
You can also execute multiple lines of commands at once:
22-
```java
23-
try (PowerShell psSession = PowerShell.open()) {
24-
System.out.println(psSession.executeCommands(
25-
"for ($i = 1; $i -le 5; $i++) {",
26-
" Write-Output $i",
27-
"}"));
28-
} catch (IOException | PowerShellExecutionException ex) {
29-
ex.printStackTrace();
30-
}
31-
```
32-
```
33-
1
34-
2
35-
3
36-
4
37-
5
38-
```
39-
40-
---
41-
42-
If your PowerShell code has parameters that are dynamically read from Java strings, they might contain characters that have special meaning in PowerShell (kind of like SQL injection). You can sanitize your input with `PowerShell.escapePowerShellString(parameter)`:
43-
```java
44-
String param = "thi's won't bre;ak' the' code";
45-
46-
try (PowerShell psSession = PowerShell.open()) {
47-
System.out.println(psSession.executeCommands("Write-Output " + PowerShell.escapePowerShellString(param)));
48-
} catch (IOException | PowerShellExecutionException ex) {
49-
ex.printStackTrace();
50-
}
51-
```
52-
```
53-
thi's won't bre;ak' the' code
54-
```
55-
56-
---
57-
58-
If there is an error on executing the command, a `PowerShellExecutionException` is thrown:
59-
```java
60-
try (PowerShell psSession = PowerShell.open()) {
61-
System.out.println(psSession.executeCommands("this is not a valid command"));
62-
} catch (IOException | PowerShellExecutionException ex) {
63-
ex.printStackTrace();
64-
}
65-
```
66-
```
67-
tuupertunut.powershelllibjava.PowerShellExecutionException: Error while executing PowerShell commands:
68-
this : The term 'this' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
69-
...
70-
```
71-
72-
## Requirements
73-
74-
You must have PowerShell installed on your machine.
75-
76-
**OS:** Windows is the only currently supported OS. This library has not been tested on Linux, but it might work.
77-
78-
**Java:** Java 8 or higher is required.
79-
80-
## Maven Central
81-
82-
[![https://mvnrepository.com/artifact/com.github.tuupertunut/powershell-lib-java](https://img.shields.io/maven-central/v/com.github.tuupertunut/powershell-lib-java.svg?style=for-the-badge)](https://mvnrepository.com/artifact/com.github.tuupertunut/powershell-lib-java)
83-
84-
**groupId:** com.github.tuupertunut
85-
86-
**artifactId:** powershell-lib-java
1+
# PowerShellLibJava
2+
3+
A simple library for using PowerShell from Java.
4+
5+
## Usage
6+
7+
`PowerShell.open()` opens a new PowerShell session with default executable. On Windows it is `powershell`, and on other platforms it is `pwsh` from PowerShell Core. You can also specify a custom PowerShell executable, for example `PowerShell.open("/usr/bin/pwsh-preview")`.
8+
9+
You can execute a PowerShell command with `psSession.executeCommands(command)`. It will return the output of the command as a string:
10+
```java
11+
try (PowerShell psSession = PowerShell.open()) {
12+
System.out.println(psSession.executeCommands("Write-Output 'hello Java'"));
13+
} catch (IOException | PowerShellExecutionException ex) {
14+
ex.printStackTrace();
15+
}
16+
```
17+
```
18+
hello Java
19+
```
20+
21+
---
22+
23+
You can also execute multiple lines of commands at once:
24+
```java
25+
try (PowerShell psSession = PowerShell.open()) {
26+
System.out.println(psSession.executeCommands(
27+
"for ($i = 1; $i -le 5; $i++) {",
28+
" Write-Output $i",
29+
"}"));
30+
} catch (IOException | PowerShellExecutionException ex) {
31+
ex.printStackTrace();
32+
}
33+
```
34+
```
35+
1
36+
2
37+
3
38+
4
39+
5
40+
```
41+
42+
---
43+
44+
If your PowerShell code has parameters that are dynamically read from Java strings, they might contain characters that have special meaning in PowerShell (kind of like SQL injection). You can sanitize your input with `PowerShell.escapePowerShellString(parameter)`:
45+
```java
46+
String param = "thi's won't bre;ak' the' code";
47+
48+
try (PowerShell psSession = PowerShell.open()) {
49+
System.out.println(psSession.executeCommands("Write-Output " + PowerShell.escapePowerShellString(param)));
50+
} catch (IOException | PowerShellExecutionException ex) {
51+
ex.printStackTrace();
52+
}
53+
```
54+
```
55+
thi's won't bre;ak' the' code
56+
```
57+
58+
---
59+
60+
If there is an error on executing the command, a `PowerShellExecutionException` is thrown:
61+
```java
62+
try (PowerShell psSession = PowerShell.open()) {
63+
System.out.println(psSession.executeCommands("this is not a valid command"));
64+
} catch (IOException | PowerShellExecutionException ex) {
65+
ex.printStackTrace();
66+
}
67+
```
68+
```
69+
tuupertunut.powershelllibjava.PowerShellExecutionException: Error while executing PowerShell commands:
70+
this : The term 'this' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
71+
...
72+
```
73+
74+
## Requirements
75+
76+
**OS:** Works on every platform that has PowerShell available.
77+
78+
**PowerShell:** On Windows 7 and newer, Windows PowerShell is installed by default and this library should work with it out of the box. On other platforms, you need to have PowerShell Core (https://github.com/PowerShell/PowerShell) installed.
79+
80+
**Java:** Java 8 or higher is required.
81+
82+
## Maven Central
83+
84+
[![https://mvnrepository.com/artifact/com.github.tuupertunut/powershell-lib-java](https://img.shields.io/maven-central/v/com.github.tuupertunut/powershell-lib-java.svg?style=for-the-badge)](https://mvnrepository.com/artifact/com.github.tuupertunut/powershell-lib-java)
85+
86+
**groupId:** com.github.tuupertunut
87+
88+
**artifactId:** powershell-lib-java

src/main/java/com/github/tuupertunut/powershelllibjava/PowerShell.java

+65-19
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,17 @@
3737

3838
/**
3939
* PowerShell session that can be used to execute PowerShell commands. An
40-
* instance of this class can be created with {@link #open()}. Instances should
41-
* always be closed with {@link #close()} to free resources.
40+
* instance of this class can be created with {@link #open()} or
41+
* {@link #open(java.lang.String)}. Instances should always be closed with
42+
* {@link #close()} to free resources.
4243
*
4344
* @author Tuupertunut
4445
*/
4546
public class PowerShell implements Closeable {
4647

48+
private static final String DEFAULT_WIN_EXECUTABLE = "powershell";
49+
private static final String DEFAULT_CORE_EXECUTABLE = "pwsh";
50+
4751
/* This string marks the end of command output. It should be as unique as
4852
* possible. This library assumes that the string never occurs as a
4953
* substring in any powershell command output. If that happens, behavior is
@@ -60,22 +64,9 @@ public class PowerShell implements Closeable {
6064

6165
private boolean closed;
6266

63-
private PowerShell() throws IOException {
67+
private PowerShell(String psExecutable) throws IOException {
6468

65-
/* cmd /c chcp 65001 : Set console codepage to UTF-8, so that input and
66-
* output streams of the console will be interpreted as UTF-8.
67-
*
68-
* > NUL : Discard any output from the codepage change command.
69-
*
70-
* & powershell : If codepage change was successful, start powershell.
71-
*
72-
* -ExecutionPolicy Bypass : Disable any prompts about unsigned scripts,
73-
* because there is no way to answer prompts.
74-
*
75-
* -NoExit : Keep the session open after executing the first command.
76-
*
77-
* -Command - : Read commands from standard input stream of the process. */
78-
psSession = new ProcessBuilder("cmd", "/c", "chcp", "65001", ">", "NUL", "&", "powershell", "-ExecutionPolicy", "Bypass", "-NoExit", "-Command", "-").start();
69+
psSession = createProcessBuilder(psExecutable).start();
7970

8071
commandOutput = new BufferedReader(new InputStreamReader(psSession.getInputStream(), StandardCharsets.UTF_8));
8172
commandErrorOutput = new BufferedReader(new InputStreamReader(psSession.getErrorStream(), StandardCharsets.UTF_8));
@@ -91,14 +82,69 @@ private PowerShell() throws IOException {
9182
closed = false;
9283
}
9384

85+
private static ProcessBuilder createProcessBuilder(String psExecutable) {
86+
87+
/* Windows needs some extra configuration to understand UTF-8. */
88+
if (isWindows()) {
89+
90+
/* cmd /c chcp 65001 : Set console codepage to UTF-8, so that input
91+
* and output streams of the console will be interpreted as UTF-8.
92+
*
93+
* > NUL : Discard any output from the codepage change command.
94+
*
95+
* & *psExecutable* : If codepage change was successful, start
96+
* powershell.
97+
*
98+
* -ExecutionPolicy Bypass : Disable any prompts about unsigned
99+
* scripts, because there is no way to answer prompts.
100+
*
101+
* -NoExit : Keep the session open after executing the first
102+
* command.
103+
*
104+
* -Command - : Read commands from standard input stream of the
105+
* process. */
106+
return new ProcessBuilder("cmd", "/c", "chcp", "65001", ">", "NUL", "&", psExecutable, "-ExecutionPolicy", "Bypass", "-NoExit", "-Command", "-");
107+
} else {
108+
return new ProcessBuilder(psExecutable, "-ExecutionPolicy", "Bypass", "-NoExit", "-Command", "-");
109+
}
110+
}
111+
112+
/* Apache commons says this is a valid way to detect Windows.
113+
* https://github.com/apache/commons-lang/blob/LANG_3_7/src/main/java/org/apache/commons/lang3/SystemUtils.java */
114+
private static boolean isWindows() {
115+
return System.getProperty("os.name").startsWith("Windows");
116+
}
117+
118+
private static String getDefaultExecutable() {
119+
if (isWindows()) {
120+
return DEFAULT_WIN_EXECUTABLE;
121+
} else {
122+
return DEFAULT_CORE_EXECUTABLE;
123+
}
124+
}
125+
94126
/**
95-
* Opens a new PowerShell session.
127+
* Opens a new PowerShell session with default executable. On Windows, the
128+
* default executable is "powershell" from Windows PowerShell, and on other
129+
* platforms it is "pwsh" from PowerShell Core.
96130
*
97131
* @return a new PowerShell session.
98132
* @throws IOException if an IOException occurred on process creation.
99133
*/
100134
public static PowerShell open() throws IOException {
101-
return new PowerShell();
135+
return new PowerShell(getDefaultExecutable());
136+
}
137+
138+
/**
139+
* Opens a new PowerShell session with the provided executable.
140+
*
141+
* @param customExecutable the PowerShell executable. Can be an executable
142+
* name like "pwsh" or a path to the executable file.
143+
* @return a new PowerShell session.
144+
* @throws IOException if an IOException occurred on process creation.
145+
*/
146+
public static PowerShell open(String customExecutable) throws IOException {
147+
return new PowerShell(customExecutable);
102148
}
103149

104150
/**

0 commit comments

Comments
 (0)