Skip to content

Commit 55566fe

Browse files
committed
Migrate from wmic to PowerShell scripting
WMIC is deprecated and no longer exists on many modern Windows machines. This replaces it with widely compatible (Windows 7 SP1 or Windows 8) PowerShell commands that should work equivalently.
1 parent 267db19 commit 55566fe

File tree

2 files changed

+48
-40
lines changed

2 files changed

+48
-40
lines changed

src/interceptors/fresh-firefox.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { isSnap, getSnapConfigPath } from '../util/snap';
1212

1313
import { launchBrowser, BrowserInstance, getBrowserDetails } from '../browsers';
1414
import { readFile, canAccess, deleteFolder } from '../util/fs';
15-
import { windowsKill, spawnToResult } from '../util/process-management';
15+
import { spawnToResult, windowsKillByCliMatch } from '../util/process-management';
1616
import { MessageServer } from '../message-server';
1717
import { CertCheckServer } from '../cert-check-server';
1818
import { Interceptor } from '.';
@@ -180,7 +180,7 @@ abstract class Firefox implements Interceptor {
180180
if (process.platform === "win32") {
181181
// Firefox spawns a child process on Windows, and doesn't let us kill it at all.
182182
// To fix this, we kill all firefox instances that were started with this exact same URL.
183-
await windowsKill(`CommandLine Like '%\\\\firefox.exe%${initialUrl}'`).catch(console.log);
183+
await windowsKillByCliMatch(`*\\firefox.exe*${initialUrl}`).catch(console.log);
184184
} else {
185185
normalStop();
186186
}

src/util/process-management.ts

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,18 @@ export function spawnToResult(command: string, args: string[] = [], options = {}
3636
});
3737
};
3838

39+
export function spawnPowerShellToResult(command: string) {
40+
return spawnToResult('powershell.exe', [
41+
'-NoProfile', '-NonInteractive',
42+
'-Command', command
43+
]);
44+
}
45+
3946
type Proc = {
4047
pid: number,
41-
command: string,
42-
bin: string | undefined,
43-
args: string | undefined
48+
command: string, // Process name (often short binary name)
49+
bin: string | undefined, // Full path to the binary, if available
50+
args: string | undefined // Arguments as a single string, if available
4451
};
4552

4653
const getOutputLines = (stdout: string) =>
@@ -122,36 +129,38 @@ export async function listRunningProcesses(): Promise<Array<Proc>> {
122129

123130
return processes;
124131
} else {
125-
const wmicOutput = await spawnToResult('wmic', [
126-
'Process', 'Get', 'processid,commandline'
127-
]);
132+
const pshResult = await spawnPowerShellToResult(
133+
'Get-CimInstance Win32_Process | ' +
134+
'ForEach-Object { "$($_.ProcessId)|$($_.Name)|$($_.CommandLine)|$($_.ExecutablePath)" }'
135+
);
128136

129-
if (wmicOutput.exitCode !== 0) {
130-
throw new Error(`WMIC exited with unexpected error code ${wmicOutput.exitCode}`);
137+
if (pshResult.exitCode !== 0) {
138+
throw new Error(`PowerShell process query exited with unexpected error code ${pshResult.exitCode}`);
131139
}
132140

133-
return getOutputLines(wmicOutput.stdout)
134-
.slice(1) // Skip the header line
135-
.filter((line) => line.includes(' ')) // Skip lines where the command line isn't available (just pids)
136-
.map((line) => {
137-
const pidIndex = line.lastIndexOf(' ') + 1;
138-
const pid = parseInt(line.substring(pidIndex), 10);
139-
140-
const command = line.substring(0, pidIndex).trim();
141-
const bin = command[0] === '"'
142-
? command.substring(1, command.substring(1).indexOf('"') + 1)
143-
: command.substring(0, command.indexOf(' '));
144-
const args = command[0] === '"'
145-
? command.substring(bin.length + 3)
146-
: command.substring(bin.length + 1);
147-
148-
return {
149-
pid,
150-
command,
151-
bin,
152-
args
153-
};
154-
});
141+
return getOutputLines(pshResult.stdout)
142+
.map(line => {
143+
const [pid, command, commandLine, bin] = line.split('|');
144+
145+
let args: string | undefined;
146+
if (commandLine.startsWith('"')) {
147+
// Command line might start with full path or bare binary name:
148+
if (commandLine.startsWith(`"${bin}"`)) {
149+
args = commandLine.substring(bin.length + 3);
150+
} else if (commandLine.startsWith(`"${command}"`)) {
151+
args = commandLine.substring(command.length + 3);
152+
}
153+
// There's probably other possibilities, but it's not critical enough that we
154+
// need to bother trying to be much smarter here.
155+
} else {
156+
const firstSpace = commandLine.indexOf(' ');
157+
if (firstSpace !== -1) {
158+
args = commandLine.substring(firstSpace + 1);
159+
}
160+
}
161+
162+
return { pid: parseInt(pid, 10), command, bin, args } as Proc;
163+
});
155164
}
156165
}
157166

@@ -183,12 +192,11 @@ export async function windowsClose(pid: number) {
183192
]);
184193
}
185194

186-
// Harshly kill a windows process by some WMIC matching string e.g.
187-
// "processId=..." or "CommandLine Like '%...%'"
188-
export async function windowsKill(processMatcher: string) {
189-
await spawnToResult('wmic', [
190-
'Path', 'win32_process',
191-
'Where', processMatcher,
192-
'Call', 'Terminate'
193-
], { }, true);
195+
// Harshly kill a windows process by command-line match:
196+
export async function windowsKillByCliMatch(globMatcher: string) {
197+
await spawnPowerShellToResult(
198+
'Get-CimInstance Win32_Process | ' +
199+
`Where-Object { $_.CommandLine -like "${globMatcher}" } | ` +
200+
'ForEach-Object { $_.Terminate() }'
201+
);
194202
}

0 commit comments

Comments
 (0)