mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
The Windows extraction step relied on `powershell -Command Expand-Archive`,
which fails when:
- Microsoft.PowerShell.Archive (a script module) cannot be loaded due to
PSModulePath shadowing (Store-installed pwsh injecting WindowsApps
paths) or ExecutionPolicy Restricted (issue #603), or
- the temp directory contains characters that corrupt PowerShell string
parsing (e.g. a single quote in TEMP).
Switch to a two-tier extraction:
1. Primary: Add-Type System.IO.Compression.FileSystem +
[ZipFile]::ExtractToDirectory. Bypasses the PowerShell module system
entirely. .NET 4.5+, available on Win 8 / Server 2012 by default and
widely on Win 7 SP1.
2. Fallback: Expand-Archive -LiteralPath, kept for the rare host without
.NET 4.5 but with PS 5.0+ (e.g. Win 7 SP1 with WMF 5).
Both paths pass file paths through env vars ($env:LARK_CLI_ARCHIVE /
$env:LARK_CLI_DEST) so quoting / wildcard chars in the path can no longer
break command parsing. -LiteralPath ensures Expand-Archive treats the value
literally rather than as a wildcard pattern. $ErrorActionPreference='Stop'
makes non-terminating cmdlet errors propagate as non-zero exit codes.
Also drop `stdio: "ignore"` so the actual PowerShell error surfaces in the
postinstall log when both paths fail, instead of leaving users with
"Command failed: powershell ..." with no detail.
Verified on Windows 10 + PS 5.1:
- Reproduced #603 with shadow Microsoft.PowerShell.Archive +
Restricted ExecutionPolicy: original install.js fails, patched
install.js succeeds.
- Reproduced single-quote-in-TEMP path corruption: original fails,
patched succeeds.
- Fallback path verified end-to-end with primary forced to fail.
- Normal-environment install: no regression.
This commit is contained in:
@@ -125,6 +125,37 @@ function download(url, destPath) {
|
||||
execFileSync("curl", args, { stdio: ["ignore", "ignore", "pipe"] });
|
||||
}
|
||||
|
||||
function extractZipWindows(archivePath, destDir) {
|
||||
const psOpts = ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"];
|
||||
const psStdio = ["ignore", "inherit", "inherit"];
|
||||
const psEnv = {
|
||||
...process.env,
|
||||
LARK_CLI_ARCHIVE: archivePath,
|
||||
LARK_CLI_DEST: destDir,
|
||||
};
|
||||
|
||||
try {
|
||||
const dotnet =
|
||||
"$ErrorActionPreference='Stop';" +
|
||||
"Add-Type -AssemblyName System.IO.Compression.FileSystem;" +
|
||||
"[System.IO.Compression.ZipFile]::ExtractToDirectory($env:LARK_CLI_ARCHIVE,$env:LARK_CLI_DEST)";
|
||||
execFileSync("powershell.exe", [...psOpts, dotnet], { stdio: psStdio, env: psEnv });
|
||||
} catch (primaryErr) {
|
||||
try {
|
||||
const cmdlet =
|
||||
"$ErrorActionPreference='Stop';" +
|
||||
"Expand-Archive -LiteralPath $env:LARK_CLI_ARCHIVE -DestinationPath $env:LARK_CLI_DEST -Force";
|
||||
execFileSync("powershell.exe", [...psOpts, cmdlet], { stdio: psStdio, env: psEnv });
|
||||
} catch (fallbackErr) {
|
||||
throw new Error(
|
||||
`Failed to extract ${archivePath}. ` +
|
||||
`.NET ZipFile attempt: ${primaryErr.message}. ` +
|
||||
`Expand-Archive fallback: ${fallbackErr.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function install() {
|
||||
const mirrorUrls = getMirrorUrls(process.env);
|
||||
const downloadUrls = [GITHUB_URL, ...mirrorUrls];
|
||||
@@ -156,10 +187,7 @@ function install() {
|
||||
verifyChecksum(archivePath, expectedHash);
|
||||
|
||||
if (isWindows) {
|
||||
execFileSync("powershell", [
|
||||
"-Command",
|
||||
`Expand-Archive -Path '${archivePath}' -DestinationPath '${tmpDir}'`,
|
||||
], { stdio: "ignore" });
|
||||
extractZipWindows(archivePath, tmpDir);
|
||||
} else {
|
||||
execFileSync("tar", ["-xzf", archivePath, "-C", tmpDir], {
|
||||
stdio: "ignore",
|
||||
|
||||
Reference in New Issue
Block a user