Skip to content
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

Add pwshw for console-less PowerShell on Windows #10962

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0d4e12e
Add pwshw for console-less PowerShell on Windows
SteveL-MSFT Nov 1, 2019
6b8ae56
address Aditya's feedback
SteveL-MSFT Nov 1, 2019
752900c
fix cases where console color is requested but there is no console
SteveL-MSFT Nov 2, 2019
7ab6d23
fix test failures. Tests Passed: 10518, Failed: 38
SteveL-MSFT Nov 3, 2019
fc94a7d
fixed and skipping some tests, 23 failures
SteveL-MSFT Nov 4, 2019
726052b
add pwshw.dll to signing
SteveL-MSFT Nov 4, 2019
933b7fd
fix build.psm1
SteveL-MSFT Nov 4, 2019
e0be561
fixed test issues, 17 failures, but they also fail on my system with …
SteveL-MSFT Nov 4, 2019
e49ad46
enable running tests in pwshw
SteveL-MSFT Nov 4, 2019
d0cb763
fix test and running CI test
SteveL-MSFT Nov 5, 2019
c8afbc4
add -OutputLog to console host, removed dependency on transcription
SteveL-MSFT Nov 5, 2019
0aa616e
remove hardcoded local path used for development
SteveL-MSFT Nov 5, 2019
9a55baa
address Codacy issue
SteveL-MSFT Nov 5, 2019
14d77e9
fix transcription test
SteveL-MSFT Nov 6, 2019
b7b8561
fix Codacy issue
SteveL-MSFT Nov 6, 2019
fbd5468
remove unused member
SteveL-MSFT Nov 6, 2019
f558536
enable unelevated pwshw tests
SteveL-MSFT Nov 6, 2019
d796f6b
fix validation of ci test purpose
SteveL-MSFT Nov 6, 2019
2ecaf02
handle not being able to create the outputlog
SteveL-MSFT Nov 6, 2019
b5a733f
enable CI tests for pwshw
SteveL-MSFT Nov 6, 2019
4d48f7c
fix transcript tests
SteveL-MSFT Nov 6, 2019
ada4330
expose as Experimental Feature, fix writing to outputlog, add tests
SteveL-MSFT Nov 6, 2019
a6e88cf
Update src/Microsoft.PowerShell.ConsoleHost/host/msh/CommandLineParam…
SteveL-MSFT Nov 7, 2019
f651490
Update src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
SteveL-MSFT Nov 7, 2019
957f516
address Ilya's feedback
SteveL-MSFT Nov 7, 2019
a50f869
fix codefactor issue making OutputLog nullable
SteveL-MSFT Aug 12, 2020
15799e2
update Files.wxs
SteveL-MSFT Aug 12, 2020
20989b9
define pwshw results filepath
SteveL-MSFT Aug 14, 2020
c0dd6fd
update packaging files
SteveL-MSFT Aug 14, 2020
3cb8e35
address Travis' feedback
SteveL-MSFT Aug 14, 2020
2ec5013
address Ilya's feedback
SteveL-MSFT Aug 18, 2020
558b26c
add xunit tests
SteveL-MSFT Aug 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions .vsts-ci/windows.yml
Expand Up @@ -71,6 +71,26 @@ stages:
purpose: ElevatedPesterTests
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
tagSet: Others

- template: templates/windows-test.yml
parameters:
purpose: PwshwElevatedPesterTests
tagSet: CI

- template: templates/windows-test.yml
parameters:
purpose: PwshwUnelevatedPesterTests
tagSet: CI

- template: templates/windows-test.yml
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
parameters:
purpose: PwshwElevatedPesterTests
tagSet: Others

- template: templates/windows-test.yml
parameters:
purpose: PwshwUnelevatedPesterTests
tagSet: Others

- template: templates/verify-xunit.yml

- stage: PackagingWin
Expand Down
28 changes: 27 additions & 1 deletion assets/files.wxs
Expand Up @@ -3111,10 +3111,30 @@
<Component Id="cmp5485813EC16244898CB9A944AC2BC5E9">
<File Id="fil6EA784763CF94299BC6E75DF068F05A3" KeyPath="yes" Source="$(var.ProductSourcePath)\Microsoft.PowerShell.Pager.dll" />
</Component>
<Component Id="cmpDA1453DB684C4170B974D0C7ADC0C424">
<File Id="fil6396806B94F34AE88BB862C8D08E66B9" KeyPath="yes" Source="$(var.ProductSourcePath)\pwshw.exe" />
</Component>
<Component Id="cmp5951388228634DD8BCBDA8F6BA84AC32">
<File Id="filFF7DCF6BF27E47C88DD211C9D813E258" KeyPath="yes" Source="$(var.ProductSourcePath)\pwshw.xml" />
</Component>
<Component Id="cmp0FC42840B034428FA062F6D848718167">
<File Id="fil13D53DE960C24D5190CF3D6C87AE0818" KeyPath="yes" Source="$(var.ProductSourcePath)\pwshw.dll" />
</Component>
<Component Id="cmpF08FF4A7952F4AE1A6148D5D879668F9">
<File Id="fil818AA56637E24A389BCAA02EACF8FC1E" KeyPath="yes" Source="$(var.ProductSourcePath)\pwshw.deps.json" />
</Component>
<Component Id="cmp0A0B969E114A4FD0AB1B5EF85DAAD9C2">
<File Id="fil6AC2B5AAC977495DBA6D4A64DE589746" KeyPath="yes" Source="$(var.ProductSourcePath)\pwshw.runtimeconfig.json" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="ApplicationFiles">
<ComponentRef Id="cmpDA1453DB684C4170B974D0C7ADC0C424" />
<ComponentRef Id="cmp5951388228634DD8BCBDA8F6BA84AC32" />
<ComponentRef Id="cmp0FC42840B034428FA062F6D848718167" />
<ComponentRef Id="cmpF08FF4A7952F4AE1A6148D5D879668F9" />
<ComponentRef Id="cmp0A0B969E114A4FD0AB1B5EF85DAAD9C2" />
<ComponentRef Id="cmpCBE3857586454EB3B634B118E8EBD1D1" />
<ComponentRef Id="cmp22EA8B65E9784BB197A5CC42FBFF1788" />
<ComponentRef Id="cmp9F22B503FD4D4F0286514A511718FD7A" />
Expand Down Expand Up @@ -3654,6 +3674,7 @@
<ComponentRef Id="cmpF1B0E6DCC3BD4797B206C879EF270062" />
<ComponentRef Id="cmp25A144CC34E545378735B06794A02F90" />
<ComponentRef Id="cmp19ADFEFDD03047828CF493B5B5CE7B6E" />
<ComponentRef Id="cmp72C41225E0B4457C8CB5F4C5FE6E3187" />
<ComponentRef Id="cmpDC2EF4541FA5A2E63F36A8CD6C5FA51B" />
<ComponentRef Id="cmpA620CA71E6FF4F50B6D7BB0761D17036" />
<ComponentRef Id="cmp2DF9FE0BD560EB7DC8489A259330C2C6" />
Expand Down Expand Up @@ -4109,11 +4130,16 @@
<ComponentRef Id="cmpE9599A00802144DF98F5792E029C8875" />
<ComponentRef Id="cmp0989343D60B74AF082291F612F0E6FA6" />
<ComponentRef Id="cmp7BDE558CCB344A399134DE2C9E2C8D3D" />
<ComponentRef Id="cmp72C41225E0B4457C8CB5F4C5FE6E3187" />
<ComponentRef Id="cmp0BD7D15E0377407FA4C43BFE89F0C12E" />
<ComponentRef Id="cmpC0FFB3F4FB30438082D2DC0F4E4BF12D" />
<ComponentRef Id="cmpF65478926051451688800150DBAEE4BC" />
<ComponentRef Id="cmp5485813EC16244898CB9A944AC2BC5E9" />
<ComponentRef Id="cmpEF8ADE303C474061BD40F76A091700FC" />
<ComponentRef Id="cmp809B0A86A84E44E8BDDBE8C10016FF7D" />
<ComponentRef Id="cmp4FB327A8BE924E14BA996745EFD40325" />
<ComponentRef Id="cmp690D406DC9F249B4AFFAFAEF0172086B" />
<ComponentRef Id="cmp463BE93A0EB34578B1B0758BEABE6726" />
<ComponentRef Id="cmp6CC991E0210642BDA9F3C3924A3E3A37" />
</ComponentGroup>
</Fragment>
</Wix>
53 changes: 48 additions & 5 deletions build.psm1
Expand Up @@ -466,6 +466,18 @@ Fix steps:
Start-NativeExecution { dotnet $Arguments }
Write-Log -message "PowerShell output: $($Options.Output)"

# Also build pwshw for Windows
if ($Options.Runtime -like 'win*') {
$OutputPath = Split-Path -Path $Options.Output -Parent
Push-Location ($Options.Top + "-w")
Start-NativeExecution { dotnet $Arguments }
# Copy the necessary binaries only
$SourcePath = (Split-Path -Path $Options.Output -Parent) -Replace "powershell-win-core","powershell-win-core-w"
Write-Log "Copying $SourcePath to $OutputPath"
Copy-Item -Path "$SourcePath\pwshw.*" -Destination $OutputPath -Force
Pop-Location
}

if ($CrossGen) {
## fxdependent package cannot be CrossGen'ed
Start-CrossGen -PublishPath $publishPath -Runtime $script:Options.Runtime
Expand Down Expand Up @@ -625,6 +637,10 @@ function Restore-PSPackage
{
$ProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules")

if ($Options.RunTime -like "win*") {
$ProjectDirs += $Options.Top + "-w"
}

if ($Options.Runtime -like 'fxdependent*') {
$ProjectDirs += "$PSScriptRoot/src/Microsoft.PowerShell.GlobalTool.Shim"
}
Expand Down Expand Up @@ -981,11 +997,11 @@ function Publish-PSTestTools {
$objPath = Join-Path -Path $tool.Path -ChildPath "obj"

if (Test-Path $toolPath) {
Remove-Item -Path $toolPath -Recurse -Force
Remove-Item -Path $toolPath -Recurse -Force -ErrorAction Ignore
}

if (Test-Path $objPath) {
Remove-Item -Path $objPath -Recurse -Force
Remove-Item -Path $objPath -Recurse -Force -ErrorAction Ignore
}

if (-not $runtime) {
Expand Down Expand Up @@ -1327,13 +1343,18 @@ function Start-PSPester {
}
else
{
$params = @{sb = [scriptblock]{& $powershell $PSFlags -c $command}}
if ($powershell.Contains("pwshw")) {
$params += @{WaitForProcess = 'pwshw'}
}

if ($Terse)
{
Start-NativeExecution -sb {& $powershell $PSFlags -c $command} | ForEach-Object { Write-Terse -line $_ }
Start-NativeExecution @params | ForEach-Object { Write-Terse -line $_ }
}
else
{
Start-NativeExecution -sb {& $powershell $PSFlags -c $command}
Start-NativeExecution @params
}
}
}
Expand Down Expand Up @@ -2158,7 +2179,8 @@ function script:Start-NativeExecution
param(
[scriptblock]$sb,
[switch]$IgnoreExitcode,
[switch]$VerboseOutputOnError
[switch]$VerboseOutputOnError,
[string]$WaitForProcess
)
$backupEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue"
Expand All @@ -2169,7 +2191,28 @@ function script:Start-NativeExecution
}
else
{
# check if process is already running, otherwise we wait forever
if ($PSBoundParameters.ContainsKey('WaitForProcess') -and $null -ne (Get-Process $WaitForProcess -ErrorAction Ignore))
{
throw "'$WaitForProcess' is already running, stop it and try again"
}

& $sb
if ($PSBoundParameters.ContainsKey('WaitForProcess'))
{
while ($null -eq (Get-Process $WaitForProcess -ErrorAction Ignore))
{
Start-Sleep -Milliseconds 250
}

Write-Verbose -Verbose "Waiting on '$WaitForProcess' to complete..."
while ($null -ne (Get-Process $WaitForProcess -ErrorAction Ignore))
{
# write some output so it doesn't timeout in CI
Write-Host "." -NoNewline
Start-Sleep -Seconds 60
}
}
}

# note, if $sb doesn't have a native invocation, $LASTEXITCODE will
Expand Down
Expand Up @@ -112,7 +112,7 @@ protected override void ProcessRecord()
informationMessage.ForegroundColor = ForegroundColor;
informationMessage.BackgroundColor = BackgroundColor;
}
catch (System.Management.Automation.Host.HostException)
catch
{
// Expected if the host is not interactive, or doesn't have Foreground / Background
// colours.
Expand Down
Expand Up @@ -187,6 +187,7 @@ internal static int MaxNameLength()
"nologo",
"noninteractive",
"noprofile",
"outputlog",
"outputformat",
"removeworkingdirectorytrailingcharacter",
"settingsfile",
Expand Down Expand Up @@ -408,6 +409,14 @@ internal bool ShowVersion
}
}

internal string? OutputLog
{
get
{
return _outputLog;
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
}
}

internal Serialization.DataFormat OutputFormat
{
get
Expand Down Expand Up @@ -871,6 +880,18 @@ private void ParseHelper(string[] args)
// Just toss this option, it was processed earlier in 'ManagedEntrance.Start()'.
}
#endif
else if (MatchSwitch(switchKey, "outputlog", "outputl") || MatchSwitch(switchKey, "ol", "ol"))
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
{
++i;
if (i >= args.Length)
{
SetCommandLineError(
CommandLineParameterParserStrings.MissingOutputLogParameter);
break;
}

_outputLog = args[i];
}
else if (MatchSwitch(switchKey, "outputformat", "o") || MatchSwitch(switchKey, "of", "o"))
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
{
ParseFormat(args, ref i, ref _outFormat, CommandLineParameterParserStrings.MissingOutputFormatParameter);
Expand Down Expand Up @@ -974,6 +995,11 @@ private void ParseHelper(string[] args)
}
}

if (string.Equals(AppDomain.CurrentDomain.FriendlyName, ConsoleHost.PwshwHost, StringComparison.OrdinalIgnoreCase))
{
_noInteractive = true;
}
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved

Dbg.Assert(
((_exitCode == ConsoleHost.ExitCodeBadCommandLineParameter) && _abortStartup)
|| (_exitCode == ConsoleHost.ExitCodeSuccess),
Expand Down Expand Up @@ -1330,6 +1356,7 @@ private bool CollectArgs(string[] args, ref int i)
private bool _wasCommandEncoded;
private uint _exitCode = ConsoleHost.ExitCodeSuccess;
private bool _dirty;
private string? _outputLog;
private Serialization.DataFormat _outFormat = Serialization.DataFormat.Text;
private bool _outputFormatSpecified = false;
private Serialization.DataFormat _inFormat = Serialization.DataFormat.Text;
Expand Down
38 changes: 36 additions & 2 deletions src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
Expand Up @@ -55,6 +55,7 @@ internal sealed partial class ConsoleHost
internal const int ExitCodeCtrlBreak = 128 + 21; // SIGBREAK
internal const int ExitCodeInitFailure = 70; // Internal Software Error
internal const int ExitCodeBadCommandLineParameter = 64; // Command Line Usage Error
internal const string PwshwHost = "pwshw";
private const uint SPI_GETSCREENREADER = 0x0046;

[DllImport("user32.dll", SetLastError = true)]
Expand Down Expand Up @@ -1225,6 +1226,11 @@ private void Dispose(bool isDisposingNotFinalizing)
StopTranscribing();
}

if (_outputLogWriter != null)
{
_outputLogWriter.Close();
}

if (_outputSerializer != null)
{
_outputSerializer.End();
Expand Down Expand Up @@ -1304,6 +1310,16 @@ internal RunspaceRef RunspaceRef
}
}

internal string OutputLog { get; private set; }

internal StreamWriter OutputLogWriter
{
get
{
return _outputLogWriter;
}
}

internal WrappedSerializer.DataFormat OutputFormat { get; private set; }

internal bool OutputFormatSpecified { get; private set; }
Expand Down Expand Up @@ -1375,9 +1391,9 @@ internal bool IsInteractive
{
get
{
// we're running interactive if we're in a prompt loop, and we're not reading keyboard input from stdin.
// we're running interactive if we're in a prompt loop, we're not reading keyboard input from stdin, and not running pwshw which doens't have a console

return _isRunningPromptLoop && !ui.ReadFromStdin;
return _isRunningPromptLoop && !ui.ReadFromStdin && !string.Equals(AppDomain.CurrentDomain.FriendlyName, PwshwHost, StringComparison.OrdinalIgnoreCase);
}
}

Expand Down Expand Up @@ -1429,6 +1445,23 @@ private uint Run(CommandLineParameterParser cpp, bool isPrestartWarned)
break;
}

OutputLog = cpp.OutputLog;
if (!string.IsNullOrEmpty(OutputLog) && _outputLogWriter == null)
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
{
try
{
_outputLogWriter = new StreamWriter(OutputLog, append: false);
}
catch (Exception e)
{
s_tracer.TraceError("Could not create log file \"{0}\": {1}", OutputLog, e.Message);
string msg = StringUtil.Format(ConsoleHostStrings.CreatingOutputLogFailed, OutputLog, e.Message);
ui.WriteErrorLine(msg);
SteveL-MSFT marked this conversation as resolved.
Show resolved Hide resolved
exitCode = ExitCodeInitFailure;
break;
}
}

OutputFormat = cpp.OutputFormat;
OutputFormatSpecified = cpp.OutputFormatSpecified;
InputFormat = cpp.InputFormat;
Expand Down Expand Up @@ -2942,6 +2975,7 @@ private class ConsoleHostStartupException : Exception
private bool _shouldEndSession;
private int _beginApplicationNotifyCount;

private StreamWriter _outputLogWriter;
private ConsoleTextWriter _consoleWriter;
private WrappedSerializer _outputSerializer;
private WrappedSerializer _errorSerializer;
Expand Down
Expand Up @@ -35,8 +35,16 @@ class ConsoleHostRawUserInterface : System.Management.Automation.Host.PSHostRawU
internal
ConsoleHostRawUserInterface(ConsoleHostUserInterface mshConsole) : base()
{
defaultForeground = ForegroundColor;
defaultBackground = BackgroundColor;
try
{
defaultForeground = ForegroundColor;
defaultBackground = BackgroundColor;
}
catch (HostException)
{
// ignore this as it means we're running as pwshw
}

parent = mshConsole;
// cacheKeyEvent is a value type and initialized automatically

Expand Down