Skip to content

Commit dba7d83

Browse files
Fix update powershell feature on windows (#2325)
* fix update powershell feature on windows * PR feedback
1 parent adb18ea commit dba7d83

File tree

4 files changed

+56
-34
lines changed

4 files changed

+56
-34
lines changed

src/features/UpdatePowerShell.ts

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5+
import { spawn } from "child_process";
6+
import * as fs from "fs";
57
import fetch, { RequestInit } from "node-fetch";
8+
import * as os from "os";
9+
import * as path from "path";
610
import * as semver from "semver";
7-
import { MessageItem, window } from "vscode";
11+
import * as stream from "stream";
12+
import * as util from "util";
13+
import { MessageItem, ProgressLocation, window } from "vscode";
814
import { LanguageClient } from "vscode-languageclient";
15+
import { SessionManager } from "../session";
916
import * as Settings from "../settings";
17+
import { isMacOS, isWindows } from "../utils";
1018
import { EvaluateRequestType } from "./Console";
1119

20+
const streamPipeline = util.promisify(stream.pipeline);
21+
1222
const PowerShellGitHubReleasesUrl =
1323
"https://api.github.com/repos/PowerShell/PowerShell/releases/latest";
1424
const PowerShellGitHubPrereleasesUrl =
@@ -67,6 +77,7 @@ interface IUpdateMessageItem extends MessageItem {
6777
}
6878

6979
export async function InvokePowerShellUpdateCheck(
80+
sessionManager: SessionManager,
7081
languageServerClient: LanguageClient,
7182
localVersion: semver.SemVer,
7283
arch: string,
@@ -103,7 +114,6 @@ export async function InvokePowerShellUpdateCheck(
103114
return;
104115
}
105116

106-
const isMacOS: boolean = process.platform === "darwin";
107117
const result = await window.showInformationMessage(
108118
`${commonText} Would you like to update the version? ${
109119
isMacOS ? "(Homebrew is required on macOS)" : ""
@@ -116,39 +126,50 @@ export async function InvokePowerShellUpdateCheck(
116126
switch (result.id) {
117127
// Yes choice.
118128
case 0:
119-
let script: string;
120-
if (process.platform === "win32") {
129+
if (isWindows) {
121130
const msiMatcher = arch === "x86" ?
122131
"win-x86.msi" : "win-x64.msi";
123132

124-
const assetUrl = release.assets.filter((asset: any) =>
125-
asset.name.indexOf(msiMatcher) >= 0)[0].browser_download_url;
126-
127-
// Grab MSI and run it.
128-
// tslint:disable-next-line: max-line-length
129-
script = `
130-
$randomFileName = [System.IO.Path]::GetRandomFileName()
131-
$tmpMsiPath = Microsoft.PowerShell.Management\\Join-Path ([System.IO.Path]::GetTempPath()) "$randomFileName.msi"
132-
Microsoft.PowerShell.Utility\\Invoke-RestMethod -Uri ${assetUrl} -OutFile $tmpMsiPath
133-
try
134-
{
135-
Microsoft.PowerShell.Management\\Start-Process -Wait -Path $tmpMsiPath
136-
}
137-
finally
138-
{
139-
Microsoft.PowerShell.Management\\Remove-Item $tmpMsiPath
140-
}`;
133+
const asset = release.assets.filter((a: any) => a.name.indexOf(msiMatcher) >= 0)[0];
134+
const msiDownloadPath = path.join(os.tmpdir(), asset.name);
141135

142-
} else if (isMacOS) {
143-
script = "brew cask upgrade powershell";
144-
if (release.isPreview) {
145-
script = "brew cask upgrade powershell-preview";
136+
const res = await fetch(asset.browser_download_url);
137+
if (!res.ok) {
138+
throw new Error("unable to fetch MSI");
146139
}
140+
141+
await window.withProgress({
142+
title: "Downloading PowerShell Installer...",
143+
location: ProgressLocation.Notification,
144+
cancellable: false,
145+
},
146+
async () => {
147+
// Streams the body of the request to a file.
148+
await streamPipeline(res.body, fs.createWriteStream(msiDownloadPath));
149+
});
150+
151+
// Stop the Integrated Console session because Windows likes to hold on to files.
152+
sessionManager.stop();
153+
154+
// Invoke the MSI via cmd.
155+
const msi = spawn("msiexec", ["/i", msiDownloadPath]);
156+
157+
msi.on("close", (code) => {
158+
// Now that the MSI is finished, start the Integrated Console session.
159+
sessionManager.start();
160+
fs.unlinkSync(msiDownloadPath);
161+
});
162+
163+
} else if (isMacOS) {
164+
const script = release.isPreview
165+
? "brew cask upgrade powershell-preview"
166+
: "brew cask upgrade powershell";
167+
168+
await languageServerClient.sendRequest(EvaluateRequestType, {
169+
expression: script,
170+
});
147171
}
148172

149-
await languageServerClient.sendRequest(EvaluateRequestType, {
150-
expression: script,
151-
});
152173
break;
153174

154175
// Never choice.

src/process.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ export class PowerShellProcess {
6969
];
7070

7171
// Only add ExecutionPolicy param on Windows
72-
if (utils.isWindowsOS()) {
72+
if (utils.isWindows) {
7373
powerShellArgs.push("-ExecutionPolicy", "Bypass");
7474
}
7575

7676
const startEditorServices = "& '" +
7777
PowerShellProcess.escapeSingleQuotes(startScriptPath) +
7878
"' " + this.startArgs;
7979

80-
if (utils.isWindowsOS()) {
80+
if (utils.isWindows) {
8181
powerShellArgs.push(
8282
"-Command",
8383
startEditorServices);

src/session.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ export class SessionManager implements Middleware {
546546
await GitHubReleaseInformation.FetchLatestRelease(isPreRelease);
547547

548548
await InvokePowerShellUpdateCheck(
549+
this,
549550
this.languageServerClient,
550551
localVersion,
551552
this.versionDetails.architecture,

src/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import fs = require("fs");
88
import os = require("os");
99
import path = require("path");
1010

11-
export let PowerShellLanguageId = "powershell";
11+
export const PowerShellLanguageId = "powershell";
1212

1313
export function ensurePathExists(targetPath: string) {
1414
// Ensure that the path exists
@@ -116,6 +116,6 @@ export function getTimestampString() {
116116
return `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}]`;
117117
}
118118

119-
export function isWindowsOS(): boolean {
120-
return os.platform() === "win32";
121-
}
119+
export const isMacOS: boolean = process.platform === "darwin";
120+
export const isWindows: boolean = process.platform === "win32";
121+
export const isLinux: boolean = !isMacOS && !isWindows;

0 commit comments

Comments
 (0)