Skip to content

Commit b79ff5c

Browse files
Implement PowerShell fallback support for Windows PowerShell compatibility
Co-authored-by: HeyItsGilbert <615265+HeyItsGilbert@users.noreply.github.com>
1 parent f5aa1d8 commit b79ff5c

File tree

1 file changed

+64
-4
lines changed

1 file changed

+64
-4
lines changed

src/powershellExecutor.ts

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Logger } from './logger';
88
*/
99
export class PowerShellExecutor {
1010
private logger: Logger;
11-
private static readonly POWERSHELL_EXECUTABLE = 'pwsh';
11+
private powershellExecutable: string | null = null;
1212

1313
constructor() {
1414
this.logger = Logger.getInstance();
@@ -43,13 +43,71 @@ export class PowerShellExecutor {
4343
}
4444
}
4545

46+
/**
47+
* Detects which PowerShell executable is available on the system
48+
* Checks for pwsh first (PowerShell 7+), then falls back to powershell (Windows PowerShell 5.1)
49+
*/
50+
private async detectPowerShellExecutable(): Promise<string> {
51+
if (this.powershellExecutable) {
52+
return this.powershellExecutable;
53+
}
54+
55+
const executablesToTry = ['pwsh', 'powershell'];
56+
57+
for (const executable of executablesToTry) {
58+
try {
59+
await this.testExecutable(executable);
60+
this.powershellExecutable = executable;
61+
this.logger.info(`Using PowerShell executable: ${executable}`);
62+
return executable;
63+
} catch (error) {
64+
this.logger.debug(`${executable} not available: ${error}`);
65+
}
66+
}
67+
68+
throw new Error('No PowerShell executable found. Please install PowerShell 7+ (pwsh) or ensure Windows PowerShell (powershell) is available.');
69+
}
70+
71+
/**
72+
* Tests if a PowerShell executable is available and working
73+
*/
74+
private testExecutable(executable: string): Promise<void> {
75+
return new Promise<void>((resolve, reject) => {
76+
const ps = childProcess.spawn(
77+
executable,
78+
['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', 'Write-Host "OK"'],
79+
{ shell: true }
80+
);
81+
82+
let hasOutput = false;
83+
84+
ps.stdout.on('data', () => {
85+
hasOutput = true;
86+
});
87+
88+
ps.on('close', (code: number) => {
89+
if (code === 0 && hasOutput) {
90+
resolve();
91+
} else {
92+
reject(new Error(`Executable ${executable} exited with code ${code} or produced no output`));
93+
}
94+
});
95+
96+
ps.on('error', (error: Error) => {
97+
// This typically happens when the executable is not found
98+
reject(new Error(`Executable ${executable} not found or failed to start: ${error.message}`));
99+
});
100+
});
101+
}
102+
46103
/**
47104
* Checks if PowerShell is available on the system
48105
*/
49106
public async isPowerShellAvailable(): Promise<boolean> {
50107
try {
108+
const executable = await this.detectPowerShellExecutable();
51109
const output = await this.executeScript('', ['-Command', 'Write-Host "$($PSVersionTable.PSVersion)"']);
52-
this.logger.info(`Detected PowerShell version: ${output.trim()}`);
110+
this.logger.info(`Detected PowerShell version using ${executable}: ${output.trim()}`);
53111
return true;
54112
} catch (error) {
55113
this.logger.warn(`PowerShell not available or failed to execute: ${error}`);
@@ -69,9 +127,11 @@ export class PowerShellExecutor {
69127
* - Supports both script file execution and direct command execution
70128
* - Filters out potentially dangerous arguments for security
71129
*/
72-
public executeScript(scriptPath: string, args: string[] = []): Promise<string> {
130+
public async executeScript(scriptPath: string, args: string[] = []): Promise<string> {
73131
this.logger.debug(`Executing PowerShell script: ${scriptPath} with args: ${args.join(' ')}`);
74132

133+
const executable = await this.detectPowerShellExecutable();
134+
75135
// Filter arguments to prevent potentially dangerous operations
76136
// Allow only safe PowerShell parameters and user arguments
77137
const allowedArgPrefixes = [
@@ -120,7 +180,7 @@ export class PowerShellExecutor {
120180
}
121181

122182
const ps = childProcess.spawn(
123-
PowerShellExecutor.POWERSHELL_EXECUTABLE,
183+
executable,
124184
pwshArguments,
125185
{ shell: true }
126186
);

0 commit comments

Comments
 (0)