Skip to content

Fix Start-Process -PassThru when no handle is returned - #27301

Open
Tom Plant (pl4nty) wants to merge 2 commits into
PowerShell:masterfrom
pl4nty:master
Open

Tom Plant (pl4nty) wants to merge 2 commits into
PowerShell:masterfrom
pl4nty:master

Conversation

@pl4nty

@pl4nty Tom Plant (pl4nty) commented Apr 20, 2026 •

Copy link
Copy Markdown

PR Summary

PR Context

Start-Process -PassThru throw an exception when Process.Start(info) returns null, but this is expected in some cases. It confuses users when the process starts, but an exception is thrown (see #10996). The error message (CannotStarttheProcess) is also a bit ambiguous: This command cannot be run completely because the system cannot find all the information required.

I'm proposing a debug message instead of an exception, like the one used when a process is started as a different user and we can't retrieve the handle. Then returning a Process object with just StartInfo. If methods are called like $process.Kill(), a slightly more meaningful exception (NoAssociatedProcess) is thrown: No process is associated with this object. The null properties like Name might be confusing though.

These changes also impact -Wait - it would throw NoAssociatedProcess instead of CannotStarttheProcess.

I'm not sure if this is a breaking change, are exceptions considered an API contract? It would break code like this:

$target = "ms-settings:"
$name = "SystemSettings"
$process = $null
try {
  $process = Start-Process $target -PassThru
} catch {
  $process = Get-Process $name
}
$process.Kill()

Alternatively, we could use a more descriptive exception than CannotStarttheProcess? Perhaps a format string that mentions -PassThru or -Wait.

PR Checklist

Copilot AI review requested due to automatic review settings April 20, 2026 01:54
@pl4nty
Tom Plant (pl4nty) requested a review from a team as a code owner April 20, 2026 01:54
Signed-off-by: Tom Plant <tom@tplant.com.au>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts Start-Process behavior on Windows Desktop when UseShellExecute starts a target that doesn’t yield a process handle (e.g., ms-settings:), to avoid throwing in -PassThru scenarios and align with expected ShellExecute behavior.

Changes:

  • Update StartWithShellExecute to always return a Process instance and emit a debug message instead of relying on Process.Start(ProcessStartInfo) returning non-null.
  • Add a Pester test covering Start-Process ms-settings: -PassThru on full Windows.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs Changes ShellExecute startup path to return a Process object and write a debug message when a handle isn’t available.
test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 Adds a Windows-only test invoking Start-Process ms-settings: -PassThru.

Comment on lines +2655 to +2657
if (!result.Start()) {
string msg = StringUtil.Format(ProcessResources.FailedToCreateProcessObject, startInfo.FileName);
WriteDebug(msg);

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FailedToCreateProcessObject is worded for a handle-retrieval failure and expects the reason in {0} (it’s used elsewhere with e.Message), but here {0} is startInfo.FileName, which will produce a misleading debug message. Also, the message references a Process object being output even when -PassThru isn't set; consider emitting this debug message only when PassThru (and/or Wait) is present and supply a reason that matches the resource string.

Suggested change
if (!result.Start()) {
string msg = StringUtil.Format(ProcessResources.FailedToCreateProcessObject, startInfo.FileName);
WriteDebug(msg);
if (!result.Start())
{
if (PassThru || Wait)
{
string msg = StringUtil.Format(ProcessResources.FailedToCreateProcessObject, "Process.Start returned false.");
WriteDebug(msg);
}

Copilot uses AI. Check for mistakes.

@pl4nty Tom Plant (pl4nty) Apr 20, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about this, but I reckon I'd like maintainer feedback on the overall approach before adding strings. May make more sense to just modify CannotStarttheProcess

Signed-off-by: Tom Plant <tom@tplant.com.au>
@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days.
Maintainer, please provide feedback and/or mark it as Waiting on Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review - Needed The PR is being reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants