Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6269,6 +6269,7 @@ version = "0.0.0"
dependencies = [
"guid",
"jiff",
"tracing",
]

[[package]]
Expand Down
16 changes: 14 additions & 2 deletions petri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,27 @@ pub enum CommandError {
Command(std::process::ExitStatus, String),
}

/// Run a command on the host and return the output
/// Run a command on the host and return the output.
pub async fn run_host_cmd(mut cmd: Command) -> Result<String, CommandError> {
cmd.stderr(Stdio::piped()).stdin(Stdio::null());

let cmd_debug = format!("{cmd:?}");
::tracing::debug!(cmd = cmd_debug, "executing command");

let start = Timestamp::now();
let output = blocking::unblock(move || cmd.output()).await?;
let output = blocking::unblock(move || {
// Retry on the WPS 5.1 EventLog AV crash. For non-PowerShell
// commands the signature never matches, so this is a no-op.
#[cfg(windows)]
{
powershell_builder::output_with_av_retry(&mut cmd)
}
Comment thread
smalis-msft marked this conversation as resolved.
Outdated
#[cfg(not(windows))]
{
cmd.output()
}
})
.await?;
let time_elapsed = Timestamp::now() - start;

let stdout_str = String::from_utf8_lossy(&output.stdout).to_string();
Expand Down
1 change: 1 addition & 0 deletions support/powershell_builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ rust-version.workspace = true
[target.'cfg(windows)'.dependencies]
guid.workspace = true
jiff.workspace = true
tracing.workspace = true

[lints]
workspace = true
36 changes: 36 additions & 0 deletions support/powershell_builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,42 @@ use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;

/// Run a PowerShell `Command` and return its output, retrying on the
/// well-known transient Windows PowerShell 5.1 startup crash (exit code
/// `0xDEAD` with an `AccessViolationException` thrown from
/// `EventLogLogProvider` during session initialization).
Comment thread
smalis-msft marked this conversation as resolved.
Outdated
///
/// The crash happens in `InitialSessionState.Bind_LoadProviders` *before*
/// the user's command is dispatched, so retrying is idempotent. Up to 2
/// retries (3 total attempts) are made.
///
/// Each call to [`Command::output`] spawns a fresh process, so the same
/// `Command` value can be reused across attempts.
pub fn output_with_av_retry(cmd: &mut Command) -> std::io::Result<Output> {
Comment thread
smalis-msft marked this conversation as resolved.
Outdated
const MAX_RETRIES: u32 = 2;
let mut attempt = 0u32;
loop {
let output = cmd.output()?;
let is_wps_eventlog_av =
!output.status.success() && output.status.code() == Some(0xDEAD) && {
let stderr = String::from_utf8_lossy(&output.stderr);
stderr.contains("System.AccessViolationException")
&& stderr.contains("EventLogLogProvider")
};
if is_wps_eventlog_av && attempt < MAX_RETRIES {
attempt += 1;
tracing::warn!(
cmd = ?cmd,
Comment thread
smalis-msft marked this conversation as resolved.
Outdated
attempt,
"retrying command after Windows PowerShell EventLog AV crash"
);
continue;
}
return Ok(output);
}
}

/// A PowerShell script builder
pub struct PowerShellBuilder(Command);
Expand Down
Loading