// internals //internal CmdletInfo CreateGetCommandCopy(CmdletInfo cmdletInfo, object[] arguments); //internal object[] Arguments { set; get; } //internal string FullName { get; } //internal bool IsGetCommandCopy { set; get; } private CommandParameterInfo AddParameterToParameterSet(Dictionary <string, Collection <CommandParameterInfo> > paramSets, MemberInfo memberInfo, Type type, ParameterAttribute paramAttr) { CommandParameterInfo pi = new CommandParameterInfo(memberInfo, type, paramAttr); var paramSetName = paramAttr.ParameterSetName; // Determine if this parameter is uniquely defined for one set and rember it if (!String.IsNullOrEmpty(paramSetName) && !paramSetName.Equals(ParameterAttribute.AllParameterSets)) { var parameterName = pi.Name; // check if we already defined that parameter for another set if (UniqueSetParameters.ContainsKey(parameterName)) { UniqueSetParameters[parameterName] = null; } else { // not yet in any set, it's a candidate for a unique parameter UniqueSetParameters[parameterName] = paramSetName; } } paramSetName = paramSetName ?? ParameterAttribute.AllParameterSets; if (!paramSets.ContainsKey(paramSetName)) { paramSets.Add(paramSetName, new Collection <CommandParameterInfo>()); } Collection <CommandParameterInfo> paramSet = paramSets[paramSetName]; paramSet.Add(pi); return(pi); }
/// <remarks> /// From MSDN article: http://msdn2.microsoft.com/en-us/library/ms714348(VS.85).aspx /// /// * A cmdlet can have any number of parameters. However, for a better user experience the number /// of parameters should be limited when possible. /// * Parameters must be declared on public non-static fields or properties. It is preferred for /// parameters to be declared on properties. The property must have a public setter, and if ValueFromPipeline /// or ValueFromPipelineByPropertyName is specified the property must have a public getter. /// * When specifying positional parameters, note the following. /// * Limit the number of positional parameters in a parameter set to less than five if possible. /// * Positional parameters do not have to be sequential; positions 5, 100, 250 works the same as positions 0, 1, 2. /// * When the Position keyword is not specified, the cmdlet parameter must be referenced by its name. /// * When using parameter sets, no parameter set should contain more than one positional parameter with the same position. /// * In addition, only one parameter in a set should declare ValueFromPipeline = true. Multiple parameters may define ValueFromPipelineByPropertyName = true. /// /// </remarks> private void GetParameterSetInfo(Type cmdletType) { Dictionary <string, Collection <CommandParameterInfo> > paramSets = new Dictionary <string, Collection <CommandParameterInfo> >(StringComparer.CurrentCultureIgnoreCase); // TODO: When using parameter sets, no parameter set should contain more than one positional parameter with the same position. // TODO: If not parameters have a position declared then positions for all the parameters should be automatically declaredin the order they are specified // TODO: Only one parameter in a set should declare ValueFromRemainingArguments = true // TODO: Only one parameter in a set should declare ValueFromPipeline = true. Multiple parameters may define ValueFromPipelineByPropertyName = true. // TODO: Currently due to the way parameters are loaded into sets from all set at the end the parameter end up in incorrect order. // get the name of the default parameter set string strDefaultParameterSetName = null; object[] cmdLetAttrs = cmdletType.GetCustomAttributes(typeof(CmdletAttribute), false); if (cmdLetAttrs.Length > 0) { strDefaultParameterSetName = ((CmdletAttribute)cmdLetAttrs[0]).DefaultParameterSetName; // If a default set is specified, it has to exist, even if it's empty. // See NonExisitingDefaultParameterSetIsEmptyPatameterSet reference test if (!String.IsNullOrEmpty(strDefaultParameterSetName)) { paramSets.Add(strDefaultParameterSetName, new Collection <CommandParameterInfo>()); } } // always have a parameter set for all parameters. even if we don't have any parameters or no parameters // that are in all sets. This will nevertheless save various checks if (!paramSets.ContainsKey(ParameterAttribute.AllParameterSets)) { paramSets.Add(ParameterAttribute.AllParameterSets, new Collection <CommandParameterInfo>()); } // Add fields with ParameterAttribute foreach (FieldInfo fieldInfo in cmdletType.GetFields(BindingFlags.Public | BindingFlags.Instance)) { System.Diagnostics.Debug.WriteLine(fieldInfo.ToString()); object[] attributes = fieldInfo.GetCustomAttributes(false); CommandParameterInfo last = null; // Find all [Parameter] attributes on the property foreach (object attr in attributes) { if (attr is ParameterAttribute) { last = AddParameterToParameterSet(paramSets, fieldInfo, fieldInfo.FieldType, (ParameterAttribute)attr); } } if (last != null) { RegisterParameter(last); } } // Add properties with ParameterAttribute foreach (PropertyInfo propertyInfo in cmdletType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { System.Diagnostics.Debug.WriteLine(propertyInfo.ToString()); object[] attributes = propertyInfo.GetCustomAttributes(false); // Get info for the setter and getter MethodInfo getter = propertyInfo.GetAccessors().FirstOrDefault(i => i.IsSpecialName && i.Name.StartsWith("get_")); MethodInfo setter = propertyInfo.GetSetMethod(); // Find all [Parameter] attributes on the property CommandParameterInfo last = null; ParameterAttribute paramAttr = null; foreach (object attr in attributes) { if (attr is ParameterAttribute) { paramAttr = (ParameterAttribute)attr; // if ValueFromPipeline or ValueFromPipelineByPropertyName is specified the property must have a public getter if ((paramAttr.ValueFromPipeline || paramAttr.ValueFromPipelineByPropertyName) && (getter == null || !getter.IsPublic)) { break; } // The property must have a public setter if (setter == null || !setter.IsPublic) { break; } last = AddParameterToParameterSet(paramSets, propertyInfo, propertyInfo.PropertyType, paramAttr); } } if (last != null) { RegisterParameter(last); } } // Clean the UniqueSetParameters foreach (var cur in UniqueSetParameters.Where(keyValue => (keyValue.Value == null)).ToList()) { UniqueSetParameters.Remove(cur.Key); } // Create param-sets collection Collection <CommandParameterSetInfo> paramSetInfo = new Collection <CommandParameterSetInfo>(); foreach (string paramSetName in paramSets.Keys) { bool bIsDefaultParamSet = paramSetName.Equals(strDefaultParameterSetName); paramSetInfo.Add(new CommandParameterSetInfo(paramSetName, bIsDefaultParamSet, paramSets[paramSetName])); // If a parameter set is not specified for a parmeter, then the parameter belongs to all the parameter sets, // therefore if this is not the AllParameterSets Set then add all parameters from the AllParameterSets Set to it... if (string.Compare(paramSetName, ParameterAttribute.AllParameterSets) != 0 && paramSets.ContainsKey(ParameterAttribute.AllParameterSets)) { foreach (CommandParameterInfo cpi in paramSets[ParameterAttribute.AllParameterSets]) { paramSets[paramSetName].Add(cpi); } } } ParameterSets = new ReadOnlyCollection <CommandParameterSetInfo>(paramSetInfo); }