2016-03-30 14:20:52 -07:00
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Management.Automation ;
using Microsoft.PowerShell.Commands.Internal.Format ;
using System.Management.Automation.Internal ;
using System.Diagnostics.CodeAnalysis ;
#if CORECLR
// Use stubs for SystemException
using Microsoft.PowerShell.CoreClr.Stubs ;
#endif
namespace Microsoft.PowerShell.Commands
{
/// <summary>
/// helper class to do wildcard matching on MshExpressions
/// </summary>
internal sealed class MshExpressionFilter
{
/// <summary>
2016-08-26 16:46:03 -04:00
/// construct the class, using an array of patterns
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="wildcardPatternsStrings">array of pattern strings to use</param>
2016-07-29 13:02:49 -07:00
internal MshExpressionFilter ( string [] wildcardPatternsStrings )
2016-03-30 14:20:52 -07:00
{
if ( wildcardPatternsStrings == null )
{
2016-07-29 13:02:49 -07:00
throw new ArgumentNullException ( "wildcardPatternsStrings" );
2016-03-30 14:20:52 -07:00
}
_wildcardPatterns = new WildcardPattern [ wildcardPatternsStrings . Length ];
for ( int k = 0 ; k < wildcardPatternsStrings . Length ; k ++)
{
2016-07-29 13:02:49 -07:00
_wildcardPatterns [ k ] = WildcardPattern . Get ( wildcardPatternsStrings [ k ], WildcardOptions . IgnoreCase );
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// try to match the expression against the array of wildcard patterns.
/// the first match shortcircuits the search
/// </summary>
/// <param name="expression">MshExpression to test against</param>
/// <returns>true if there is a match, else false</returns>
2016-07-29 13:02:49 -07:00
internal bool IsMatch ( MshExpression expression )
2016-03-30 14:20:52 -07:00
{
for ( int k = 0 ; k < _wildcardPatterns . Length ; k ++)
{
2016-07-29 13:02:49 -07:00
if ( _wildcardPatterns [ k ]. IsMatch ( expression . ToString ()))
2016-03-30 14:20:52 -07:00
return true ;
}
return false ;
}
private WildcardPattern [] _wildcardPatterns ;
}
internal class SelectObjectExpressionParameterDefinition : CommandParameterDefinition
{
2016-07-29 13:02:49 -07:00
protected override void SetEntries ()
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
this . hashEntries . Add ( new ExpressionEntryDefinition ());
this . hashEntries . Add ( new NameEntryDefinition ());
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
///
/// </summary>
[Cmdlet("Select", "Object", DefaultParameterSetName = "DefaultParameter",
2016-08-23 21:21:31 -04:00
HelpUri = "https://go.microsoft.com/fwlink/?LinkID=113387", RemotingCapability = RemotingCapability.None)]
2016-03-30 14:20:52 -07:00
public sealed class SelectObjectCommand : PSCmdlet
{
#region Command Line Switches
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(ValueFromPipeline = true)]
2016-08-02 13:29:09 -07:00
public PSObject InputObject { set ; get ; } = AutomationNull . Value ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(Position = 0, ParameterSetName = "DefaultParameter")]
[Parameter(Position = 0, ParameterSetName = "SkipLastParameter")]
2016-08-02 13:29:09 -07:00
public object [] Property { get ; set ; }
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "DefaultParameter")]
[Parameter(ParameterSetName = "SkipLastParameter")]
2016-08-02 13:29:09 -07:00
public string [] ExcludeProperty { get ; set ; } = null ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "DefaultParameter")]
[Parameter(ParameterSetName = "SkipLastParameter")]
2016-08-02 13:29:09 -07:00
public string ExpandProperty { get ; set ; } = null ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter]
public SwitchParameter Unique
{
2016-07-29 13:02:49 -07:00
get { return _unique ; }
set { _unique = value ; }
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private bool _unique ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "DefaultParameter")]
// NTRAID#Windows Out Of Band Releases-927878-2006/03/02
// Allow zero
[ValidateRange(0, int.MaxValue)]
public int Last
{
2016-07-29 13:02:49 -07:00
get { return _last ; }
set { _last = value ; _firstOrLastSpecified = true ; }
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private int _last = 0 ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "DefaultParameter")]
// NTRAID#Windows Out Of Band Releases-927878-2006/03/02
// Allow zero
[ValidateRange(0, int.MaxValue)]
public int First
{
2016-07-29 13:02:49 -07:00
get { return _first ; }
set { _first = value ; _firstOrLastSpecified = true ; }
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private int _first = 0 ;
private bool _firstOrLastSpecified ;
2016-03-30 14:20:52 -07:00
/// <summary>
2016-08-26 16:46:03 -04:00
/// Skips the specified number of items from top when used with First,from end when used with Last
2016-03-30 14:20:52 -07:00
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "DefaultParameter")]
[ValidateRange(0, int.MaxValue)]
2016-08-02 13:29:09 -07:00
public int Skip { get ; set ; } = 0 ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// Skip the specified number of items from end.
/// </summary>
[Parameter(ParameterSetName = "SkipLastParameter")]
[ValidateRange(0, int.MaxValue)]
2016-08-02 13:29:09 -07:00
public int SkipLast { get ; set ; } = 0 ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// With this switch present, the cmdlet won't "short-circuit"
/// (i.e. won't stop upstream cmdlets after it knows that no further objects will be emitted downstream)
/// </summary>
[Parameter(ParameterSetName = "DefaultParameter")]
[Parameter(ParameterSetName = "IndexParameter")]
public SwitchParameter Wait { get ; set ; }
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Used to display the object at specified index
/// </summary>
/// <value></value>
[Parameter(ParameterSetName = "IndexParameter")]
[ValidateRangeAttribute(0, int.MaxValue)]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public int [] Index
{
get
{
2016-07-29 13:02:49 -07:00
return _index ;
2016-03-30 14:20:52 -07:00
}
set
{
2016-07-29 13:02:49 -07:00
_index = value ;
_indexSpecified = true ;
Array . Sort ( _index );
2016-03-30 14:20:52 -07:00
}
}
2016-07-29 13:02:49 -07:00
private int [] _index ;
private bool _indexSpecified ;
2016-03-30 14:20:52 -07:00
#endregion
2016-07-29 13:02:49 -07:00
private SelectObjectQueue _selectObjectQueue ;
2016-03-30 14:20:52 -07:00
private class SelectObjectQueue : Queue < PSObject >
{
internal SelectObjectQueue ( int first , int last , int skip , int skipLast , bool firstOrLastSpecified )
{
2016-07-29 13:02:49 -07:00
_first = first ;
_last = last ;
_skip = skip ;
_skipLast = skipLast ;
_firstOrLastSpecified = firstOrLastSpecified ;
2016-03-30 14:20:52 -07:00
}
public bool AllRequestedObjectsProcessed
{
get
{
2016-07-29 13:02:49 -07:00
return _firstOrLastSpecified && _last == 0 && _first != 0 && _streamedObjectCount >= _first ;
2016-03-30 14:20:52 -07:00
}
}
2016-08-02 19:00:50 -07:00
public new void Enqueue ( PSObject obj )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _last > 0 && this . Count >= ( _last + _skip ) && _first == 0 )
2016-03-30 14:20:52 -07:00
{
base . Dequeue ();
}
2016-07-29 13:02:49 -07:00
else if ( _last > 0 && this . Count >= _last && _first != 0 )
2016-03-30 14:20:52 -07:00
{
base . Dequeue ();
}
base . Enqueue ( obj );
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
public PSObject StreamingDequeue ()
{
//if skip parameter is not mentioned or there are no more objects to skip
2016-07-29 13:02:49 -07:00
if ( _skip == 0 )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _skipLast > 0 )
2016-03-30 14:20:52 -07:00
{
// We are going to skip some items from end, but it's okay to process
// the early input objects once we have more items in queue than the
// specified 'skipLast' value.
2016-07-29 13:02:49 -07:00
if ( this . Count > _skipLast )
2016-03-30 14:20:52 -07:00
{
return Dequeue ();
}
}
else
{
2016-07-29 13:02:49 -07:00
if ( _streamedObjectCount < _first || ! _firstOrLastSpecified )
2016-03-30 14:20:52 -07:00
{
Diagnostics . Assert ( this . Count > 0 , "Streaming an empty queue" );
2016-07-29 13:02:49 -07:00
_streamedObjectCount ++;
2016-03-30 14:20:52 -07:00
return Dequeue ();
}
2016-07-29 13:02:49 -07:00
if ( _last == 0 )
2016-03-30 14:20:52 -07:00
{
Dequeue ();
}
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
}
else
{
2016-08-26 16:46:03 -04:00
//if last parameter is not mentioned,remove the objects and decrement the skip
2016-07-29 13:02:49 -07:00
if ( _last == 0 )
2016-03-30 14:20:52 -07:00
{
Dequeue ();
2016-07-29 13:02:49 -07:00
_skip --;
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
else if ( _first != 0 )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_skip --;
2016-03-30 14:20:52 -07:00
Dequeue ();
}
}
return null ;
}
2016-07-29 13:02:49 -07:00
private int _streamedObjectCount ;
private int _first , _last , _skip , _skipLast ;
private bool _firstOrLastSpecified ;
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// list of processed parameters obtained from the Expression array
/// </summary>
2016-07-29 13:02:49 -07:00
private List < MshParameter > _propertyMshParameterList ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// singleton list of process parameters obtained from ExpandProperty
/// </summary>
2016-07-29 13:02:49 -07:00
private List < MshParameter > _expandMshParameterList ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private MshExpressionFilter _exclusionFilter ;
2016-03-30 14:20:52 -07:00
private class UniquePSObjectHelper
{
internal UniquePSObjectHelper ( PSObject o , int notePropertyCount )
{
WrittenObject = o ;
2016-08-02 13:29:09 -07:00
NotePropertyCount = notePropertyCount ;
2016-03-30 14:20:52 -07:00
}
internal readonly PSObject WrittenObject ;
2016-08-02 13:29:09 -07:00
internal int NotePropertyCount { get ; }
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private List < UniquePSObjectHelper > _uniques = null ;
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
private void ProcessExpressionParameter ()
2016-03-30 14:20:52 -07:00
{
TerminatingErrorContext invocationContext = new TerminatingErrorContext ( this );
ParameterProcessor processor =
new ParameterProcessor ( new SelectObjectExpressionParameterDefinition ());
2016-08-02 13:29:09 -07:00
if (( Property != null ) && ( Property . Length != 0 ))
2016-03-30 14:20:52 -07:00
{
2016-08-02 13:29:09 -07:00
_propertyMshParameterList = processor . ProcessParameters ( Property , invocationContext );
2016-03-30 14:20:52 -07:00
}
else
{
2016-07-29 13:02:49 -07:00
_propertyMshParameterList = new List < MshParameter >();
2016-03-30 14:20:52 -07:00
}
2016-08-02 13:29:09 -07:00
if (! string . IsNullOrEmpty ( ExpandProperty ))
2016-03-30 14:20:52 -07:00
{
2016-08-02 13:29:09 -07:00
_expandMshParameterList = processor . ProcessParameters ( new string [] { ExpandProperty }, invocationContext );
2016-03-30 14:20:52 -07:00
}
2016-08-02 13:29:09 -07:00
if ( ExcludeProperty != null )
2016-03-30 14:20:52 -07:00
{
2016-08-02 13:29:09 -07:00
_exclusionFilter = new MshExpressionFilter ( ExcludeProperty );
2016-03-30 14:20:52 -07:00
}
}
private void ProcessObject ( PSObject inputObject )
{
2016-08-02 13:29:09 -07:00
if (( Property == null || Property . Length == 0 ) && string . IsNullOrEmpty ( ExpandProperty ))
2016-03-30 14:20:52 -07:00
{
FilteredWriteObject ( inputObject , new List < PSNoteProperty >());
return ;
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
//If property parameter is mentioned
List < PSNoteProperty > matchedProperties = new List < PSNoteProperty >();
2016-07-29 13:02:49 -07:00
foreach ( MshParameter p in _propertyMshParameterList )
2016-03-30 14:20:52 -07:00
{
ProcessParameter ( p , inputObject , matchedProperties );
}
2016-08-02 13:29:09 -07:00
if ( string . IsNullOrEmpty ( ExpandProperty ))
2016-03-30 14:20:52 -07:00
{
PSObject result = new PSObject ();
if ( matchedProperties . Count != 0 )
{
HashSet < string > propertNames = new HashSet < string >( StringComparer . OrdinalIgnoreCase );
foreach ( PSNoteProperty noteProperty in matchedProperties )
{
try
{
if (! propertNames . Contains ( noteProperty . Name ))
{
propertNames . Add ( noteProperty . Name );
result . Properties . Add ( noteProperty );
}
else
{
WriteAlreadyExistingPropertyError ( noteProperty . Name , inputObject ,
"AlreadyExistingUserSpecifiedPropertyNoExpand" );
}
}
catch ( ExtendedTypeSystemException )
{
WriteAlreadyExistingPropertyError ( noteProperty . Name , inputObject ,
"AlreadyExistingUserSpecifiedPropertyNoExpand" );
}
}
}
FilteredWriteObject ( result , matchedProperties );
}
else
{
2016-07-29 13:02:49 -07:00
ProcessExpandParameter ( _expandMshParameterList [ 0 ], inputObject , matchedProperties );
2016-03-30 14:20:52 -07:00
}
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
private void ProcessParameter ( MshParameter p , PSObject inputObject , List < PSNoteProperty > result )
{
string name = p . GetEntry ( NameEntryDefinition . NameEntryKey ) as string ;
MshExpression ex = p . GetEntry ( FormatParameterDefinitionKeys . ExpressionEntryKey ) as MshExpression ;
List < MshExpressionResult > expressionResults = new List < MshExpressionResult >();
foreach ( MshExpression resolvedName in ex . ResolveNames ( inputObject ))
{
2016-07-29 13:02:49 -07:00
if ( _exclusionFilter == null || ! _exclusionFilter . IsMatch ( resolvedName ))
2016-03-30 14:20:52 -07:00
{
List < MshExpressionResult > tempExprResults = resolvedName . GetValues ( inputObject );
if ( tempExprResults == null ) continue ;
foreach ( MshExpressionResult mshExpRes in tempExprResults )
{
expressionResults . Add ( mshExpRes );
}
}
}
if ( expressionResults . Count == 0 )
{
//Commented out for bug 1107600
//if (!ex.HasWildCardCharacters)
//{
// ErrorRecord errorRecord = new ErrorRecord(
// tracer.NewArgumentException("Property", ResourcesBaseName, "PropertyNotFound", ex.ToString()),
// "PropertyNotFound",
// ErrorCategory.InvalidArgument,
// inputObject);
// WriteError(errorRecord);
//}
expressionResults . Add ( new MshExpressionResult ( null , ex , null ));
}
// if we have an expansion, renaming is not acceptable
else if (! string . IsNullOrEmpty ( name ) && expressionResults . Count > 1 )
{
string errorMsg = SelectObjectStrings . RenamingMultipleResults ;
ErrorRecord errorRecord = new ErrorRecord (
new InvalidOperationException ( errorMsg ),
"RenamingMultipleResults" ,
ErrorCategory . InvalidOperation ,
inputObject );
WriteError ( errorRecord );
return ;
}
foreach ( MshExpressionResult r in expressionResults )
{
// filter the exclusions, if any
2016-07-29 13:02:49 -07:00
if ( _exclusionFilter != null && _exclusionFilter . IsMatch ( r . ResolvedExpression ))
2016-03-30 14:20:52 -07:00
continue ;
PSNoteProperty mshProp ;
if ( string . IsNullOrEmpty ( name ))
{
string resolvedExpressionName = r . ResolvedExpression . ToString ();
if ( string . IsNullOrEmpty ( resolvedExpressionName ))
{
PSArgumentException mshArgE = PSTraceSource . NewArgumentException (
"Property" ,
SelectObjectStrings . EmptyScriptBlockAndNoName );
ThrowTerminatingError (
new ErrorRecord (
mshArgE ,
"EmptyScriptBlockAndNoName" ,
ErrorCategory . InvalidArgument , null ));
}
mshProp = new PSNoteProperty ( resolvedExpressionName , r . Result );
}
else
{
mshProp = new PSNoteProperty ( name , r . Result );
}
result . Add ( mshProp );
}
}
private void ProcessExpandParameter ( MshParameter p , PSObject inputObject ,
List < PSNoteProperty > matchedProperties )
{
MshExpression ex = p . GetEntry ( FormatParameterDefinitionKeys . ExpressionEntryKey ) as MshExpression ;
List < MshExpressionResult > expressionResults = ex . GetValues ( inputObject );
2016-07-29 13:02:49 -07:00
if ( expressionResults . Count == 0 )
2016-03-30 14:20:52 -07:00
{
ErrorRecord errorRecord = new ErrorRecord (
2016-08-02 13:29:09 -07:00
PSTraceSource . NewArgumentException ( "ExpandProperty" , SelectObjectStrings . PropertyNotFound , ExpandProperty ),
2016-03-30 14:20:52 -07:00
"ExpandPropertyNotFound" ,
ErrorCategory . InvalidArgument ,
inputObject );
throw new SelectObjectException ( errorRecord );
}
if ( expressionResults . Count > 1 )
{
ErrorRecord errorRecord = new ErrorRecord (
2016-08-02 13:29:09 -07:00
PSTraceSource . NewArgumentException ( "ExpandProperty" , SelectObjectStrings . MutlipleExpandProperties , ExpandProperty ),
2016-03-30 14:20:52 -07:00
"MutlipleExpandProperties" ,
ErrorCategory . InvalidArgument ,
inputObject );
throw new SelectObjectException ( errorRecord );
}
MshExpressionResult r = expressionResults [ 0 ];
if ( r . Exception == null )
{
// ignore the property value if it's null
if ( r . Result == null ) { return ; }
System . Collections . IEnumerable results = LanguagePrimitives . GetEnumerable ( r . Result );
if ( results == null )
{
// add NoteProperties if there is any
// If r.Result is a base object, we don't want to associate the NoteProperty
// directly with it. We want the NoteProperty to be associated only with this
// particular PSObject, so that when the user uses the base object else where,
// its members remain the same as before the Select-Object command run.
PSObject expandedObject = PSObject . AsPSObject ( r . Result , true );
AddNoteProperties ( expandedObject , inputObject , matchedProperties );
FilteredWriteObject ( expandedObject , matchedProperties );
return ;
}
foreach ( object expandedValue in results )
{
// ignore the element if it's null
if ( expandedValue == null ) { continue ; }
// add NoteProperties if there is any
// If expandedValue is a base object, we don't want to associate the NoteProperty
// directly with it. We want the NoteProperty to be associated only with this
// particular PSObject, so that when the user uses the base object else where,
// its members remain the same as before the Select-Object command run.
PSObject expandedObject = PSObject . AsPSObject ( expandedValue , true );
AddNoteProperties ( expandedObject , inputObject , matchedProperties );
FilteredWriteObject ( expandedObject , matchedProperties );
}
}
else
{
ErrorRecord errorRecord = new ErrorRecord (
r . Exception ,
"PropertyEvaluationExpand" ,
ErrorCategory . InvalidResult ,
inputObject );
throw new SelectObjectException ( errorRecord );
}
}
private void AddNoteProperties ( PSObject expandedObject , PSObject inputObject , IEnumerable < PSNoteProperty > matchedProperties )
{
foreach ( PSNoteProperty noteProperty in matchedProperties )
{
try
{
if ( expandedObject . Properties [ noteProperty . Name ] != null )
{
WriteAlreadyExistingPropertyError ( noteProperty . Name , inputObject , "AlreadyExistingUserSpecifiedPropertyExpand" );
}
else
{
expandedObject . Properties . Add ( noteProperty );
}
}
catch ( ExtendedTypeSystemException )
{
WriteAlreadyExistingPropertyError ( noteProperty . Name , inputObject , "AlreadyExistingUserSpecifiedPropertyExpand" );
}
}
}
private void WriteAlreadyExistingPropertyError ( string name , object inputObject , string errorId )
{
ErrorRecord errorRecord = new ErrorRecord (
PSTraceSource . NewArgumentException ( "Property" , SelectObjectStrings . AlreadyExistingProperty , name ),
errorId ,
ErrorCategory . InvalidOperation ,
inputObject );
WriteError ( errorRecord );
}
private void FilteredWriteObject ( PSObject obj , List < PSNoteProperty > addedNoteProperties )
{
Diagnostics . Assert ( obj != null , "This command should never write null" );
2016-07-29 13:02:49 -07:00
if (! _unique )
2016-03-30 14:20:52 -07:00
{
if ( obj != AutomationNull . Value )
{
SetPSCustomObject ( obj );
WriteObject ( obj );
}
return ;
}
//if only unique is mentioned
2016-07-29 13:02:49 -07:00
else if (( _unique ))
2016-03-30 14:20:52 -07:00
{
bool isObjUnique = true ;
2016-07-29 13:02:49 -07:00
foreach ( UniquePSObjectHelper uniqueObj in _uniques )
2016-03-30 14:20:52 -07:00
{
ObjectCommandComparer comparer = new ObjectCommandComparer ( true , CultureInfo . CurrentCulture , true );
if (( comparer . Compare ( obj . BaseObject , uniqueObj . WrittenObject . BaseObject ) == 0 ) &&
( uniqueObj . NotePropertyCount == addedNoteProperties . Count ))
{
bool found = true ;
foreach ( PSNoteProperty note in addedNoteProperties )
{
PSMemberInfo prop = uniqueObj . WrittenObject . Properties [ note . Name ];
if ( prop == null || comparer . Compare ( prop . Value , note . Value ) != 0 )
{
found = false ;
break ;
}
}
if ( found )
{
isObjUnique = false ;
break ;
}
}
else
{
continue ;
}
}
if ( isObjUnique )
{
2016-07-29 13:02:49 -07:00
SetPSCustomObject ( obj );
_uniques . Add ( new UniquePSObjectHelper ( obj , addedNoteProperties . Count ));
2016-03-30 14:20:52 -07:00
}
}
}
private void SetPSCustomObject ( PSObject psObj )
{
2016-07-29 13:02:49 -07:00
if ( psObj . ImmediateBaseObject is PSCustomObject )
2016-08-02 13:29:09 -07:00
psObj . TypeNames . Insert ( 0 , "Selected." + InputObject . BaseObject . GetType (). ToString ());
2016-03-30 14:20:52 -07:00
}
private void ProcessObjectAndHandleErrors ( PSObject pso )
{
Diagnostics . Assert ( pso != null , "Caller should verify pso != null" );
try
{
ProcessObject ( pso );
}
catch ( SelectObjectException e )
{
WriteError ( e . ErrorRecord );
}
}
/// <summary>
///
/// </summary>
2016-07-29 13:02:49 -07:00
protected override void BeginProcessing ()
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
ProcessExpressionParameter ();
if ( _unique )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_uniques = new List < UniquePSObjectHelper >();
2016-03-30 14:20:52 -07:00
}
2016-08-02 13:29:09 -07:00
_selectObjectQueue = new SelectObjectQueue ( _first , _last , Skip , SkipLast , _firstOrLastSpecified );
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private int _indexOfCurrentObject = 0 ;
private int _indexCount = 0 ;
2016-03-30 14:20:52 -07:00
/// <summary>
///
/// </summary>
protected override void ProcessRecord ()
{
2016-08-02 13:29:09 -07:00
if ( InputObject != AutomationNull . Value && InputObject != null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if (! _indexSpecified )
2016-03-30 14:20:52 -07:00
{
2016-08-02 13:29:09 -07:00
_selectObjectQueue . Enqueue ( InputObject );
2016-07-29 13:02:49 -07:00
PSObject streamingInputObject = _selectObjectQueue . StreamingDequeue ();
2016-03-30 14:20:52 -07:00
if ( streamingInputObject != null )
{
ProcessObjectAndHandleErrors ( streamingInputObject );
}
2016-07-29 13:02:49 -07:00
if ( _selectObjectQueue . AllRequestedObjectsProcessed && ! this . Wait )
2016-03-30 14:20:52 -07:00
{
this . EndProcessing ();
throw new StopUpstreamCommandsException ( this );
}
}
else
{
2016-07-29 13:02:49 -07:00
if ( _indexOfCurrentObject < _index . Length )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
int currentlyRequestedIndex = _index [ _indexOfCurrentObject ];
if ( _indexCount == currentlyRequestedIndex )
2016-03-30 14:20:52 -07:00
{
2016-08-02 13:29:09 -07:00
ProcessObjectAndHandleErrors ( InputObject );
2016-07-29 13:02:49 -07:00
while (( _indexOfCurrentObject < _index . Length ) && ( _index [ _indexOfCurrentObject ] == currentlyRequestedIndex ))
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_indexOfCurrentObject ++;
2016-03-30 14:20:52 -07:00
}
}
}
2016-07-29 13:02:49 -07:00
if (! this . Wait && _indexOfCurrentObject >= _index . Length )
2016-03-30 14:20:52 -07:00
{
this . EndProcessing ();
throw new StopUpstreamCommandsException ( this );
}
2016-07-29 13:02:49 -07:00
_indexCount ++;
2016-03-30 14:20:52 -07:00
}
}
}
/// <summary>
///
/// </summary>
protected override void EndProcessing ()
{
// We can skip this part for 'IndexParameter' and 'SkipLastParameter' sets because:
// 1. 'IndexParameter' set doesn't use selectObjectQueue.
// 2. 'SkipLastParameter' set should have processed all valid input in the ProcessRecord.
if ( ParameterSetName == "DefaultParameter" )
{
2016-07-29 13:02:49 -07:00
if ( _first != 0 )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
while (( _selectObjectQueue . Count > 0 ))
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
ProcessObjectAndHandleErrors ( _selectObjectQueue . Dequeue ());
2016-03-30 14:20:52 -07:00
}
}
else
{
2016-07-29 13:02:49 -07:00
while (( _selectObjectQueue . Count > 0 ))
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
int lenQueue = _selectObjectQueue . Count ;
2016-08-02 13:29:09 -07:00
if ( lenQueue > Skip )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
ProcessObjectAndHandleErrors ( _selectObjectQueue . Dequeue ());
2016-03-30 14:20:52 -07:00
}
else
{
break ;
}
}
}
}
2016-07-29 13:02:49 -07:00
if ( _uniques != null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
foreach ( UniquePSObjectHelper obj in _uniques )
2016-03-30 14:20:52 -07:00
{
if ( obj . WrittenObject == null || obj . WrittenObject == AutomationNull . Value )
{
continue ;
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
WriteObject ( obj . WrittenObject );
}
}
}
}
/// <summary>
/// Used only internally for select-object
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "This exception is internal and never thrown by any public API")]
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception is internal and never thrown by any public API")]
[SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic", Justification = "This exception is internal and never thrown by any public API")]
internal class SelectObjectException : SystemException
{
2016-08-02 13:29:09 -07:00
internal ErrorRecord ErrorRecord { get ; }
2016-03-30 14:20:52 -07:00
internal SelectObjectException ( ErrorRecord errorRecord )
{
2016-08-02 13:29:09 -07:00
ErrorRecord = errorRecord ;
2016-03-30 14:20:52 -07:00
}
}
}