Skip to content

Update PowerShell Direct to try pwsh then fallback to powershell #7241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 11, 2018

Conversation

TravisEz13
Copy link
Member

@TravisEz13 TravisEz13 commented Jul 6, 2018

PR Summary

Update PowerShell Direct to try pwsh then fallback to powershell

  • Forward port changes from Windows Powershell to fall back
  • change the order from powershell->pwsh to pwsh->powershell

fixes #7237

PR Checklist

@bergmeister
Copy link
Contributor

If I understand correctly, this partially resolves also #6669 but it also means this is a breaking change because the default is no longer Windows PowerShell?

@TravisEz13 TravisEz13 added the Breaking-Change breaking change that may affect users label Jul 9, 2018
@TravisEz13
Copy link
Member Author

@bergmeister Yes, it is part of the resolution for the issue you mention. I've added the breaking change label for the reason you mentioned.

@TravisEz13 TravisEz13 added the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Jul 9, 2018
// This code executes `powershell.exe` as it exists in the container which currently is
// expected to be Windows PowerShell as it's inbox in the container.
// This code executes `pwsh.exe` as it exists in the container which currently is
// expected to be PowerShell Core as it's inbox in the container.
//
cmd = string.Format(System.Globalization.CultureInfo.InvariantCulture,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this logic be in a separate function?

}
else
{
processId = Convert.ToInt32(ProcessInformation.ProcessId);
processId = 0;
error = result;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should set ErrorMessage here and in the failure path for failing to launch powershell.exe; otherwise, it won't be diagnosable (i.e., which path failed? pwsh.exe or powershell.exe after not finding pwsh.exe)

Copy link
Collaborator

@BrucePay BrucePay left a comment

Choose a reason for hiding this comment

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

Subject to Dan's comments, looks ok to me.

make the code to get the process command a method
make the error when we fail to launch the container process include the process that we were trying to launch.
error = result;
processId = Convert.ToInt32(ProcessInformation.ProcessId);
}
else if (result == 2147942402) // 0x80070002 (2147942402) - The system cannot find the file specified.
Copy link
Member

Choose a reason for hiding this comment

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

Prefer to just have the number on RHS in hex as it's easier to perform a web search against a hex error code. The comment can then be simplified.

Executable = "powershell.exe";
cmd = GetContainerProcessCommand();

result = HcsCreateProcess(ComputeSystem, cmd, ref ProcessInformation, ref Process, ref resultString);
Copy link
Member

Choose a reason for hiding this comment

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

Seems like this can be simplified as a loop (having only one HcsCreateProcess and checking of the error). Have Executable as an array containing pwsh.exe, powershell.exe. Once process creation succeeds, break out of the loop, otherwise try the next executable.

{
processId = 0;
error = result;
// the executable was found but did not work
Copy link
Member

Choose a reason for hiding this comment

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

We should return the HRESULT within the exception message for future troubleshooting

// the process was started, exit the loop.
break;
}
else if (result == 0x80070002) // 0x80070002 (2147942402) - The system cannot find the file specified.
Copy link
Member

Choose a reason for hiding this comment

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

remove the "0x80070002 (2147942402) -" as it's not needed now

return string.Format(System.Globalization.CultureInfo.InvariantCulture,
@"{{""CommandLine"": ""{0} {1} -NoLogo {2}"",""RestrictedToken"": {3}}}",
Executable,
(RuntimeId != Guid.Empty) ? "-so -NoProfile" : "-NamedPipeServerMode",
Copy link
Member

Choose a reason for hiding this comment

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

Can we expand -so?

/// </summary>
private string GetContainerProcessCommand()
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture,
Copy link
Contributor

Choose a reason for hiding this comment

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

Using string interpolation and FormattableString.Invariant would make this string construction easier to read:

using static System.FormattableString;
private string foo()
{
   return Invariant($"bar {expression} {baz == null ? 1 : 0}");
}

(RuntimeId != Guid.Empty) ? "-so -NoProfile" : "-NamedPipeServerMode",
String.IsNullOrEmpty(ConfigurationName) ? String.Empty : String.Concat("-Config ", ConfigurationName),
(RunAsAdmin) ? "false" : "true");
string[] executables = new string[]("pwsh.exe"."powershell.exe")
Copy link
Contributor

Choose a reason for hiding this comment

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

I am unfamiliar with this syntax. Shouldn't the string array initializer be?:

var executables = new string[] {"pwsh.exe", "powershell.exe"}

Also this can be a static readonly string array.

{
return string.Format(System.Globalization.CultureInfo.InvariantCulture,
@"{{""CommandLine"": ""{0} {1} -NoLogo {2}"",""RestrictedToken"": {3}}}",
Executable,
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels cleaner if the Executable loop variable is passed in as a parameter. I know we need the property set for error handling, but this code is a bit confusing without realizing Executable is a loop variable.

// the process was started, exit the loop.
break;
}
else if (result == 0x80070002)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we create a const variable for this expected error, with a descriptive name?

@TravisEz13 TravisEz13 force-pushed the port_ps_direct_changes branch from d6d49f1 to cd90133 Compare July 10, 2018 01:30
@TravisEz13 TravisEz13 force-pushed the port_ps_direct_changes branch from cd90133 to 239f8a7 Compare July 10, 2018 01:32
{
// "The system cannot find the file specified", try the next one
// or exit the loop of none are left to try.
continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

If both pwsh.exe and powershell.exe files are not found then this will exit without error. It is unlikely but not impossible and I feel we should handle this error case so as not to change behavior.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed, it is actually fairly likely as NanoServer containers don't have PowerShell by default if they are 1709 or newer.

Copy link
Contributor

@PaulHigin PaulHigin left a comment

Choose a reason for hiding this comment

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

LGTM

@TravisEz13
Copy link
Member Author

Restarted CI due to #7260

@TravisEz13 TravisEz13 force-pushed the port_ps_direct_changes branch from 002412f to b638ecd Compare July 11, 2018 21:41
@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee reviewed this and the order makes sense. There was some discussion about supporting pwsh-preview, however, we'll defer that until that is customer feedback requiring that change.

@SteveL-MSFT SteveL-MSFT added Committee-Reviewed PS-Committee has reviewed this and made a decision and removed Review - Committee The PR/Issue needs a review from the PowerShell Committee labels Jul 11, 2018
@TravisEz13 TravisEz13 merged commit 79d20a1 into PowerShell:master Jul 11, 2018
@TravisEz13 TravisEz13 deleted the port_ps_direct_changes branch July 11, 2018 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking-Change breaking change that may affect users Committee-Reviewed PS-Committee has reviewed this and made a decision
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Forward port PowerShell Direct into PS Core on Windows
6 participants