Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ParameterBinderController.cs1327 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Diagnostics;7using System.Globalization;8using System.Management.Automation.Language;9using System.Text;10 11namespace System.Management.Automation12{13    /// <summary>14    /// The base class for the parameter binder controllers. This class and15    /// its derived classes control the interaction between the command processor16    /// and the parameter binder(s). It holds the state of the arguments and parameters.17    /// </summary>18    [DebuggerDisplay("InvocationInfo = {InvocationInfo}")]19    internal abstract class ParameterBinderController20    {21        #region ctor22 23        /// <summary>24        /// Constructs a parameter binder controller for the specified command25        /// in the specified engine context.26        /// </summary>27        /// <param name="invocationInfo">28        ///     The invocation information about the code being run.29        /// </param>30        /// <param name="context">31        ///     The engine context in which the command is being run.32        /// </param>33        /// <param name="parameterBinder">34        ///     The default parameter binder for the command.35        /// </param>36        internal ParameterBinderController(InvocationInfo invocationInfo, ExecutionContext context, ParameterBinderBase parameterBinder)37        {38            Diagnostics.Assert(invocationInfo != null, "Caller to verify invocationInfo is not null.");39            Diagnostics.Assert(parameterBinder != null, "Caller to verify parameterBinder is not null.");40            Diagnostics.Assert(context != null, "call to verify context is not null.");41 42            this.DefaultParameterBinder = parameterBinder;43            Context = context;44            InvocationInfo = invocationInfo;45        }46 47        #endregion ctor48 49        #region internal_members50 51        /// <summary>52        /// The engine context the command is running in.53        /// </summary>54        internal ExecutionContext Context { get; }55 56        /// <summary>57        /// Gets the parameter binder for the command.58        /// </summary>59        internal ParameterBinderBase DefaultParameterBinder { get; }60 61        /// <summary>62        /// The invocation information about the code being run.63        /// </summary>64        internal InvocationInfo InvocationInfo { get; }65 66        /// <summary>67        /// All the metadata associated with any of the parameters that68        /// are available from the command.69        /// </summary>70        internal MergedCommandParameterMetadata BindableParameters71        {72            get { return _bindableParameters; }73        }74 75        protected MergedCommandParameterMetadata _bindableParameters = new MergedCommandParameterMetadata();76 77        /// <summary>78        /// A list of the unbound parameters for the command.79        /// </summary>80        protected List<MergedCompiledCommandParameter> UnboundParameters { get; set; }81 82        /// <summary>83        /// A collection of the bound parameters for the command. The collection is84        /// indexed based on the name of the parameter.85        /// </summary>86        protected Dictionary<string, MergedCompiledCommandParameter> BoundParameters { get; } = new Dictionary<string, MergedCompiledCommandParameter>(StringComparer.OrdinalIgnoreCase);87 88        internal CommandLineParameters CommandLineParameters89        {90            get { return this.DefaultParameterBinder.CommandLineParameters; }91        }92 93        /// <summary>94        /// Set true if the default parameter binding is in use.95        /// </summary>96        protected bool DefaultParameterBindingInUse { get; set; } = false;97 98        // Set true if the default parameter values are applied99 100        /// <summary>101        /// A collection of bound default parameters.102        /// </summary>103        protected Collection<string> BoundDefaultParameters { get; } = new Collection<string>();104 105        // Keep record of the bound default parameters106 107        /// <summary>108        /// A collection of the unbound arguments.109        /// </summary>110        /// <value></value>111        protected Collection<CommandParameterInternal> UnboundArguments { get; set; } = new Collection<CommandParameterInternal>();112 113        internal void ClearUnboundArguments()114        {115            UnboundArguments.Clear();116        }117 118        /// <summary>119        /// A collection of the arguments that have been bound.120        /// </summary>121        protected Dictionary<string, CommandParameterInternal> BoundArguments { get; } = new Dictionary<string, CommandParameterInternal>(StringComparer.OrdinalIgnoreCase);122 123        /// <summary>124        /// Reparses the unbound arguments using the parameter metadata of the125        /// specified parameter binder as the parsing guide.126        /// </summary>127        /// <exception cref="ParameterBindingException">128        /// If a parameter token is not matched with an argument and its not a bool or129        /// SwitchParameter.130        /// Or131        /// The name of the argument matches more than one parameter.132        /// </exception>133        protected void ReparseUnboundArguments()134        {135            Collection<CommandParameterInternal> result = new Collection<CommandParameterInternal>();136 137            for (int index = 0; index < UnboundArguments.Count; ++index)138            {139                CommandParameterInternal argument = UnboundArguments[index];140 141                // If the parameter name is not specified, or if it is specified _and_ there is an142                // argument, we have nothing to reparse for this argument.143                if (!argument.ParameterNameSpecified || argument.ArgumentSpecified)144                {145                    result.Add(argument);146                    continue;147                }148 149                Diagnostics.Assert(argument.ParameterNameSpecified && !argument.ArgumentSpecified,150                    "At this point, we only process parameters with no arguments");151 152                // Now check the argument name with the binder.153 154                string parameterName = argument.ParameterName;155                MergedCompiledCommandParameter matchingParameter =156                    _bindableParameters.GetMatchingParameter(157                        parameterName,158                        false,159                        true,160                        new InvocationInfo(this.InvocationInfo.MyCommand, argument.ParameterExtent));161 162                if (matchingParameter == null)163                {164                    // Since we couldn't find a match, just add the argument as it was165                    // and continue166                    result.Add(argument);167                    continue;168                }169 170                // Now that we know we have a single match for the parameter name,171                // see if we can figure out what the argument value for the parameter is.172 173                // If its a bool or switch parameter, then set the value to true and continue174 175                if (IsSwitchAndSetValue(parameterName, argument, matchingParameter.Parameter))176                {177                    result.Add(argument);178                    continue;179                }180 181                // Since it's not a bool or a SwitchParameter we need to check the next182                // argument.183 184                if (UnboundArguments.Count - 1 > index)185                {186                    CommandParameterInternal nextArgument = UnboundArguments[index + 1];187 188                    // Since the argument appears to be a valid parameter, check the189                    // next argument to see if it is the value for that parameter190 191                    if (nextArgument.ParameterNameSpecified)192                    {193                        // Since we have a valid parameter we need to see if the next argument is194                        // an argument value for that parameter or a parameter itself.195 196                        MergedCompiledCommandParameter nextMatchingParameter =197                            _bindableParameters.GetMatchingParameter(198                                nextArgument.ParameterName,199                                false,200                                true,201                                new InvocationInfo(this.InvocationInfo.MyCommand, nextArgument.ParameterExtent));202 203                        if ((nextMatchingParameter != null) || nextArgument.ParameterAndArgumentSpecified)204                        {205                            // Since the next argument is a valid parameter that means the current206                            // argument doesn't have a value207 208                            // It is an error to have an argument that is a parameter name209                            // but doesn't have a value210 211                            ParameterBindingException exception =212                                new ParameterBindingException(213                                    ErrorCategory.InvalidArgument,214                                    this.InvocationInfo,215                                    GetParameterErrorExtent(argument),216                                    matchingParameter.Parameter.Name,217                                    matchingParameter.Parameter.Type,218                                    null,219                                    ParameterBinderStrings.MissingArgument,220                                    "MissingArgument");221 222                            throw exception;223                        }224 225                        ++index;226                        argument.ParameterName = matchingParameter.Parameter.Name;227                        argument.SetArgumentValue(nextArgument.ArgumentAst, nextArgument.ParameterText);228                        result.Add(argument);229                        continue;230                    }231 232                    // The next argument appears to be the value for this parameter. Set the value,233                    // increment the index and continue234 235                    ++index;236                    argument.ParameterName = matchingParameter.Parameter.Name;237                    argument.SetArgumentValue(nextArgument.ArgumentAst, nextArgument.ArgumentValue);238                    result.Add(argument);239                }240                else241                {242                    // It is an error to have a argument that is a parameter name243                    // but doesn't have a value244 245                    ParameterBindingException exception =246                        new ParameterBindingException(247                            ErrorCategory.InvalidArgument,248                            this.InvocationInfo,249                            GetParameterErrorExtent(argument),250                            matchingParameter.Parameter.Name,251                            matchingParameter.Parameter.Type,252                            null,253                            ParameterBinderStrings.MissingArgument,254                            "MissingArgument");255 256                    throw exception;257                }258            }259 260            UnboundArguments = result;261        }262 263        protected void InitUnboundArguments(Collection<CommandParameterInternal> arguments)264        {265            // Add the passed in arguments to the unboundArguments collection266            Collection<CommandParameterInternal> paramsFromSplatting = null;267            foreach (CommandParameterInternal argument in arguments)268            {269                if (argument.FromHashtableSplatting)270                {271                    paramsFromSplatting ??= new Collection<CommandParameterInternal>();272                    paramsFromSplatting.Add(argument);273                }274                else275                {276                    UnboundArguments.Add(argument);277                }278            }279 280            // Move the arguments from hashtable splatting to the end of the unbound args list, so that281            // the explicitly specified named arguments can supersede those from a hashtable splatting.282            if (paramsFromSplatting != null)283            {284                foreach (CommandParameterInternal argument in paramsFromSplatting)285                {286                    UnboundArguments.Add(argument);287                }288            }289        }290 291        private static bool IsSwitchAndSetValue(292            string argumentName,293            CommandParameterInternal argument,294            CompiledCommandParameter matchingParameter)295        {296            bool result = false;297 298            if (matchingParameter.Type == typeof(SwitchParameter))299            {300                argument.ParameterName = argumentName;301                argument.SetArgumentValue(null, SwitchParameter.Present);302                result = true;303            }304 305            return result;306        }307 308        /// <summary>309        /// The argument looks like a parameter if it is a string310        /// and starts with a dash.311        /// </summary>312        /// <param name="arg">313        /// The argument to check.314        /// </param>315        /// <returns>316        /// True if the argument is a string and starts with a dash,317        /// or false otherwise.318        /// </returns>319        internal static bool ArgumentLooksLikeParameter(string arg)320        {321            bool result = false;322 323            if (!string.IsNullOrEmpty(arg))324            {325                result = arg[0].IsDash();326            }327 328            return result;329        }330 331        /// <summary>332        /// Reparses the arguments specified in the object[] and generates CommandParameterInternal instances333        /// based on whether the arguments look like parameters. The CommandParameterInternal instances then334        /// get added to the specified command processor.335        /// </summary>336        /// <param name="commandProcessor">337        /// The command processor instance to add the reparsed parameters to.338        /// </param>339        /// <param name="arguments">340        /// The arguments that require reparsing.341        /// </param>342        internal static void AddArgumentsToCommandProcessor(CommandProcessorBase commandProcessor, object[] arguments)343        {344            if ((arguments != null) && (arguments.Length > 0))345            {346                PSBoundParametersDictionary boundParameters = arguments[0] as PSBoundParametersDictionary;347                if ((boundParameters != null) && (arguments.Length == 1))348                {349                    // If they are supplying a dictionary of parameters, use those directly350                    foreach (KeyValuePair<string, object> boundParameter in boundParameters)351                    {352                        CommandParameterInternal param = CommandParameterInternal.CreateParameterWithArgument(353                            /*parameterAst*/null, boundParameter.Key, boundParameter.Key,354                            /*argumentAst*/null, boundParameter.Value, false);355                        commandProcessor.AddParameter(param);356                    }357                }358                else359                {360                    // Otherwise, we need to parse them ourselves361                    for (int argIndex = 0; argIndex < arguments.Length; ++argIndex)362                    {363                        CommandParameterInternal param;364                        string paramText = arguments[argIndex] as string;365                        if (ArgumentLooksLikeParameter(paramText))366                        {367                            // The argument looks like a parameter.368                            // Create a parameter with argument if the paramText is like this: -Path:c:\windows369                            // Combine it with the next argument if there is an argument, and the parameter ends in ':'.370 371                            var colonIndex = paramText.IndexOf(':');372                            if (colonIndex != -1 && colonIndex != paramText.Length - 1)373                            {374                                param = CommandParameterInternal.CreateParameterWithArgument(375                                    /*parameterAst*/null, paramText.Substring(1, colonIndex - 1), paramText,376                                    /*argumentAst*/null, paramText.AsSpan(colonIndex + 1).Trim().ToString(),377                                    false);378                            }379                            else if (argIndex == arguments.Length - 1 || paramText[paramText.Length - 1] != ':')380                            {381                                param = CommandParameterInternal.CreateParameter(382                                    paramText.Substring(1), paramText);383                            }384                            else385                            {386                                param = CommandParameterInternal.CreateParameterWithArgument(387                                    /*parameterAst*/null, paramText.Substring(1, paramText.Length - 2), paramText,388                                    /*argumentAst*/null, arguments[argIndex + 1],389                                    false);390                                argIndex++;391                            }392                        }393                        else394                        {395                            param = CommandParameterInternal.CreateArgument(arguments[argIndex]);396                        }397 398                        commandProcessor.AddParameter(param);399                    }400                }401            }402        }403 404        /// <summary>405        /// Bind the argument to the specified parameter.406        /// </summary>407        /// <param name="argument">408        /// The argument to be bound.409        /// </param>410        /// <param name="flags">411        /// The flags for type coercion, validation, and script block binding.412        /// </param>413        /// <returns>414        /// True if the parameter was successfully bound. False if <paramref name="flags"/> does not have the415        /// flag <see>ParameterBindingFlags.ShouldCoerceType</see> and the type does not match the parameter type.416        /// </returns>417        /// <exception cref="ParameterBindingException">418        /// If argument transformation fails.419        /// or420        /// The argument could not be coerced to the appropriate type for the parameter.421        /// or422        /// The parameter argument transformation, prerequisite, or validation failed.423        /// or424        /// If the binding to the parameter fails.425        /// or426        /// The parameter has already been bound.427        /// </exception>428        internal virtual bool BindParameter(429            CommandParameterInternal argument,430            ParameterBindingFlags flags)431        {432            bool result = false;433 434            MergedCompiledCommandParameter matchingParameter =435                BindableParameters.GetMatchingParameter(436                    argument.ParameterName,437                    (flags & ParameterBindingFlags.ThrowOnParameterNotFound) != 0,438                    true,439                    new InvocationInfo(this.InvocationInfo.MyCommand, argument.ParameterExtent));440 441            if (matchingParameter != null)442            {443                // Now check to make sure it hasn't already been444                // bound by looking in the boundParameters collection445 446                if (BoundParameters.ContainsKey(matchingParameter.Parameter.Name))447                {448                    ParameterBindingException bindingException =449                        new ParameterBindingException(450                            ErrorCategory.InvalidArgument,451                            this.InvocationInfo,452                            GetParameterErrorExtent(argument),453                            argument.ParameterName,454                            null,455                            null,456                            ParameterBinderStrings.ParameterAlreadyBound,457                            nameof(ParameterBinderStrings.ParameterAlreadyBound));458 459                    throw bindingException;460                }461 462                flags &= ~ParameterBindingFlags.DelayBindScriptBlock;463                result = BindParameter(_currentParameterSetFlag, argument, matchingParameter, flags);464            }465 466            return result;467        }468 469        /// <summary>470        /// Derived classes need to define the binding of multiple arguments.471        /// </summary>472        /// <param name="parameters">473        /// The arguments to be bound.474        /// </param>475        /// <returns>476        /// The arguments which are still not bound.477        /// </returns>478        internal virtual Collection<CommandParameterInternal> BindParameters(Collection<CommandParameterInternal> parameters)479        {480            throw new NotImplementedException();481        }482 483        /// <summary>484        /// Bind the argument to the specified parameter.485        /// </summary>486        /// <param name="parameterSets">487        /// The parameter set used to bind the arguments.488        /// </param>489        /// <param name="argument">490        /// The argument to be bound.491        /// </param>492        /// <param name="parameter">493        /// The metadata for the parameter to bind the argument to.494        /// </param>495        /// <param name="flags">496        /// Flags for type coercion and validation of the arguments.497        /// </param>498        /// <returns>499        /// True if the parameter was successfully bound. False if <paramref name="flags"/>500        /// specifies no type coercion and the type does not match the parameter type.501        /// </returns>502        /// <exception cref="ArgumentNullException">503        /// If <paramref name="parameter"/> or <paramref name="argument"/> is null.504        /// </exception>505        /// <exception cref="ParameterBindingException">506        /// If argument transformation fails.507        /// or508        /// The argument could not be coerced to the appropriate type for the parameter.509        /// or510        /// The parameter argument transformation, prerequisite, or validation failed.511        /// or512        /// If the binding to the parameter fails.513        /// </exception>514        internal virtual bool BindParameter(515            uint parameterSets,516            CommandParameterInternal argument,517            MergedCompiledCommandParameter parameter,518            ParameterBindingFlags flags)519        {520            bool result = false;521 522            switch (parameter.BinderAssociation)523            {524                case ParameterBinderAssociation.DeclaredFormalParameters:525                    result =526                        this.DefaultParameterBinder.BindParameter(527                            argument,528                            parameter.Parameter,529                            flags);530                    break;531 532                default:533                    Diagnostics.Assert(534                        false,535                        "Only the formal parameters are available for this type of command");536                    break;537            }538 539            if (result && ((flags & ParameterBindingFlags.IsDefaultValue) == 0))540            {541                UnboundParameters.Remove(parameter);542                BoundParameters.Add(parameter.Parameter.Name, parameter);543            }544 545            return result;546        }547 548        /// <summary>549        /// This is used by <see cref="BindNamedParameters"/> to validate and bind a given named parameter.550        /// </summary>551        protected virtual void BindNamedParameter(552            uint parameterSets,553            CommandParameterInternal argument,554            MergedCompiledCommandParameter parameter)555        {556            BindParameter(parameterSets, argument, parameter, ParameterBindingFlags.ShouldCoerceType);557        }558 559        /// <summary>560        /// Bind the named parameters from the specified argument collection,561        /// for only the parameters in the specified parameter set.562        /// </summary>563        /// <param name="parameterSets">564        /// The parameter set used to bind the arguments.565        /// </param>566        /// <param name="arguments">567        /// The arguments that should be attempted to bind to the parameters of the specified parameter binder.568        /// </param>569        /// <exception cref="ParameterBindingException">570        /// if multiple parameters are found matching the name.571        /// or572        /// if no match could be found.573        /// or574        /// If argument transformation fails.575        /// or576        /// The argument could not be coerced to the appropriate type for the parameter.577        /// or578        /// The parameter argument transformation, prerequisite, or validation failed.579        /// or580        /// If the binding to the parameter fails.581        /// </exception>582        protected Collection<CommandParameterInternal> BindNamedParameters(uint parameterSets, Collection<CommandParameterInternal> arguments)583        {584            Collection<CommandParameterInternal> result = new Collection<CommandParameterInternal>();585            HashSet<string> boundExplicitNamedParams = null;586 587            foreach (CommandParameterInternal argument in arguments)588            {589                if (!argument.ParameterNameSpecified)590                {591                    result.Add(argument);592                    continue;593                }594 595                // We don't want to throw an exception yet because the parameter might be a positional argument,596                // or in case of a cmdlet or an advanced function, it might match up to a dynamic parameter.597                MergedCompiledCommandParameter parameter =598                    BindableParameters.GetMatchingParameter(599                        name: argument.ParameterName,600                        throwOnParameterNotFound: false,601                        tryExactMatching: true,602                        invocationInfo: new InvocationInfo(this.InvocationInfo.MyCommand, argument.ParameterExtent));603 604                // If the parameter is not in the specified parameter set, throw a binding exception605                if (parameter != null)606                {607                    string formalParamName = parameter.Parameter.Name;608 609                    if (argument.FromHashtableSplatting)610                    {611                        boundExplicitNamedParams ??= new HashSet<string>(612                            BoundParameters.Keys,613                            StringComparer.OrdinalIgnoreCase);614 615                        if (boundExplicitNamedParams.Contains(formalParamName))616                        {617                            // This named parameter from splatting is also explicitly specified by the user,618                            // which was successfully bound, so we ignore the one from splatting because it619                            // is superseded by the explicit one. For example:620                            //   $splat = @{ Path = $path1 }621                            //   dir @splat -Path $path2622                            continue;623                        }624                    }625 626                    // Now check to make sure it hasn't already been627                    // bound by looking in the boundParameters collection628 629                    if (BoundParameters.ContainsKey(formalParamName))630                    {631                        ParameterBindingException bindingException =632                            new ParameterBindingException(633                                ErrorCategory.InvalidArgument,634                                this.InvocationInfo,635                                GetParameterErrorExtent(argument),636                                argument.ParameterName,637                                null,638                                null,639                                ParameterBinderStrings.ParameterAlreadyBound,640                                nameof(ParameterBinderStrings.ParameterAlreadyBound));641 642                        throw bindingException;643                    }644 645                    BindNamedParameter(parameterSets, argument, parameter);646                }647                else if (argument.ParameterName.Equals(Parser.VERBATIM_PARAMETERNAME, StringComparison.Ordinal))648                {649                    // We sometimes send a magic parameter from a remote machine with the values referenced via650                    // a using expression ($using:x).  We then access these values via PSBoundParameters, so651                    // "bind" them here.652                    DefaultParameterBinder.CommandLineParameters.SetImplicitUsingParameters(argument.ArgumentValue);653                }654                else655                {656                    result.Add(argument);657                }658            }659 660            return result;661        }662 663        /// <summary>664        /// Binds the unbound arguments to positional parameters.665        /// </summary>666        /// <param name="unboundArguments">667        /// The unbound arguments to attempt to bind as positional arguments.668        /// </param>669        /// <param name="validParameterSets">670        /// The current parameter set flags that are valid.671        /// </param>672        /// <param name="defaultParameterSet">673        /// The parameter set to use to disambiguate parameters that have the same position674        /// </param>675        /// <param name="outgoingBindingException">676        /// Returns the underlying parameter binding exception if any was generated.677        /// </param>678        /// <returns>679        /// The remaining arguments that have not been bound.680        /// </returns>681        /// <remarks>682        /// It is assumed that the unboundArguments parameter has already been processed683        /// for this parameter binder. All named parameters have been paired with their684        /// values. Any arguments that don't have a name are considered positional and685        /// will be processed in this method.686        /// </remarks>687        /// <exception cref="ParameterBindingException">688        /// If multiple parameters were found for the same position in the specified689        /// parameter set.690        /// or691        /// If argument transformation fails.692        /// or693        /// The argument could not be coerced to the appropriate type for the parameter.694        /// or695        /// The parameter argument transformation, prerequisite, or validation failed.696        /// or697        /// If the binding to the parameter fails.698        /// </exception>699        internal Collection<CommandParameterInternal> BindPositionalParameters(700            Collection<CommandParameterInternal> unboundArguments,701            uint validParameterSets,702            uint defaultParameterSet,703            out ParameterBindingException outgoingBindingException704            )705        {706            Collection<CommandParameterInternal> result = new Collection<CommandParameterInternal>();707            outgoingBindingException = null;708 709            if (unboundArguments.Count > 0)710            {711                // Create a new collection to iterate over so that we can remove712                // unbound arguments while binding them.713 714                List<CommandParameterInternal> unboundArgumentsCollection = new List<CommandParameterInternal>(unboundArguments);715 716                // Get a sorted dictionary of the positional parameters with the position717                // as the key718 719                SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>> positionalParameterDictionary;720 721                try722                {723                    positionalParameterDictionary =724                        EvaluateUnboundPositionalParameters(UnboundParameters, _currentParameterSetFlag);725                }726                catch (InvalidOperationException)727                {728                    // The parameter set declaration is ambiguous so729                    // throw an exception.730 731                    ParameterBindingException bindingException =732                        new ParameterBindingException(733                            ErrorCategory.InvalidArgument,734                            this.InvocationInfo,735                            null,736                            null,737                            null,738                            null,739                            ParameterBinderStrings.AmbiguousPositionalParameterNoName,740                            "AmbiguousPositionalParameterNoName");741 742                    // This exception is thrown because the binder found two positional parameters743                    // from the same parameter set with the same position defined. This is not caused744                    // by introducing the default parameter binding.745                    throw bindingException;746                }747 748                if (positionalParameterDictionary.Count > 0)749                {750                    int unboundArgumentsIndex = 0;751 752                    foreach (Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> nextPositionalParameters in positionalParameterDictionary.Values)753                    {754                        // Only continue if there are parameters at the specified position. Parameters755                        // can be removed as the parameter set gets narrowed down.756 757                        if (nextPositionalParameters.Count == 0)758                        {759                            continue;760                        }761 762                        CommandParameterInternal argument = GetNextPositionalArgument(763                            unboundArgumentsCollection,764                            result,765                            ref unboundArgumentsIndex);766 767                        if (argument == null)768                        {769                            break;770                        }771 772                        // Bind first to defaultParameterSet without type coercion, then to773                        // other sets without type coercion, then to the defaultParameterSet with774                        // type coercion and finally to the other sets with type coercion.775 776                        bool aParameterWasBound = false;777                        if (defaultParameterSet != 0 && (validParameterSets & defaultParameterSet) != 0)778                        {779                            // Favor the default parameter set.780                            // First try without type coercion781 782                            aParameterWasBound =783                                BindPositionalParametersInSet(784                                    defaultParameterSet,785                                    nextPositionalParameters,786                                    argument,787                                    ParameterBindingFlags.DelayBindScriptBlock,788                                    out outgoingBindingException);789                        }790 791                        if (!aParameterWasBound)792                        {793                            // Try the non-default parameter sets794                            // without type coercion.795 796                            aParameterWasBound =797                                BindPositionalParametersInSet(798                                    validParameterSets,799                                    nextPositionalParameters,800                                    argument,801                                    ParameterBindingFlags.DelayBindScriptBlock,802                                    out outgoingBindingException);803                        }804 805                        if (!aParameterWasBound)806                        {807                            // Now try the default parameter set with type coercion808                            if (defaultParameterSet != 0 && (validParameterSets & defaultParameterSet) != 0)809                            {810                                // Favor the default parameter set.811                                // First try without type coercion812 813                                aParameterWasBound =814                                    BindPositionalParametersInSet(815                                        defaultParameterSet,816                                        nextPositionalParameters,817                                        argument,818                                        ParameterBindingFlags.ShouldCoerceType | ParameterBindingFlags.DelayBindScriptBlock,819                                        out outgoingBindingException);820                            }821                        }822 823                        if (!aParameterWasBound)824                        {825                            // Try the non-default parameter sets826                            // with type coercion.827 828                            aParameterWasBound =829                                BindPositionalParametersInSet(830                                    validParameterSets,831                                    nextPositionalParameters,832                                    argument,833                                    ParameterBindingFlags.ShouldCoerceType | ParameterBindingFlags.DelayBindScriptBlock,834                                    out outgoingBindingException);835                        }836 837                        if (!aParameterWasBound)838                        {839                            // Add the unprocessed argument to the results and continue840                            result.Add(argument);841                        }842                        else843                        {844                            // Update the parameter sets if necessary845                            if (validParameterSets != _currentParameterSetFlag)846                            {847                                validParameterSets = _currentParameterSetFlag;848                                UpdatePositionalDictionary(positionalParameterDictionary, validParameterSets);849                            }850                        }851                    }852 853                    // Now for any arguments that were not processed, add them to854                    // the result855 856                    for (int index = unboundArgumentsIndex; index < unboundArgumentsCollection.Count; ++index)857                    {858                        result.Add(unboundArgumentsCollection[index]);859                    }860                }861                else862                {863                    // Since no positional parameters were found, add the arguments864                    // to the result865 866                    result = unboundArguments;867                }868            }869 870            return result;871        }872 873        /// <summary>874        /// This method only updates the collections contained in the dictionary, not the dictionary875        /// itself to contain only the parameters that are in the specified parameter set.876        /// </summary>877        /// <param name="positionalParameterDictionary">878        /// The sorted dictionary of positional parameters.879        /// </param>880        /// <param name="validParameterSets">881        /// Valid parameter sets882        /// </param>883        internal static void UpdatePositionalDictionary(884            SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>> positionalParameterDictionary,885            uint validParameterSets)886        {887            foreach (Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> parameterCollection in positionalParameterDictionary.Values)888            {889                Collection<MergedCompiledCommandParameter> paramToRemove = new Collection<MergedCompiledCommandParameter>();890 891                foreach (PositionalCommandParameter positionalParameter in parameterCollection.Values)892                {893                    Collection<ParameterSetSpecificMetadata> parameterSetData = positionalParameter.ParameterSetData;894 895                    for (int index = parameterSetData.Count - 1; index >= 0; --index)896                    {897                        if ((parameterSetData[index].ParameterSetFlag & validParameterSets) == 0 &&898                            !parameterSetData[index].IsInAllSets)899                        {900                            // The parameter is not in the valid parameter sets so remove it from the collection.901                            parameterSetData.RemoveAt(index);902                        }903                    }904 905                    if (parameterSetData.Count == 0)906                    {907                        paramToRemove.Add(positionalParameter.Parameter);908                    }909                }910 911                // Now remove all the parameters that no longer have parameter set data912                foreach (MergedCompiledCommandParameter removeParam in paramToRemove)913                {914                    parameterCollection.Remove(removeParam);915                }916            }917        }918 919        private bool BindPositionalParametersInSet(920            uint validParameterSets,921            Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> nextPositionalParameters,922            CommandParameterInternal argument,923            ParameterBindingFlags flags,924            out ParameterBindingException bindingException925            )926        {927            bool result = false;928            bindingException = null;929 930            foreach (PositionalCommandParameter parameter in nextPositionalParameters.Values)931            {932                foreach (ParameterSetSpecificMetadata parameterSetData in parameter.ParameterSetData)933                {934                    // if the parameter is not in the specified parameter set, don't consider it935 936                    if ((validParameterSets & parameterSetData.ParameterSetFlag) == 0 &&937                        !parameterSetData.IsInAllSets)938                    {939                        continue;940                    }941 942                    bool bindResult = false;943                    string parameterName = parameter.Parameter.Parameter.Name;944 945                    ParameterBindingException parameterBindingExceptionToThrown = null;946                    try947                    {948                        CommandParameterInternal bindableArgument =949                            CommandParameterInternal.CreateParameterWithArgument(950                                /*parameterAst*/null, parameterName, "-" + parameterName + ":",951                                argument.ArgumentAst, argument.ArgumentValue,952                                false);953 954                        bindResult =955                            BindParameter(956                                validParameterSets,957                                bindableArgument,958                                parameter.Parameter,959                                flags);960                    }961                    catch (ParameterBindingArgumentTransformationException pbex)962                    {963                        parameterBindingExceptionToThrown = pbex;964                    }965                    catch (ParameterBindingValidationException pbex)966                    {967                        if (pbex.SwallowException)968                        {969                            // Just ignore and continue970                            bindResult = false;971                            bindingException = pbex;972                        }973                        else974                        {975                            parameterBindingExceptionToThrown = pbex;976                        }977                    }978                    catch (ParameterBindingParameterDefaultValueException pbex)979                    {980                        parameterBindingExceptionToThrown = pbex;981                    }982                    catch (ParameterBindingException e)983                    {984                        // Just ignore and continue;985                        bindResult = false;986                        bindingException = e;987                    }988 989                    if (parameterBindingExceptionToThrown != null)990                    {991                        if (!DefaultParameterBindingInUse)992                        {993                            throw parameterBindingExceptionToThrown;994                        }995                        else996                        {997                            ThrowElaboratedBindingException(parameterBindingExceptionToThrown);998                        }999                    }1000 1001                    if (bindResult)1002                    {1003                        result = true;1004                        this.CommandLineParameters.MarkAsBoundPositionally(parameterName);1005                        break;1006                    }1007                }1008            }1009 1010            return result;1011        }1012 1013        /// <summary>1014        /// Generate elaborated binding exception so that the user will know the default binding might cause the failure.1015        /// </summary>1016        /// <param name="pbex"></param>1017        protected void ThrowElaboratedBindingException(ParameterBindingException pbex)1018        {1019            if (pbex == null)1020            {1021                throw PSTraceSource.NewArgumentNullException(nameof(pbex));1022            }1023 1024            Diagnostics.Assert(pbex.ErrorRecord != null, "ErrorRecord should not be null in a ParameterBindingException");1025 1026            // Original error message1027            string oldMsg = pbex.Message;1028            // Default parameters get bound so far1029            StringBuilder defaultParamsGetBound = new StringBuilder();1030            foreach (string paramName in BoundDefaultParameters)1031            {1032                defaultParamsGetBound.Append(CultureInfo.InvariantCulture, $" -{paramName}");1033            }1034 1035            string resourceString = ParameterBinderStrings.DefaultBindingErrorElaborationSingle;1036            if (BoundDefaultParameters.Count > 1)1037            {1038                resourceString = ParameterBinderStrings.DefaultBindingErrorElaborationMultiple;1039            }1040 1041            ParameterBindingException newBindingException =1042                new ParameterBindingException(1043                    pbex.InnerException,1044                    pbex,1045                    resourceString,1046                    oldMsg, defaultParamsGetBound);1047 1048            throw newBindingException;1049        }1050 1051        private static CommandParameterInternal GetNextPositionalArgument(1052            List<CommandParameterInternal> unboundArgumentsCollection,1053            Collection<CommandParameterInternal> nonPositionalArguments,1054            ref int unboundArgumentsIndex)1055        {1056            // Find the next positional argument1057            // An argument without a name is considered to be positional since1058            // we are assuming the unboundArguments have been reparsed using1059            // the merged metadata from this parameter binder controller.1060 1061            CommandParameterInternal result = null;1062            while (unboundArgumentsIndex < unboundArgumentsCollection.Count)1063            {1064                CommandParameterInternal argument = unboundArgumentsCollection[unboundArgumentsIndex++];1065 1066                if (!argument.ParameterNameSpecified)1067                {1068                    result = argument;1069                    break;1070                }1071 1072                nonPositionalArguments.Add(argument);1073 1074                // Now check to see if the next argument needs to be consumed as well.1075 1076                if (unboundArgumentsCollection.Count - 1 >= unboundArgumentsIndex)1077                {1078                    argument = unboundArgumentsCollection[unboundArgumentsIndex];1079 1080                    if (!argument.ParameterNameSpecified)1081                    {1082                        // Since the next argument doesn't appear to be a parameter name1083                        // consume it as well.1084 1085                        nonPositionalArguments.Add(argument);1086                        unboundArgumentsIndex++;1087                    }1088                }1089            }1090 1091            return result;1092        }1093 1094        /// <summary>1095        /// Gets the unbound positional parameters in a sorted dictionary in the order of their1096        /// positions.1097        /// </summary>1098        /// <returns>1099        /// The sorted dictionary of MergedCompiledCommandParameter metadata with the position1100        /// as the key.1101        /// </returns>1102        internal static SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>> EvaluateUnboundPositionalParameters(1103            ICollection<MergedCompiledCommandParameter> unboundParameters, uint validParameterSetFlag)1104        {1105            SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>> result =1106                new SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>>();1107 1108            if (unboundParameters.Count > 0)1109            {1110                // Loop through the unbound parameters and find a parameter in the specified parameter set1111                // that has a position greater than or equal to the positionalParameterIndex1112 1113                foreach (MergedCompiledCommandParameter parameter in unboundParameters)1114                {1115                    bool isInParameterSet = (parameter.Parameter.ParameterSetFlags & validParameterSetFlag) != 0 || parameter.Parameter.IsInAllSets;1116 1117                    if (isInParameterSet)1118                    {1119                        var parameterSetDataCollection = parameter.Parameter.GetMatchingParameterSetData(validParameterSetFlag);1120                        foreach (ParameterSetSpecificMetadata parameterSetData in parameterSetDataCollection)1121                        {1122                            // Skip ValueFromRemainingArguments parameters1123                            if (parameterSetData.ValueFromRemainingArguments)1124                            {1125                                continue;1126                            }1127 1128                            // Check the position in the parameter set1129 1130                            int positionInParameterSet = parameterSetData.Position;1131 1132                            if (positionInParameterSet == int.MinValue)1133                            {1134                                // The parameter is not positional so go to the next one1135                                continue;1136                            }1137 1138                            AddNewPosition(result, positionInParameterSet, parameter, parameterSetData);1139                        }1140                    }1141                }1142            }1143 1144            return result;1145        }1146 1147        private static void AddNewPosition(1148            SortedDictionary<int, Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>> result,1149            int positionInParameterSet,1150            MergedCompiledCommandParameter parameter,1151            ParameterSetSpecificMetadata parameterSetData)1152        {1153            Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> positionalCommandParameters;1154            if (result.TryGetValue(positionInParameterSet, out positionalCommandParameters))1155            {1156                // Check to see if any of the other parameters in this position are in the same parameter set.1157                if (ContainsPositionalParameterInSet(positionalCommandParameters, parameter, parameterSetData.ParameterSetFlag))1158                {1159                    // Multiple parameters were found with the same1160                    // position. This means the parameter set is ambiguous.1161 1162                    // positional parameter could not be resolved1163 1164                    // We throw InvalidOperationException, which the1165                    // caller will catch and throw a more1166                    // appropriate exception.1167                    throw PSTraceSource.NewInvalidOperationException();1168                }1169 1170                PositionalCommandParameter positionalCommandParameter;1171                if (!positionalCommandParameters.TryGetValue(parameter, out positionalCommandParameter))1172                {1173                    positionalCommandParameter = new PositionalCommandParameter(parameter);1174                    positionalCommandParameters.Add(parameter, positionalCommandParameter);1175                }1176 1177                positionalCommandParameter.ParameterSetData.Add(parameterSetData);1178            }1179            else1180            {1181                Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> newPositionDictionary =1182                    new Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter>();1183 1184                PositionalCommandParameter newPositionalParameter = new PositionalCommandParameter(parameter);1185                newPositionalParameter.ParameterSetData.Add(parameterSetData);1186                newPositionDictionary.Add(parameter, newPositionalParameter);1187 1188                result.Add(positionInParameterSet, newPositionDictionary);1189            }1190        }1191 1192        private static bool ContainsPositionalParameterInSet(1193            Dictionary<MergedCompiledCommandParameter, PositionalCommandParameter> positionalCommandParameters,1194            MergedCompiledCommandParameter parameter,1195            uint parameterSet)1196        {1197            bool result = false;1198 1199            foreach (KeyValuePair<MergedCompiledCommandParameter, PositionalCommandParameter> pair in positionalCommandParameters)1200            {

Showing the first 1,200 of 1327 lines. Download the file for the rest.