From 618d9f31a0c70152226f3546e1d802eefa9d372b Mon Sep 17 00:00:00 2001 From: Staffan Gustafsson Date: Thu, 9 Aug 2018 20:59:54 +0200 Subject: [PATCH] Add '-SkipIndex' parameter to 'Select-Object' (#7483) --- .../commands/utility/select-object.cs | 125 ++++++++++++++---- .../Select-Object.Tests.ps1 | 12 ++ 2 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs index 4b31897411..aece2f1466 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/select-object.cs @@ -161,7 +161,7 @@ namespace Microsoft.PowerShell.Commands public SwitchParameter Wait { get; set; } /// - /// Used to display the object at specified index. + /// Used to display the object at the specified index. /// /// [Parameter(ParameterSetName = "IndexParameter")] @@ -177,11 +177,36 @@ namespace Microsoft.PowerShell.Commands { _index = value; _indexSpecified = true; + _isIncludeIndex = true; Array.Sort(_index); } } + + /// + /// Used to display all objects at the specified indices. + /// + /// + [Parameter(ParameterSetName = "SkipIndexParameter")] + [ValidateRangeAttribute(0, int.MaxValue)] + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + public int[] SkipIndex + { + get + { + return _index; + } + set + { + _index = value; + _indexSpecified = true; + _isIncludeIndex = false; + Array.Sort(_index); + } + } + private int[] _index; private bool _indexSpecified; + private bool _isIncludeIndex; #endregion @@ -641,15 +666,18 @@ namespace Microsoft.PowerShell.Commands _selectObjectQueue = new SelectObjectQueue(_first, _last, Skip, SkipLast, _firstOrLastSpecified); } - private int _indexOfCurrentObject = 0; - private int _indexCount = 0; /// + /// Handles processing of InputObject. /// protected override void ProcessRecord() { if (InputObject != AutomationNull.Value && InputObject != null) { - if (!_indexSpecified) + if (_indexSpecified) + { + ProcessIndexed(); + } + else { _selectObjectQueue.Enqueue(InputObject); PSObject streamingInputObject = _selectObjectQueue.StreamingDequeue(); @@ -657,39 +685,82 @@ namespace Microsoft.PowerShell.Commands { ProcessObjectAndHandleErrors(streamingInputObject); } + if (_selectObjectQueue.AllRequestedObjectsProcessed && !this.Wait) { this.EndProcessing(); throw new StopUpstreamCommandsException(this); } } - else - { - if (_indexOfCurrentObject < _index.Length) - { - int currentlyRequestedIndex = _index[_indexOfCurrentObject]; - if (_indexCount == currentlyRequestedIndex) - { - ProcessObjectAndHandleErrors(InputObject); - while ((_indexOfCurrentObject < _index.Length) && (_index[_indexOfCurrentObject] == currentlyRequestedIndex)) - { - _indexOfCurrentObject++; - } - } - } - - if (!this.Wait && _indexOfCurrentObject >= _index.Length) - { - this.EndProcessing(); - throw new StopUpstreamCommandsException(this); - } - - _indexCount++; - } } } /// + /// The index of the active index filter. + /// + private int _currentFilterIndex; + + /// + /// The index of the object being processed. + /// + private int _currentObjectIndex; + + /// + /// Handles processing of InputObject if -Index or -SkipIndex is specified. + /// + private void ProcessIndexed() + { + if (_isIncludeIndex) + { + if (_currentFilterIndex < _index.Length) + { + int nextIndexToOutput = _index[_currentFilterIndex]; + if (_currentObjectIndex == nextIndexToOutput) + { + ProcessObjectAndHandleErrors(InputObject); + while ((_currentFilterIndex < _index.Length) && (_index[_currentFilterIndex] == nextIndexToOutput)) + { + _currentFilterIndex++; + } + } + } + + if (!Wait && _currentFilterIndex >= _index.Length) + { + EndProcessing(); + throw new StopUpstreamCommandsException(this); + } + + _currentObjectIndex++; + } + else + { + if (_currentFilterIndex < _index.Length) + { + int nextIndexToSkip = _index[_currentFilterIndex]; + if (_currentObjectIndex != nextIndexToSkip) + { + ProcessObjectAndHandleErrors(InputObject); + } + else + { + while ((_currentFilterIndex < _index.Length) && (_index[_currentFilterIndex] == nextIndexToSkip)) + { + _currentFilterIndex++; + } + } + } + else + { + ProcessObjectAndHandleErrors(InputObject); + } + + _currentObjectIndex++; + } + } + + /// + /// Completes the processing of Input. /// protected override void EndProcessing() { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 index 8565b3ccae..872b785049 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 @@ -244,6 +244,18 @@ Describe "Select-Object DRT basic functionality" -Tags "CI" { $results[0] | Should -BeExactly "3" } + It "Select-Object with SkipIndex should work" { + $results = "1", "2", "3" | Select-Object -SkipIndex 0, 2 + $results | Should -HaveCount 1 + $results[0] | Should -BeExactly "2" + } + + It "Select-Object with SkipIndex should work with index out of range" { + $results = 0..10 | Select-Object -SkipIndex 5, 6, 7, 8, 11 + $results | Should -HaveCount 7 + $results -join ',' | Should -BeExactly "0,1,2,3,4,9,10" + } + It "Select-Object should handle dynamic (DLR) properties"{ $dynObj = [TestDynamic]::new() $results = $dynObj, $dynObj | Select-Object -ExpandProperty FooProp