Skip to content

Conversation

@SteveL-MSFT
Copy link
Member

@SteveL-MSFT SteveL-MSFT commented Oct 6, 2020

PR Summary

Change #13481 modified some logic on how console apps are detected. The problem in this situation is:

  1. user starts diskmgmt.msc
  2. check if exe, this is not an exe so set _isWindowsApplication = false
  3. check if associated with an exe
  4. finds mmc.exe
  5. check if exe, this is an exe, so launch this with previous "command" as the argument
  6. check _isWindowsApplication to determine if we block waiting for exe to finish, since this value was cached and not updated on step 5, it treats as console exe and waits

Fix is to change CheckIfConsoleApplication() to be non-static so that the second time it's called it updates _isWindowsApplication to point to the new exe and not the previous file.

Tested manually. Since CI won't have a Windows app associated with a file, can't create a test case.

PR Context

Fix #13744

PR Checklist

@SteveL-MSFT SteveL-MSFT requested a review from iSazonov October 6, 2020 02:00
@SteveL-MSFT SteveL-MSFT added this to the 7.1-Consider milestone Oct 6, 2020
@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

@SteveL-MSFT I think we should simply revert a change in line 557
from
_isRunningInBackground = IsWindowsApplication;
to
_isRunningInBackground = IsWindowsApplication(_nativeProcess.StartInfo.FileName);

As for test, you could see last test in Invoke-Item.Tests,ps1 file:
Describe "Invoke-Item tests on Windows" -Tags "CI","RequireAdminOnWindows" {

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Oct 6, 2020
@SteveL-MSFT
Copy link
Member Author

@iSazonov the problem is if anyone updates the code and uses CheckIfConsoleApplication() it will have a similar problem as IsWindowsApplication doesn't get updated if we just do the change you are suggesting.

As for the test, it appears the hang only occurs if the associated process explicitly supports elevation like mmc.exe. I can add a test that runs if diskmgmt.msc and mmc.exe are on the system, otherwise it'll be skipped. At least it can work locally.

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

the problem is if anyone updates the code and uses CheckIfConsoleApplication() it will have a similar problem as IsWindowsApplication doesn't get updated if we just do the change you are suggesting.

My thoughts is that switching to mmc.exe is temporary and we should follow diskmgmt.msc. Otherwise it will very tricky code - input is diskmgmt.msc but result is for mmc.exe.
And I'd remove IsWindowsApplication and IsConsoleApplication because they is used once.

@SteveL-MSFT
Copy link
Member Author

@iSazonov but diskmgmt.msc is not the process so following it doesn't make sense unless I'm misunderstanding. Removing IsWindowsApplication and IsConsoleApplication makes sense.

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

If we remove IsWindowsApplication we remove _isWindowsApplication and this resolves our discussion (til we will want to make IsWindowsApplication public :-) )

_startPosition = new Host.Coordinates();

CalculateIORedirection(out redirectOutput, out redirectError, out redirectInput);
bool isWindowsApplication = IsWindowsApplication(this.Path);
Copy link
Collaborator

Choose a reason for hiding this comment

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

These names are so similar that it can be confused. Can we keep the old name for the method?

Copy link
Member Author

Choose a reason for hiding this comment

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

The old name with the Check makes it slightly harder to understand reading the code as it's not as clear what true/false means with Check vs Is. The alternative is to have the local variable be isConsoleApplication to differentiate I guess.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could use bool windowsApplication without Bulgarian prefix.
If no I agreed with isWindowsApplication.

Copy link
Member Author

Choose a reason for hiding this comment

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

Since this code currently is only used in one place, I think the casing diff is ok and prefer the is making it a bit more readable

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

As unrelated notice. The code fallback to default shell (cmd.exe/bash) to invoke an item. But what if we assign PowerShell as default shell? Infinite cycle?
It seems we need to review all places where we fallback to default shell to understand the consequences.

@SteveL-MSFT
Copy link
Member Author

@iSazonov can you point me to what code you are referring to?

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

In the context - line 488. If UseShellExecute is true we call PowerShell again?

@SteveL-MSFT
Copy link
Member Author

@iSazonov that line with UseShellExecute only starts a new process if the previous attempt fails because it's not an executable and isn't associated with an executable so it tries to let the Shell try to start it. I don't see the problem.

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

I mean the code

lock (_sync)
{
if (_stopped)
{
throw new PipelineStoppedException();
}
try
{
_nativeProcess = new Process() { StartInfo = startInfo };
_nativeProcess.Start();
}
catch (Win32Exception)

If PowerShell is default shell the code will run PowerShell again and again.

@SteveL-MSFT
Copy link
Member Author

@iSazonov ok, now I see what you mean. However, on my macBook I can see that Process.Start() doesn't start a new shell to run the exe.

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 6, 2020

I'd expect the cycle with:

  1. Set PowerShell as default shell
  2. Run PowerShell unelevated
  3. Run diskmgmt.msc

In line 534 we will have UseShellExecute = true and run PowerShell again.

@SteveL-MSFT
Copy link
Member Author

@iSazonov perhaps you can open a new issue to discuss that specific concern, I don't see additional pwsh processes, however

@iSazonov
Copy link
Collaborator

iSazonov commented Oct 7, 2020

@SteveL-MSFT I looked at the UseShellExecute implementation. It does not use a call to default shell. On Windows it uses ShellExecuteEx P/Invoke, on Unix it uses x-bit. So the cycle would be only if PowerShell associated with the extension or file.
On Windows this is an incredible scenario. On Unix the code path is blocked in line 494.
On Unix I still had a concern because in line 488 UseShellExecute is false and Process.Start will just fork and execute - if the file has #!pwsh in header the pwsh would run again but I tried on WSL without problems. So the question is closed.

@ghost
Copy link

ghost commented Oct 21, 2020

🎉v7.1.0-rc.2 has been released which incorporates this pull request.:tada:

Handy links:

@ghost
Copy link

ghost commented Nov 17, 2020

🎉v7.2.0-preview.1 has been released which incorporates this pull request.:tada:

Handy links:

@God-damnit-all
Copy link
Contributor

Is this in 7.1 stable? I don't see a revert to this commit in the diff log between 7.1 and 7.1-rc2, but it's re-incorporated in 7.2 preview 1.

@iSazonov
Copy link
Collaborator

It was included in v7.2.0-preview.1. You can check that 7.1 works well in the scenario.

@God-damnit-all
Copy link
Contributor

It was included in v7.2.0-preview.1. You can check that 7.1 works well in the scenario.

So... both versions have it?

@iSazonov
Copy link
Collaborator

Yes, both.

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

Labels

BackPort-7.1.x-Done Backport to 7.1.x completed CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When PowerShell runs elevated on Windows, starting *.msc files locks the console

4 participants