From 673117cf612d920ff96852af34879fa19d1ba157 Mon Sep 17 00:00:00 2001 From: Michael Klement Date: Sun, 26 Nov 2017 15:23:30 -0500 Subject: [PATCH] Fix accidental wrapping of scalar Write-Output input when -NoEnumerate is used. Fix #5122 --- .../commands/utility/Write-Object.cs | 24 +++++++++++++++++-- .../Write-Output.Tests.ps1 | 8 +++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs index 2ac76d2c63a..ae0274f472c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Write-Object.cs @@ -3,6 +3,7 @@ --********************************************************************/ using System.Management.Automation; +using System.Collections.Generic; namespace Microsoft.PowerShell.Commands { @@ -14,7 +15,7 @@ namespace Microsoft.PowerShell.Commands [Cmdlet(VerbsCommunications.Write, "Output", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113427", RemotingCapability = RemotingCapability.None)] public sealed class WriteOutputCommand : PSCmdlet { - private PSObject[] _inputObjects = null; + private object _inputObjects = null; /// /// Holds the list of objects to be Written @@ -22,7 +23,7 @@ public sealed class WriteOutputCommand : PSCmdlet [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromRemainingArguments = true)] [AllowNull] [AllowEmptyCollection] - public PSObject[] InputObject + public object InputObject { get { return _inputObjects; } set { _inputObjects = value; } @@ -39,6 +40,25 @@ public SwitchParameter NoEnumerate set; } + /// + /// This method implements the BeginProcessing method for Write-output command + /// + protected override void BeginProcessing() { + // If the input is a List instance with a single element, + // assume that it is a single argument bound via ValueFromRemainingArguments and unwrap it. + // Note: + // * This case is indistinguishable from something like the following: + // Write-Output -NoEnumerate -InputObject ([System.Collections.Generic.List[object]]::new((, 1))) + // However, this seems like an acceptable price to pay in order to prevent unexpected wrapping of + // a scalar in a collection when using -NoEnumerate. + // * Is the case of *multiple* ValueFromRemainingArguments values, the List instance + // is passed through when -NoEnumerate is specified. + List lst; + if (_inputObjects is List && (lst = (List)_inputObjects).Count == 1) { + _inputObjects = lst[0]; + } + } + /// /// This method implements the ProcessRecord method for Write-output command /// diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Output.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Output.Tests.ps1 index bca5d13a239..7899a8a9a54 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Output.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Output.Tests.ps1 @@ -71,4 +71,12 @@ Describe "Write-Output" -Tags "CI" { $singleCollection | Should Be 1 } } + + Context "Scalar input" { + It "Write-Object -NoEnumerate should not wrap a scalar" { + Write-Output -NoEnumerate 1 | Should BeOfType [int] + Write-Output -NoEnumerate -InputObject 1 | Should BeOfType [int] + 1 | Write-Output -NoEnumerate | Should BeOfType [int] + } + } }