mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Fix ValueFromRemainingArguments to have consistent behavior between script and C# (#2038)
This commit is contained in:
@@ -55,10 +55,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
enumerate = false;
|
||||
}
|
||||
foreach (PSObject inputObject in _inputObjects) // compensate for ValueFromRemainingArguments
|
||||
{
|
||||
WriteObject(inputObject, enumerate);
|
||||
}
|
||||
|
||||
WriteObject(_inputObjects, enumerate);
|
||||
}//processrecord
|
||||
}//WriteOutputCommand
|
||||
#endregion
|
||||
|
||||
@@ -1684,33 +1684,31 @@ namespace System.Management.Automation
|
||||
var cpi = CommandParameterInternal.CreateParameterWithArgument(
|
||||
PositionUtilities.EmptyExtent, varargsParameter.Parameter.Name, "-" + varargsParameter.Parameter.Name + ":",
|
||||
argumentExtent, valueFromRemainingArguments, false);
|
||||
|
||||
// To make all of the following work similarly (the first is handled elsewhere, but second and third are
|
||||
// handled here):
|
||||
// Set-ClusterOwnerNode -Owners foo,bar
|
||||
// Set-ClusterOwnerNode foo bar
|
||||
// Set-ClusterOwnerNode foo,bar
|
||||
// we unwrap our List, but only if there is a single argument of type object[].
|
||||
if (valueFromRemainingArguments.Count == 1 && valueFromRemainingArguments[0] is object[])
|
||||
{
|
||||
cpi.SetArgumentValue(UnboundArguments[0].ArgumentExtent, valueFromRemainingArguments[0]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BindParameter(cpi, varargsParameter, ParameterBindingFlags.ShouldCoerceType);
|
||||
}
|
||||
catch (ParameterBindingException pbex)
|
||||
{
|
||||
// To make all of the following work similarly (the first is handled elsewhere, but second and third are
|
||||
// handled here):
|
||||
// Set-ClusterOwnerNode -Owners foo,bar
|
||||
// Set-ClusterOwnerNode foo bar
|
||||
// Set-ClusterOwnerNode foo,bar
|
||||
// we make one additional attempt at converting, but only if there is a single argument of type object[].
|
||||
if (valueFromRemainingArguments.Count == 1 && valueFromRemainingArguments[0] is object[])
|
||||
if (!DefaultParameterBindingInUse)
|
||||
{
|
||||
cpi.SetArgumentValue(UnboundArguments[0].ArgumentExtent, valueFromRemainingArguments[0]);
|
||||
BindParameter(cpi, varargsParameter, ParameterBindingFlags.ShouldCoerceType);
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DefaultParameterBindingInUse)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowElaboratedBindingException(pbex);
|
||||
}
|
||||
ThrowElaboratedBindingException(pbex);
|
||||
}
|
||||
}
|
||||
UnboundArguments.Clear();
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[array]$Parameter1,
|
||||
[int[]]$Parameter2
|
||||
[int[]]$Parameter2
|
||||
)
|
||||
|
||||
Process {
|
||||
@@ -329,4 +329,98 @@
|
||||
$result | Should Be $expected
|
||||
}
|
||||
}
|
||||
|
||||
Context "ValueFromRemainingArguments" {
|
||||
BeforeAll {
|
||||
function Test-BindingFunction {
|
||||
param (
|
||||
[Parameter(ValueFromRemainingArguments)]
|
||||
[object[]] $Parameter
|
||||
)
|
||||
|
||||
return [pscustomobject] @{
|
||||
ArgumentCount = $Parameter.Count
|
||||
Value = $Parameter
|
||||
}
|
||||
}
|
||||
|
||||
# Deliberately not using TestDrive:\ here because Pester will fail to clean it up due to the
|
||||
# assembly being loaded in our process.
|
||||
|
||||
if ($IsWindows)
|
||||
{
|
||||
$tempDir = $env:temp
|
||||
}
|
||||
else
|
||||
{
|
||||
$tempDir = '/tmp'
|
||||
}
|
||||
|
||||
$dllPath = Join-Path $tempDir TestBindingCmdlet.dll
|
||||
|
||||
Add-Type -OutputAssembly $dllPath -TypeDefinition '
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
|
||||
[Cmdlet("Test", "BindingCmdlet")]
|
||||
public class TestBindingCommand : PSCmdlet
|
||||
{
|
||||
[Parameter(Position = 0, ValueFromRemainingArguments = true)]
|
||||
public string[] Parameter { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
PSObject obj = new PSObject();
|
||||
|
||||
obj.Properties.Add(new PSNoteProperty("ArgumentCount", Parameter.Length));
|
||||
obj.Properties.Add(new PSNoteProperty("Value", Parameter));
|
||||
|
||||
WriteObject(obj);
|
||||
}
|
||||
}
|
||||
'
|
||||
|
||||
Import-Module $dllPath
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Get-Module TestBindingCmdlet | Remove-Module -Force
|
||||
}
|
||||
|
||||
It "Binds properly when passing an explicit array to an advanced function" {
|
||||
$result = Test-BindingFunction 1,2,3
|
||||
|
||||
$result.ArgumentCount | Should Be 3
|
||||
$result.Value[0] | Should Be 1
|
||||
$result.Value[1] | Should Be 2
|
||||
$result.Value[2] | Should Be 3
|
||||
}
|
||||
|
||||
It "Binds properly when passing multiple arguments to an advanced function" {
|
||||
$result = Test-BindingFunction 1 2 3
|
||||
|
||||
$result.ArgumentCount | Should Be 3
|
||||
$result.Value[0] | Should Be 1
|
||||
$result.Value[1] | Should Be 2
|
||||
$result.Value[2] | Should Be 3
|
||||
}
|
||||
|
||||
It "Binds properly when passing an explicit array to a cmdlet" {
|
||||
$result = Test-BindingCmdlet 1,2,3
|
||||
|
||||
$result.ArgumentCount | Should Be 3
|
||||
$result.Value[0] | Should Be 1
|
||||
$result.Value[1] | Should Be 2
|
||||
$result.Value[2] | Should Be 3
|
||||
}
|
||||
|
||||
It "Binds properly when passing multiple arguments to a cmdlet" {
|
||||
$result = Test-BindingCmdlet 1 2 3
|
||||
|
||||
$result.ArgumentCount | Should Be 3
|
||||
$result.Value[0] | Should Be 1
|
||||
$result.Value[1] | Should Be 2
|
||||
$result.Value[2] | Should Be 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user