/// <summary>
        /// Gets the parameter set with the given name if it exists on the cmdlet,
        /// otherwise creates a new parameter set and adds it to the cmdlet.
        /// </summary>
        /// <param name="cmdlet">The cmdlet</param>
        /// <param name="parameterSetName">The name of the parameter set</param>
        /// <returns>The parameter set that was either retrieved or created</returns>
        public static CmdletParameterSet GetOrCreateParameterSet(this Cmdlet cmdlet, string parameterSetName)
        {
            if (parameterSetName == null)
            {
                throw new ArgumentNullException(nameof(parameterSetName));
            }

            // Create the parameter set if it doesn't already exist
            CmdletParameterSet parameterSet = cmdlet.ParameterSets.Get(parameterSetName);

            if (parameterSet == null)
            {
                parameterSet = new CmdletParameterSet(parameterSetName);
                cmdlet.ParameterSets.Add(parameterSet);
            }

            return(parameterSet);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Create the processor for adding parameters to a cmdlet.
        /// </summary>
        /// <param name="cmdlet">The cmdlet</param>
        /// <param name="baseType">The type for which we should add parameters</param>
        /// <param name="addSwitchParametersForAbstractTypes">Whether or not to create a switch parameter for abstract types</param>
        /// <param name="sharedParameterSetName">
        /// The name of the shared parameter set, or null if parameters shouldn't be added to the shared parameter set
        /// </param>
        public static void AddParametersForEntityProperties(
            this Cmdlet cmdlet,
            OdcmType baseType,
            Func <OdcmProperty, bool> isReadOnlyFunc,
            string sharedParameterSetName         = null,
            bool addSwitchParameters              = true,
            bool markAsPowerShellParameter        = true,
            bool setBaseTypeParameterSetAsDefault = false,
            bool allowPipelineInputByName         = true)
        {
            if (cmdlet == null)
            {
                throw new ArgumentNullException(nameof(cmdlet));
            }
            if (baseType == null)
            {
                throw new ArgumentNullException(nameof(baseType));
            }
            if (isReadOnlyFunc == null)
            {
                throw new ArgumentNullException(nameof(isReadOnlyFunc));
            }

            // Don't try to add parameters for Edm types
            if (baseType.Namespace.Name.StartsWith("Edm"))
            {
                return;
            }

            // Track parameters as we visit each type
            // C# is case sensitive whereas PowerShell is not, so we need to use case-insensitive comparisons when deduping
            IDictionary <OdcmType, IEnumerable <string> > parameterNameLookup = new Dictionary <OdcmType, IEnumerable <string> >();
            IDictionary <string, CmdletParameter>         parameterLookup     = new Dictionary <string, CmdletParameter>(StringComparer.OrdinalIgnoreCase);

            // Visit all derived types
            baseType.VisitAllDerivedTypes((OdcmClass @class) =>
            {
                string parameterName    = @class.Name;
                string parameterSetName = @class.FullName;

                // Determine if this is the only entity type for this cmdlet
                bool isTheOnlyType = (@class == baseType && [email protected]().Any());

                // Create the parameter set for this type if it doesn't already exist
                CmdletParameterSet parameterSet = cmdlet.GetOrCreateParameterSet(parameterSetName);

                // Set this as the default parameter set if it's the only type
                if ((setBaseTypeParameterSetAsDefault && @class == baseType) ||
                    (isTheOnlyType && markAsPowerShellParameter))
                {
                    cmdlet.DefaultParameterSetName = parameterSet.Name;
                }

                // Add a switch parameter for this type if required
                if (addSwitchParameters &&
                    [email protected] && // don't add a switch for abstract types
                    !isTheOnlyType)    // if there is only 1 type, don't add a switch parameter for it
                {
                    // Add the switch parameter
                    parameterSet.Add(new CmdletParameter(parameterName, typeof(PS.SwitchParameter))
                    {
                        Mandatory = true,
                        ParameterSetSelectorName        = parameterSetName,
                        ValueFromPipelineByPropertyName = false,
                        Documentation = new CmdletParameterDocumentation()
                        {
                            Descriptions = new string[]
                            {
                                $"A switch parameter for selecting the parameter set which corresponds to the \"{@class.FullName}\" type.",
                            },
                        },
                    });
                }

                // Evaluate the properties on this type
                IEnumerable <OdcmProperty> properties = @class.EvaluateProperties(@class == baseType)
                                                        .Where(prop => prop.Name != RequestProperties.Id);

                // Add this type into the parmeter name lookup table
                parameterNameLookup.Add(@class, properties
                                        //.Where(prop => !prop.ReadOnly && !prop.IsCollection && !prop.IsLink)
                                        .Select(prop => prop.Name)
                                        .Distinct());

                // Add the base types' properties as parameters to this parameter set
                // NOTE: Safe lookups are not necessary since all base types are guaranteed to have already been processed
                // by the VisitDerivedTypes() method
                OdcmType currentType = @class;
                while (currentType != baseType)
                {
                    // Get the next type
                    currentType = currentType.GetBaseType();

                    // Lookup the properties for this type
                    IEnumerable <string> parameterNames = parameterNameLookup[currentType];

                    // Lookup the CmdletParameter objects for each parameter name
                    IEnumerable <CmdletParameter> parameters = parameterNames.Select(paramName => parameterLookup[paramName]);

                    // Add the parameters to the parameter set
                    parameterSet.AddAll(parameters);
                }

                // Iterate over properties
                foreach (OdcmProperty property in properties)
                {
                    // Get the PowerShell type for this property from the Edm type
                    Type propertyType = property.Type.ToPowerShellType(property.IsCollection);

                    // Create the parameter for this property if it doesn't already exist
                    if (!parameterLookup.TryGetValue(property.Name, out CmdletParameter parameter))
                    {
                        // Get the valid values if it is an enum
                        IEnumerable <string> enumMembers = null;
                        if (markAsPowerShellParameter && property.Type is OdcmEnum @enum)
                        {
                            enumMembers = @enum.Members.Select(enumMember => enumMember.Name);
                        }

                        parameter = CreateEntityParameter(
                            property,
                            propertyType,
                            markAsPowerShellParameter,
                            @class == baseType,
                            @class.FullName,
                            isReadOnly: isReadOnlyFunc(property),
                            allowPipelineInputByName: allowPipelineInputByName,
                            enumValues: enumMembers);

                        parameterLookup.Add(property.Name, parameter);
                    }
                    else if (propertyType != parameter.Type)
                    {
                        // If all uses of this parameter don't use the same type, default to System.Object
                        parameter = CreateEntityParameter(
                            property,
                            typeof(object),
                            markAsPowerShellParameter,
                            @class == baseType,
                            @class.FullName,
                            isReadOnly: isReadOnlyFunc(property),
                            allowPipelineInputByName: allowPipelineInputByName);

                        parameterLookup[property.Name] = parameter;
                    }

                    // Save the original OData type name
                    parameter.ODataTypeFullName = property.Type.FullName;

                    // Save the names of the subtypes of the original OData type
                    parameter.ODataSubTypeFullNames = property.Type.GetAllDerivedTypes().Select(type => type.FullName);

                    // Add this type's properties as parameters to this parameter set
                    parameterSet.Add(parameter);
                }
            });

            // Get/create the shared parameter set if required (e.g. the "Post" parameter set for the "Create" cmdlet)
            if (sharedParameterSetName != null)
            {
                // Create the parameter set if it doesn't already exist
                CmdletParameterSet sharedParameterSet = cmdlet.GetOrCreateParameterSet(sharedParameterSetName);

                // All properties should be part of the shared parameter set
                sharedParameterSet.AddAll(parameterLookup.Values);
            }
        }