Skip to content

Commit 37defc4

Browse files
Veykrilmikayla-maki
authored andcommitted
util: Check whether discovered powershell is actually executable (#43044)
Closes #42944 The powershell we discovered might be in a directory with higher permission requirements which will cause us to fail using it. Release Notes: - Fixed powershell discovery disregarding admin requirements
1 parent deb5373 commit 37defc4

File tree

3 files changed

+55
-36
lines changed

3 files changed

+55
-36
lines changed

crates/askpass/src/askpass.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ impl PasswordProxy {
250250
.await
251251
.with_context(|| format!("creating askpass script at {askpass_script_path:?}"))?;
252252
make_file_executable(&askpass_script_path).await?;
253+
// todo(shell): There might be no powershell on the system
253254
#[cfg(target_os = "windows")]
254255
let askpass_helper = format!(
255256
"powershell.exe -ExecutionPolicy Bypass -File {}",

crates/gpui/src/platform/windows/platform.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,12 @@ impl Platform for WindowsPlatform {
390390
clippy::disallowed_methods,
391391
reason = "We are restarting ourselves, using std command thus is fine"
392392
)]
393-
let restart_process = util::command::new_std_command("powershell.exe")
394-
.arg("-command")
395-
.arg(script)
396-
.spawn();
393+
// todo(shell): There might be no powershell on the system
394+
let restart_process =
395+
util::command::new_std_command(util::shell::get_windows_system_shell())
396+
.arg("-command")
397+
.arg(script)
398+
.spawn();
397399

398400
match restart_process {
399401
Ok(_) => self.quit(),

crates/util/src/shell.rs

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use schemars::JsonSchema;
22
use serde::{Deserialize, Serialize};
33
use std::{borrow::Cow, fmt, path::Path, sync::LazyLock};
44

5+
use crate::command::new_std_command;
6+
57
/// Shell configuration to open the terminal with.
68
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
79
#[serde(rename_all = "snake_case")]
@@ -108,16 +110,12 @@ pub fn get_windows_system_shell() -> String {
108110
use std::path::PathBuf;
109111

110112
fn find_pwsh_in_programfiles(find_alternate: bool, find_preview: bool) -> Option<PathBuf> {
111-
#[cfg(target_pointer_width = "64")]
112-
let env_var = if find_alternate {
113-
"ProgramFiles(x86)"
114-
} else {
115-
"ProgramFiles"
116-
};
117-
118-
#[cfg(target_pointer_width = "32")]
119113
let env_var = if find_alternate {
120-
"ProgramW6432"
114+
if cfg!(target_pointer_width = "64") {
115+
"ProgramFiles(x86)"
116+
} else {
117+
"ProgramW6432"
118+
}
121119
} else {
122120
"ProgramFiles"
123121
};
@@ -165,23 +163,19 @@ pub fn get_windows_system_shell() -> String {
165163
} else {
166164
"Microsoft.PowerShell_"
167165
};
168-
msix_app_dir
169-
.read_dir()
170-
.ok()?
171-
.filter_map(|entry| {
172-
let entry = entry.ok()?;
173-
if !matches!(entry.file_type(), Ok(ft) if ft.is_dir()) {
174-
return None;
175-
}
166+
msix_app_dir.read_dir().ok()?.find_map(|entry| {
167+
let entry = entry.ok()?;
168+
if !matches!(entry.file_type(), Ok(ft) if ft.is_dir()) {
169+
return None;
170+
}
176171

177-
if !entry.file_name().to_string_lossy().starts_with(prefix) {
178-
return None;
179-
}
172+
if !entry.file_name().to_string_lossy().starts_with(prefix) {
173+
return None;
174+
}
180175

181-
let exe_path = entry.path().join("pwsh.exe");
182-
exe_path.exists().then_some(exe_path)
183-
})
184-
.next()
176+
let exe_path = entry.path().join("pwsh.exe");
177+
exe_path.exists().then_some(exe_path)
178+
})
185179
}
186180

187181
fn find_pwsh_in_scoop() -> Option<PathBuf> {
@@ -190,15 +184,37 @@ pub fn get_windows_system_shell() -> String {
190184
pwsh_exe.exists().then_some(pwsh_exe)
191185
}
192186

187+
// check whether the found powershell is executable for us
193188
static SYSTEM_SHELL: LazyLock<String> = LazyLock::new(|| {
194-
find_pwsh_in_programfiles(false, false)
195-
.or_else(|| find_pwsh_in_programfiles(true, false))
196-
.or_else(|| find_pwsh_in_msix(false))
197-
.or_else(|| find_pwsh_in_programfiles(false, true))
198-
.or_else(|| find_pwsh_in_msix(true))
199-
.or_else(|| find_pwsh_in_programfiles(true, true))
200-
.or_else(find_pwsh_in_scoop)
201-
.map(|p| p.to_string_lossy().into_owned())
189+
let can_execute_pwsh = |p: &PathBuf| {
190+
#[allow(clippy::disallowed_methods)]
191+
let status = new_std_command(p).arg("-NoProfile").arg("-Help").status();
192+
let success = status.as_ref().is_ok_and(|status| status.success());
193+
if !success {
194+
log::warn!(
195+
"Powershell found at `{}` is not executable: {status:?}",
196+
p.display()
197+
);
198+
}
199+
success
200+
};
201+
202+
let locations = [
203+
|| find_pwsh_in_programfiles(false, false),
204+
|| find_pwsh_in_programfiles(true, false),
205+
|| find_pwsh_in_msix(false),
206+
|| find_pwsh_in_programfiles(false, true),
207+
|| find_pwsh_in_msix(true),
208+
|| find_pwsh_in_programfiles(true, true),
209+
|| find_pwsh_in_scoop(),
210+
|| which::which_global("pwsh.exe").ok(),
211+
|| which::which_global("powershell.exe").ok(),
212+
];
213+
locations
214+
.into_iter()
215+
.filter_map(|f| f())
216+
.find(|p| can_execute_pwsh(&p))
217+
.map(|p| p.to_string_lossy().trim().to_owned())
202218
.inspect(|shell| log::info!("Found powershell in: {}", shell))
203219
.unwrap_or_else(|| {
204220
log::warn!("Powershell not found, falling back to `cmd`");

0 commit comments

Comments
 (0)