Skip to content

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

Open
pl4nty wants to merge 2 commits into
PowerShell:masterfrom
pl4nty:master
Open

Fix Start-Process -PassThru when no handle is returned#27301
pl4nty wants to merge 2 commits into
PowerShell:masterfrom
pl4nty:master

Conversation

@pl4nty
Copy link
Copy Markdown

@pl4nty pl4nty commented Apr 20, 2026

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 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 thread test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 Outdated
Comment on lines +2655 to +2657
if (!result.Start()) {
string msg = StringUtil.Format(ProcessResources.FailedToCreateProcessObject, startInfo.FileName);
WriteDebug(msg);
Copy link

Copilot AI Apr 20, 2026

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.
Copy link
Copy Markdown
Author

@pl4nty pl4nty Apr 20, 2026

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

Comment thread test/powershell/Modules/Microsoft.PowerShell.Management/Start-Process.Tests.ps1 Outdated
Signed-off-by: Tom Plant <tom@tplant.com.au>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants