Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
ParameterBinderBase.cs2068 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics;8using System.Diagnostics.CodeAnalysis;9using System.Globalization;10using System.Linq;11using System.Management.Automation.Internal;12using System.Management.Automation.Language;13using System.Reflection;14 15using Dbg = System.Management.Automation.Diagnostics;16 17namespace System.Management.Automation18{19    /// <summary>20    /// Flags.21    /// </summary>22    [Flags]23    internal enum ParameterBindingFlags24    {25        /// <summary>26        /// No flags specified.27        /// </summary>28        None = 0,29 30        /// <summary>31        /// Set when the argument should be converted to the parameter type.32        /// </summary>33        ShouldCoerceType = 0x01,34 35        /// <summary>36        /// Set when the argument should not be validated or recorded in BoundParameters.37        /// </summary>38        IsDefaultValue = 0x02,39 40        /// <summary>41        /// Set when script blocks can be bound as a script block parameter instead of a normal argument.42        /// </summary>43        DelayBindScriptBlock = 0x04,44 45        /// <summary>46        /// Set when an exception will be thrown if a matching parameter could not be found.47        /// </summary>48        ThrowOnParameterNotFound = 0x08,49    }50 51    /// <summary>52    /// An abstract class used by the CommandProcessor to bind parameters to a bindable object.53    /// Derived classes are used to provide specific binding behavior for different object types,54    /// like Cmdlet, PsuedoParameterCollection, and dynamic parameter objects.55    /// </summary>56    [DebuggerDisplay("Command = {command}")]57    internal abstract class ParameterBinderBase58    {59        #region tracer60        [TraceSource("ParameterBinderBase", "A abstract helper class for the CommandProcessor that binds parameters to the specified object.")]61        private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("ParameterBinderBase", "A abstract helper class for the CommandProcessor that binds parameters to the specified object.");62 63        [TraceSource("ParameterBinding", "Traces the process of binding the arguments to the parameters of cmdlets, scripts, and applications.")]64        internal static readonly PSTraceSource bindingTracer =65            PSTraceSource.GetTracer(66                "ParameterBinding",67                "Traces the process of binding the arguments to the parameters of cmdlets, scripts, and applications.",68                false);69 70        #endregion tracer71 72        #region ctor73 74        /// <summary>75        /// Constructs the parameter binder with the specified type metadata. The binder is only valid76        /// for a single instance of a bindable object and only for the duration of a command.77        /// </summary>78        /// <param name="target">79        /// The target object that the parameter values will be bound to.80        /// </param>81        /// <param name="invocationInfo">82        /// The invocation information for the code that is being bound.83        /// </param>84        /// <param name="context">85        /// The context of the currently running engine.86        /// </param>87        /// <param name="command">88        /// The command that the parameter binder is binding to. The command can be null.89        /// </param>90        internal ParameterBinderBase(91            object target,92            InvocationInfo invocationInfo,93            ExecutionContext context,94            InternalCommand command)95        {96            Diagnostics.Assert(target != null, "caller to verify target is not null.");97            Diagnostics.Assert(invocationInfo != null, "caller to verify invocationInfo is not null.");98            Diagnostics.Assert(context != null, "caller to verify context is not null.");99 100            bindingTracer.ShowHeaders = false;101 102            _command = command;103            _target = target;104            _invocationInfo = invocationInfo;105            _context = context;106            _engine = context.EngineIntrinsics;107            _isTranscribing = context.EngineHostInterface.UI.IsTranscribing;108        }109 110        /// <summary>111        /// Constructs the parameter binder with the specified type metadata. The binder is only valid112        /// for a single instance of a bindable object and only for the duration of a command.113        /// </summary>114        /// <param name="invocationInfo">115        /// The invocation information for the code that is being bound.116        /// </param>117        /// <param name="context">118        /// The context of the currently running engine.119        /// </param>120        /// <param name="command">121        /// The command that the parameter binder is binding to. The command can be null.122        /// </param>123        internal ParameterBinderBase(124            InvocationInfo invocationInfo,125            ExecutionContext context,126            InternalCommand command)127        {128            Diagnostics.Assert(invocationInfo != null, "caller to verify invocationInfo is not null.");129            Diagnostics.Assert(context != null, "caller to verify context is not null.");130 131            bindingTracer.ShowHeaders = false;132 133            _command = command;134            _invocationInfo = invocationInfo;135            _context = context;136            _engine = context.EngineIntrinsics;137            _isTranscribing = context.EngineHostInterface.UI.IsTranscribing;138        }139 140        #endregion ctor141 142        #region internal members143 144        /// <summary>145        /// Gets or sets the bindable object that the binder will bind parameters to.146        /// </summary>147        /// <value></value>148        internal object Target149        {150            get151            {152                Diagnostics.Assert(153                    _target != null,154                    "The target should always be set for the binder");155 156                return _target;157            }158 159            set160            {161                _target = value;162            }163        }164 165        /// <summary>166        /// The bindable object that parameters will be bound to.167        /// </summary>168        private object _target;169 170        /// <summary>171        /// Holds the set of parameters that have been bound from the command line...172        /// </summary>173        internal CommandLineParameters CommandLineParameters174        {175            get { return _commandLineParameters ??= new CommandLineParameters(); }176 177            // Setter is needed to pass into RuntimeParameterBinder instances178            set { _commandLineParameters = value; }179        }180 181        private CommandLineParameters _commandLineParameters;182 183        /// <summary>184        /// If this is true, then we want to record the list of bound parameters...185        /// </summary>186        internal bool RecordBoundParameters = true;187 188        /// <summary>189        /// Full Qualified ID for the obsolete parameter warning.190        /// </summary>191        internal const string FQIDParameterObsolete = "ParameterObsolete";192 193        #region Parameter default values194 195        /// <summary>196        /// Derived classes must override this method to get the default parameter197        /// value so that it can be restored between pipeline input.198        /// </summary>199        /// <param name="name">200        /// The name of the parameter to get the default value of.201        /// </param>202        /// <returns>203        /// The value of the parameter specified by name.204        /// </returns>205        internal abstract object GetDefaultParameterValue(string name);206 207        #endregion Parameter default values208 209        #region Parameter binding210 211        /// <summary>212        /// Derived classes define this method to bind the specified value213        /// to the specified parameter.214        /// </summary>215        /// <param name="name">216        ///     The name of the parameter to bind the value to.217        /// </param>218        /// <param name="value">219        ///     The value to bind to the parameter. It should be assumed by220        ///     derived classes that the proper type coercion has already taken221        ///     place and that any validation metadata has been satisfied.222        /// </param>223        /// <param name="parameterMetadata"></param>224        internal abstract void BindParameter(string name, object value, CompiledCommandParameter parameterMetadata);225 226        private void ValidatePSTypeName(227            CommandParameterInternal parameter,228            CompiledCommandParameter parameterMetadata,229            bool retryOtherBindingAfterFailure,230            object parameterValue)231        {232            Dbg.Assert(parameter != null, "Caller should verify parameter != null");233            Dbg.Assert(parameterMetadata != null, "Caller should verify parameterMetadata != null");234 235            if (parameterValue == null)236            {237                return;238            }239 240            IEnumerable<string> psTypeNamesOfArgumentValue = PSObject.AsPSObject(parameterValue).InternalTypeNames;241            string psTypeNameRequestedByParameter = parameterMetadata.PSTypeName;242 243            if (!psTypeNamesOfArgumentValue.Contains(psTypeNameRequestedByParameter, StringComparer.OrdinalIgnoreCase))244            {245                // win8: 228176..The callers know when to ignore and when not to ignore invalid cast exceptions.246                PSInvalidCastException e = new PSInvalidCastException(nameof(ErrorCategory.InvalidArgument),247                        null,248                        ParameterBinderStrings.MismatchedPSTypeName,249                        (_invocationInfo != null) && (_invocationInfo.MyCommand != null) ? _invocationInfo.MyCommand.Name : string.Empty,250                        parameterMetadata.Name,251                        parameterMetadata.Type,252                        parameterValue.GetType(),253                        0,254                        0,255                        psTypeNameRequestedByParameter);256 257                ParameterBindingException parameterBindingException;258                if (!retryOtherBindingAfterFailure)259                {260                    parameterBindingException = new ParameterBindingArgumentTransformationException(261                        e,262                        ErrorCategory.InvalidArgument,263                        this.InvocationInfo,264                        GetErrorExtent(parameter),265                        parameterMetadata.Name,266                        parameterMetadata.Type,267                        parameterValue.GetType(),268                        ParameterBinderStrings.MismatchedPSTypeName,269                        "MismatchedPSTypeName",270                        psTypeNameRequestedByParameter);271                }272                else273                {274                    parameterBindingException = new ParameterBindingException(275                        e,276                        ErrorCategory.InvalidArgument,277                        this.InvocationInfo,278                        GetErrorExtent(parameter),279                        parameterMetadata.Name,280                        parameterMetadata.Type,281                        parameterValue.GetType(),282                        ParameterBinderStrings.MismatchedPSTypeName,283                        "MismatchedPSTypeName",284                        psTypeNameRequestedByParameter);285                }286 287                throw parameterBindingException;288            }289        }290 291        /// <summary>292        /// Does all the type coercion, data generation, and validation necessary to bind the293        /// parameter, then calls the protected BindParameter method to have294        /// the derived class do the actual binding.295        /// </summary>296        /// <param name="parameter">297        /// The parameter to be bound.298        /// </param>299        /// <param name="parameterMetadata">300        /// The metadata for the parameter to use in guiding the binding.301        /// </param>302        /// <param name="flags">303        /// Flags for type coercion and validation.304        /// </param>305        /// <returns>306        /// True if the parameter was successfully bound. False if <paramref name="coerceTypeIfNeeded"/>307        /// is false and the type does not match the parameter type.308        /// </returns>309        /// <remarks>310        /// The binding algorithm goes as follows:311        /// 1. The data generation attributes are run312        /// 2. The data is coerced into the correct type313        /// 3. The data if validated using the validation attributes314        /// 4. The data is encoded into the bindable object using the315        ///    protected BindParameter method.316        /// </remarks>317        /// <exception cref="ArgumentNullException">318        /// If <paramref name="parameter"/> or <paramref name="parameterMetadata"/> is null.319        /// </exception>320        /// <exception cref="ParameterBindingException">321        /// If argument transformation fails.322        /// or323        /// The argument could not be coerced to the appropriate type for the parameter.324        /// or325        /// The parameter argument transformation, prerequisite, or validation failed.326        /// or327        /// If the binding to the parameter fails.328        /// </exception>329        internal virtual bool BindParameter(330            CommandParameterInternal parameter,331            CompiledCommandParameter parameterMetadata,332            ParameterBindingFlags flags)333        {334            bool result = false;335            bool coerceTypeIfNeeded = (flags & ParameterBindingFlags.ShouldCoerceType) != 0;336            bool isDefaultValue = (flags & ParameterBindingFlags.IsDefaultValue) != 0;337 338            if (parameter == null)339            {340                throw PSTraceSource.NewArgumentNullException(nameof(parameter));341            }342 343            if (parameterMetadata == null)344            {345                throw PSTraceSource.NewArgumentNullException(nameof(parameterMetadata));346            }347 348            using (bindingTracer.TraceScope(349                       "BIND arg [{0}] to parameter [{1}]",350                       parameter.ArgumentValue,351                       parameterMetadata.Name))352            {353                // Set the complete parameter name354 355                parameter.ParameterName = parameterMetadata.Name;356 357                object parameterValue = parameter.ArgumentValue;358 359                do // false loop360                {361                    // Now call any argument transformation attributes that might be present on the parameter362                    ScriptParameterBinder spb = this as ScriptParameterBinder;363                    bool usesCmdletBinding = false;364                    if (spb != null)365                    {366                        usesCmdletBinding = spb.Script.UsesCmdletBinding;367                    }368 369                    // Now do the argument transformation. No transformation is done for the default values in script that meet the following 2 conditions:370                    //  1. the default value is not specified by the user, but is the powershell default value.371                    //     e.g. the powershell default value for a class type is null, for the string type is string.empty.372                    //  2. the powershell default value is null.373                    // This is to prevent ArgumentTransformationAttributes from making a non-mandatory parameter behave like a mandatory one.374                    // Example:375                    //   ## without the fix, 'CredentialAttribute' would make $Credential like a mandatory parameter376                    //   ## 'PS> test-credential' would prompt for credential input377                    //   function test-credential {378                    //       param(379                    //           [System.Management.Automation.CredentialAttribute()]380                    //           $Credential381                    //       )382                    //       $Credential383                    //   }384                    //385                    foreach (ArgumentTransformationAttribute dma in parameterMetadata.ArgumentTransformationAttributes)386                    {387                        using (bindingTracer.TraceScope(388                            "Executing DATA GENERATION metadata: [{0}]",389                            dma.GetType()))390                        {391                            try392                            {393                                ArgumentTypeConverterAttribute argumentTypeConverter = dma as ArgumentTypeConverterAttribute;394 395                                if (argumentTypeConverter != null)396                                {397                                    if (coerceTypeIfNeeded)398                                    {399                                        parameterValue = argumentTypeConverter.Transform(_engine, parameterValue, true, usesCmdletBinding);400                                    }401                                }402                                else403                                {404                                    // Only apply argument transformation when the argument is not null, is mandatory, or disallows null as a value.405                                    //406                                    // If we are binding default value for an unbound script parameter, this parameter is guaranteed not mandatory407                                    // in the chosen parameter set. This is because:408                                    //  1. If we use cmdlet binding for this script (CmdletParameterBinderController is used), then binding409                                    //     default value to unbound parameters won't happen until after all mandatory parameters from the410                                    //     chosen parameter set are handled. Therefore, the unbound parameter we are dealing with here won't411                                    //     be mandatory in the chosen parameter set.412                                    //  2. If we use script binding (ScriptParameterBinderController is used), then parameters won't have the413                                    //     ParameterAttribute declared for them, and thus are definitely not mandatory.414                                    // So we check 'IsParameterMandatory' only if we are not binding default values.415                                    if ((parameterValue != null) ||416                                        (!isDefaultValue && (parameterMetadata.IsMandatoryInSomeParameterSet ||417                                                             parameterMetadata.CannotBeNull ||418                                                             dma.TransformNullOptionalParameters)))419                                    {420                                        parameterValue = dma.TransformInternal(_engine, parameterValue);421                                    }422                                }423 424                                bindingTracer.WriteLine(425                                    "result returned from DATA GENERATION: {0}",426                                    parameterValue);427                            }428                            catch (Exception e) // Catch-all OK, 3rd party callout429                            {430                                bindingTracer.WriteLine(431                                    "ERROR: DATA GENERATION: {0}",432                                    e.Message);433 434                                ParameterBindingException bindingException =435                                        new ParameterBindingArgumentTransformationException(436                                            e,437                                            ErrorCategory.InvalidData,438                                            this.InvocationInfo,439                                            GetErrorExtent(parameter),440                                            parameterMetadata.Name,441                                            parameterMetadata.Type,442                                            parameterValue?.GetType(),443                                            ParameterBinderStrings.ParameterArgumentTransformationError,444                                            "ParameterArgumentTransformationError",445                                            e.Message);446                                throw bindingException;447                            }448                        }449                    }450 451                    // Only try to coerce the type if asked. If not asked,452                    // see if the value type matches or is a subclass of453                    // the parameter type.454 455                    if (coerceTypeIfNeeded)456                    {457                        // Now do the type coercion458 459                        parameterValue =460                            CoerceTypeAsNeeded(461                                parameter,462                                parameterMetadata.Name,463                                parameterMetadata.Type,464                                parameterMetadata.CollectionTypeInformation,465                                parameterValue);466                    }467                    else468                    {469                        if (!ShouldContinueUncoercedBind(parameter, parameterMetadata, flags, ref parameterValue))470                        {471                            // Don't attempt the bind because the value472                            // is not of the correct473                            // type for the parameter.474                            break;475                        }476                    }477 478                    if ((parameterMetadata.PSTypeName != null) && (parameterValue != null))479                    {480                        IEnumerable parameterValueAsEnumerable = LanguagePrimitives.GetEnumerable(parameterValue);481                        if (parameterValueAsEnumerable != null)482                        {483                            foreach (object o in parameterValueAsEnumerable)484                            {485                                this.ValidatePSTypeName(parameter, parameterMetadata, !coerceTypeIfNeeded, o);486                            }487                        }488                        else489                        {490                            this.ValidatePSTypeName(parameter, parameterMetadata, !coerceTypeIfNeeded, parameterValue);491                        }492                    }493 494                    // Now do the data validation.  No validation is done for default values in script as that is495                    // one way for people to have a known "bad" value to detect unspecified parameters.496 497                    if (!isDefaultValue)498                    {499                        for (int i = 0; i < parameterMetadata.ValidationAttributes.Length; i++)500                        {501                            var validationAttribute = parameterMetadata.ValidationAttributes[i];502 503                            using (bindingTracer.TraceScope(504                                "Executing VALIDATION metadata: [{0}]",505                                validationAttribute.GetType()))506                            {507                                try508                                {509                                    validationAttribute.InternalValidate(parameterValue, _engine);510                                }511                                catch (Exception e) // Catch-all OK, 3rd party callout512                                {513                                    bindingTracer.WriteLine(514                                        "ERROR: VALIDATION FAILED: {0}",515                                        e.Message);516 517                                    ParameterBindingValidationException bindingException =518                                        new ParameterBindingValidationException(519                                            e,520                                            ErrorCategory.InvalidData,521                                            this.InvocationInfo,522                                            GetErrorExtent(parameter),523                                            parameterMetadata.Name,524                                            parameterMetadata.Type,525                                            parameterValue?.GetType(),526                                            ParameterBinderStrings.ParameterArgumentValidationError,527                                            "ParameterArgumentValidationError",528                                            e.Message);529                                    throw bindingException;530                                }531 532                                s_tracer.WriteLine("Validation attribute on {0} returned {1}.", parameterMetadata.Name, result);533                            }534                        }535 536                        // If the is null, an empty string, or an empty collection,537                        // check the parameter metadata to ensure that binding can continue538                        // This method throws an appropriate ParameterBindingException539                        // if binding cannot continue. If it returns then binding can540                        // proceed.541                        if (parameterMetadata.IsMandatoryInSomeParameterSet)542                        {543                            ValidateNullOrEmptyArgument(parameter, parameterMetadata, parameterMetadata.Type, parameterValue, true);544                        }545                    }546 547                    // Write out obsolete parameter warning only if548                    //  1. We are binding parameters for a simple function/script549                    //  2. We are not binding a default parameter value550 551                    if (parameterMetadata.ObsoleteAttribute != null &&552                        (!isDefaultValue) &&553                        spb != null && !usesCmdletBinding)554                    {555                        string obsoleteWarning = string.Format(556                            CultureInfo.InvariantCulture,557                            ParameterBinderStrings.UseOfDeprecatedParameterWarning,558                            parameterMetadata.Name,559                            parameterMetadata.ObsoleteAttribute.Message);560 561                        var mshCommandRuntime = this.Command.commandRuntime as MshCommandRuntime;562 563                        // Write out warning only if we are in the context of MshCommandRuntime.564                        // This is because565                        //  1. The overload method WriteWarning(WarningRecord) is only available in MshCommandRuntime;566                        //  2. We write out warnings for obsolete commands and obsolete cmdlet parameters only when in567                        //     the context of MshCommandRuntime. So we do it here to keep consistency.568                        mshCommandRuntime?.WriteWarning(new WarningRecord(FQIDParameterObsolete, obsoleteWarning));569                    }570 571                    // Finally bind the argument to the parameter572 573                    Exception bindError = null;574 575                    try576                    {577                        BindParameter(parameter.ParameterName, parameterValue, parameterMetadata);578                        result = true;579                    }580                    catch (SetValueException setValueException)581                    {582                        bindError = setValueException;583                    }584 585                    if (bindError != null)586                    {587                        Type specifiedType = parameterValue?.GetType();588                        ParameterBindingException bindingException =589                            new ParameterBindingException(590                                bindError,591                                ErrorCategory.WriteError,592                                this.InvocationInfo,593                                GetErrorExtent(parameter),594                                parameterMetadata.Name,595                                parameterMetadata.Type,596                                specifiedType,597                                ParameterBinderStrings.ParameterBindingFailed,598                                "ParameterBindingFailed",599                                bindError.Message);600 601                        throw bindingException;602                    }603                }604                while (false);605 606                bindingTracer.WriteLine(607                    "BIND arg [{0}] to param [{1}] {2}",608                    parameterValue,609                    parameter.ParameterName,610                    (result) ? "SUCCESSFUL" : "SKIPPED");611 612                if (result)613                {614                    // Add this name to the set of bound parameters...615                    if (RecordBoundParameters)616                    {617                        this.CommandLineParameters.Add(parameter.ParameterName, parameterValue);618                    }619 620                    MshCommandRuntime cmdRuntime = this.Command.commandRuntime as MshCommandRuntime;621                    if ((cmdRuntime != null) &&622                        (cmdRuntime.LogPipelineExecutionDetail || _isTranscribing) &&623                        (cmdRuntime.PipelineProcessor != null))624                    {625                        string stringToPrint = null;626                        try627                        {628                            // Unroll parameter value629                            IEnumerable values = LanguagePrimitives.GetEnumerable(parameterValue);630                            if (values != null)631                            {632                                var sb = new Text.StringBuilder(256);633                                var sep = string.Empty;634                                foreach (var value in values)635                                {636                                    sb.Append(sep);637                                    sep = ", ";638                                    sb.Append(value);639                                    // For better performance, avoid logging too much640                                    if (sb.Length > 256)641                                    {642                                        sb.Append(", ...");643                                        break;644                                    }645                                }646 647                                stringToPrint = sb.ToString();648                            }649                            else if (parameterValue != null)650                            {651                                stringToPrint = parameterValue.ToString();652                            }653                        }654                        catch (Exception) // Catch-all OK, 3rd party callout655                        {656                        }657 658                        if (stringToPrint != null)659                        {660                            cmdRuntime.PipelineProcessor.LogExecutionParameterBinding(this.InvocationInfo, parameter.ParameterName, stringToPrint);661                        }662                    }663                }664 665                return result;666            }667        }668 669        /// <summary>670        /// This method ensures that if the parameter is mandatory, and AllowNull, AllowEmptyString,671        /// and/or AllowEmptyCollection is not specified, then argument is not null or empty.672        /// </summary>673        /// <param name="parameter">674        /// The argument token.675        /// </param>676        /// <param name="parameterMetadata">677        /// The metadata for the parameter.678        /// </param>679        /// <param name="argumentType">680        /// The type of the argument to validate against.681        /// </param>682        /// <param name="parameterValue">683        /// The value that will be bound to the parameter.684        /// </param>685        /// <param name="recurseIntoCollections">686        /// If true, then elements of collections will be validated against the metadata.687        /// </param>688        private void ValidateNullOrEmptyArgument(689            CommandParameterInternal parameter,690            CompiledCommandParameter parameterMetadata,691            Type argumentType,692            object parameterValue,693            bool recurseIntoCollections)694        {695            if (parameterValue == null && argumentType != typeof(bool?))696            {697                if (!parameterMetadata.AllowsNullArgument)698                {699                    bindingTracer.WriteLine("ERROR: Argument cannot be null");700 701                    ParameterBindingValidationException bindingException =702                        new ParameterBindingValidationException(703                            ErrorCategory.InvalidData,704                            this.InvocationInfo,705                            GetErrorExtent(parameter),706                            parameterMetadata.Name,707                            argumentType,708                            null,709                            ParameterBinderStrings.ParameterArgumentValidationErrorNullNotAllowed,710                            "ParameterArgumentValidationErrorNullNotAllowed");711                    throw bindingException;712                }713 714                return;715            }716 717            if (argumentType == typeof(string))718            {719                // Since the parameter is of type string, verify that either the argument720                // is not null and not empty or that the parameter can accept null or empty.721                string stringParamValue = parameterValue as string;722                Diagnostics.Assert(723                    stringParamValue != null,724                    "Type coercion should have already converted the argument value to a string");725 726                if (stringParamValue.Length == 0 && !parameterMetadata.AllowsEmptyStringArgument)727                {728                    bindingTracer.WriteLine("ERROR: Argument cannot be an empty string");729 730                    ParameterBindingValidationException bindingException =731                        new ParameterBindingValidationException(732                            ErrorCategory.InvalidData,733                            this.InvocationInfo,734                            GetErrorExtent(parameter),735                            parameterMetadata.Name,736                            parameterMetadata.Type,737                            parameterValue?.GetType(),738                            ParameterBinderStrings.ParameterArgumentValidationErrorEmptyStringNotAllowed,739                            "ParameterArgumentValidationErrorEmptyStringNotAllowed");740                    throw bindingException;741                }742 743                return;744            }745 746            if (!recurseIntoCollections)747                return;748 749            switch (parameterMetadata.CollectionTypeInformation.ParameterCollectionType)750            {751                case ParameterCollectionType.IList:752                case ParameterCollectionType.Array:753                case ParameterCollectionType.ICollectionGeneric:754                    break;755                default:756                    // not a recognized collection, no need to recurse757                    return;758            }759 760            // All these collection types implement IEnumerable761            IEnumerator ienum = LanguagePrimitives.GetEnumerator(parameterValue);762            Diagnostics.Assert(763                ienum != null,764                "Type coercion should have already converted the argument value to an IEnumerator");765 766            // Ensure that each element abides by the metadata767            bool isEmpty = true;768            Type elementType = parameterMetadata.CollectionTypeInformation.ElementType;769            bool isElementValueType = elementType != null && elementType.IsValueType;770 771            // Note - we explicitly don't pass the context here because we don't want772            // the overhead of the calls that check for stopping.773            if (ParserOps.MoveNext(null, null, ienum))774            {775                isEmpty = false;776            }777 778            // If the element of the collection is of value type, then no need to check for null779            // because a value-type value cannot be null.780            if (!isEmpty && !isElementValueType)781            {782                do783                {784                    object element = ParserOps.Current(null, ienum);785                    ValidateNullOrEmptyArgument(786                        parameter,787                        parameterMetadata,788                        parameterMetadata.CollectionTypeInformation.ElementType,789                        element,790                        false);791                } while (ParserOps.MoveNext(null, null, ienum));792            }793 794            if (isEmpty && !parameterMetadata.AllowsEmptyCollectionArgument)795            {796                bindingTracer.WriteLine("ERROR: Argument cannot be an empty collection");797 798                string errorId, resourceString;799                if (parameterMetadata.CollectionTypeInformation.ParameterCollectionType == ParameterCollectionType.Array)800                {801                    errorId = "ParameterArgumentValidationErrorEmptyArrayNotAllowed";802                    resourceString = ParameterBinderStrings.ParameterArgumentValidationErrorEmptyArrayNotAllowed;803                }804                else805                {806                    errorId = "ParameterArgumentValidationErrorEmptyCollectionNotAllowed";807                    resourceString = ParameterBinderStrings.ParameterArgumentValidationErrorEmptyCollectionNotAllowed;808                }809 810                ParameterBindingValidationException bindingException =811                    new ParameterBindingValidationException(812                        ErrorCategory.InvalidData,813                        this.InvocationInfo,814                        GetErrorExtent(parameter),815                        parameterMetadata.Name,816                        parameterMetadata.Type,817                        parameterValue?.GetType(),818                        resourceString,819                        errorId);820                throw bindingException;821            }822        }823 824        private bool ShouldContinueUncoercedBind(825            CommandParameterInternal parameter,826            CompiledCommandParameter parameterMetadata,827            ParameterBindingFlags flags,828            ref object parameterValue)829        {830            bool isDefaultValue = (flags & ParameterBindingFlags.IsDefaultValue) != 0;831            Type parameterType = parameterMetadata.Type;832 833            if (parameterValue == null)834            {835                return parameterType == null ||836                       isDefaultValue ||837                       (!parameterType.IsValueType &&838                        parameterType != typeof(string));839            }840 841            // If the types are not a direct match, or842            // the value type is not a subclass of the parameter type, or843            // the value is an PSObject and the parameter type is not object and844            //     the PSObject.BaseObject type does not match or is not a subclass845            //     of the parameter type, or846            // the value must be encoded into a collection but it is not of the correct element type847            //848            // then return false849 850            if (parameterType.IsInstanceOfType(parameterValue))851            {852                return true;853            }854 855            var psobj = parameterValue as PSObject;856            if (psobj != null && !psobj.ImmediateBaseObjectIsEmpty)857            {858                // See if the base object is of the same type or859                // as subclass of the parameter860 861                parameterValue = psobj.BaseObject;862 863                if (parameterType.IsInstanceOfType(parameterValue))864                {865                    return true;866                }867            }868 869            // Maybe the parameter type is a collection and the value needs to870            // be encoded871 872            if (parameterMetadata.CollectionTypeInformation.ParameterCollectionType != ParameterCollectionType.NotCollection)873            {874                // See if the value needs to be encoded in a collection875 876                bool coercionRequired;877                object encodedValue =878                    EncodeCollection(879                        parameter,880                        parameterMetadata.Name,881                        parameterMetadata.CollectionTypeInformation,882                        parameterType,883                        parameterValue,884                        false,885                        out coercionRequired);886 887                if (encodedValue == null || coercionRequired)888                {889                    // Don't attempt the bind because the890                    // PSObject BaseObject is not of the correct891                    // type for the parameter.892                    return false;893                }894 895                parameterValue = encodedValue;896                return true;897            }898 899            return false;900        }901 902        #endregion Parameter binding903 904        /// <summary>905        /// The invocation information for the code that is being bound.906        /// </summary>907        private readonly InvocationInfo _invocationInfo;908 909        internal InvocationInfo InvocationInfo910        {911            get912            {913                return _invocationInfo;914            }915        }916 917        /// <summary>918        /// The context of the currently running engine.919        /// </summary>920        private readonly ExecutionContext _context;921 922        internal ExecutionContext Context923        {924            get925            {926                return _context;927            }928        }929 930        /// <summary>931        /// An instance of InternalCommand that the binder is binding to.932        /// </summary>933        private readonly InternalCommand _command;934 935        internal InternalCommand Command936        {937            get938            {939                return _command;940            }941        }942 943        /// <summary>944        /// The engine APIs that need to be passed the attributes when evaluated.945        /// </summary>946        private readonly EngineIntrinsics _engine;947 948        private readonly bool _isTranscribing;949 950        #endregion internal members951 952        #region Private helpers953 954        /// <summary>955        /// Coerces the argument type to the parameter value type as needed.956        /// </summary>957        /// <param name="argument">958        /// The argument as was specified by the command line.959        /// </param>960        /// <param name="parameterName">961        /// The name of the parameter that the coercion is taking place to bind to. It is962        /// used only for error reporting.963        /// </param>964        /// <param name="toType">965        /// The type to coerce the value to.966        /// </param>967        /// <param name="collectionTypeInfo">968        /// The information about the collection type, like element type, etc.969        /// </param>970        /// <param name="currentValue">971        /// The current value of the argument.972        /// </param>973        /// <returns>974        /// The value of the argument in the type of the parameter.975        /// </returns>976        /// <exception cref="ArgumentNullException">977        /// If <paramref name="argument"/> or <paramref name="toType"/> is null.978        /// </exception>979        /// <exception cref="ParameterBindingException">980        /// If the argument value is missing and the parameter is not a bool or SwitchParameter.981        /// or982        /// If the argument value could not be converted to the parameter type.983        /// </exception>984        private object CoerceTypeAsNeeded(985            CommandParameterInternal argument,986            string parameterName,987            Type toType,988            ParameterCollectionTypeInformation collectionTypeInfo,989            object currentValue)990        {991            if (argument == null)992            {993                throw PSTraceSource.NewArgumentNullException(nameof(argument));994            }995 996            if (toType == null)997            {998                throw PSTraceSource.NewArgumentNullException(nameof(toType));999            }1000 1001            // Construct the collection type information if it wasn't passed in.1002 1003            collectionTypeInfo ??= new ParameterCollectionTypeInformation(toType);1004 1005            object originalValue = currentValue;1006            object result = currentValue;1007 1008            using (bindingTracer.TraceScope(1009                "COERCE arg to [{0}]", toType))1010            {1011                Type argumentType = null;1012                try1013                {1014                    do // false loop1015                    {1016                        if (IsNullParameterValue(currentValue))1017                        {1018                            result = HandleNullParameterForSpecialTypes(argument, parameterName, toType, currentValue);1019                            break;1020                        }1021 1022                        // Do the coercion1023                        argumentType = currentValue.GetType();1024 1025                        // If the types are identical (or can be cast directly,) then no coercion1026                        // needs to be done1027                        if (toType.IsAssignableFrom(argumentType))1028                        {1029                            bindingTracer.WriteLine(1030                                "Parameter and arg types the same, no coercion is needed.");1031 1032                            result = currentValue;1033                            break;1034                        }1035 1036                        bindingTracer.WriteLine("Trying to convert argument value from {0} to {1}", argumentType, toType);1037 1038                        // Likewise shortcircuit the case were the user has asked for a shell object.1039                        // He always gets a shell object regardless of the actual type of the object.1040                        if (toType == typeof(PSObject))1041                        {1042                            // It may be the case that we're binding the current pipeline object1043                            // as is to a PSObject parameter in which case, we want to make1044                            // sure that we're using the same shell object instead of creating an1045                            // alias object.1046                            if (_command != null &&1047                                currentValue == _command.CurrentPipelineObject.BaseObject)1048                            {1049                                currentValue = _command.CurrentPipelineObject;1050                            }1051 1052                            bindingTracer.WriteLine(1053                                "The parameter is of type [{0}] and the argument is an PSObject, so the parameter value is the argument value wrapped into an PSObject.",1054                                toType);1055                            result = LanguagePrimitives.AsPSObjectOrNull(currentValue);1056                            break;1057                        }1058 1059                        // NTRAID#Windows OS Bugs-1064175-2004/02/28-JeffJon1060                        // If we have an PSObject with null base and we are trying to1061                        // convert to a string, then we need to use null instead of1062                        // calling LanguagePrimitives.ConvertTo as that will return1063                        // string.Empty.1064 1065                        if (toType == typeof(string) &&1066                            argumentType == typeof(PSObject))1067                        {1068                            PSObject currentValueAsPSObject = (PSObject)currentValue;1069 1070                            if (currentValueAsPSObject == AutomationNull.Value)1071                            {1072                                bindingTracer.WriteLine(1073                                    "CONVERT a null PSObject to a null string.");1074                                result = null;1075                                break;1076                            }1077                        }1078 1079                        // NTRAID#Windows OS Bugs -<bug id here> - Nana1080                        // If we have a boolean, we have to ensure that it can1081                        // only take parameters of type boolean or numbers with1082                        // 0 indicating false and everything else indicating true1083                        // Anything else passed should be reported as an error1084 1085                        if (toType == typeof(bool) || toType == typeof(SwitchParameter) ||1086                            toType == typeof(bool?))1087                        {1088                            Type boType = null;1089                            if (argumentType == typeof(PSObject))1090                            {1091                                // Unwrap the PSObject at this point...1092                                PSObject currentValueAsPSObject = (PSObject)currentValue;1093                                currentValue = currentValueAsPSObject.BaseObject;1094 1095                                if (currentValue is SwitchParameter)1096                                {1097                                    currentValue = ((SwitchParameter)currentValue).IsPresent;1098                                }1099 1100                                boType = currentValue.GetType();1101                            }1102                            else1103                            {1104                                boType = argumentType;1105                            }1106 1107                            if (boType == typeof(bool))1108                            {1109                                if (LanguagePrimitives.IsBooleanType(toType))1110                                    result = ParserOps.BoolToObject((bool)currentValue);1111                                else1112                                    result = new SwitchParameter((bool)currentValue);1113                            }1114                            else if (boType == typeof(int))1115                            {1116                                if ((int)LanguagePrimitives.ConvertTo(currentValue,1117                                            typeof(int), CultureInfo.InvariantCulture) != 0)1118                                {1119                                    if (LanguagePrimitives.IsBooleanType(toType))1120                                        result = ParserOps.BoolToObject(true);1121                                    else1122                                        result = new SwitchParameter(true);1123                                }1124                                else1125                                {1126                                    if (LanguagePrimitives.IsBooleanType(toType))1127                                        result = ParserOps.BoolToObject(false);1128                                    else1129                                        result = new SwitchParameter(false);1130                                }1131                            }1132                            else if (LanguagePrimitives.IsNumeric(boType.GetTypeCode()))1133                            {1134                                double currentValueAsDouble = (double)LanguagePrimitives.ConvertTo(1135                                                                        currentValue, typeof(double), CultureInfo.InvariantCulture);1136 1137                                if (currentValueAsDouble != 0)1138                                {1139                                    if (LanguagePrimitives.IsBooleanType(toType))1140                                        result = ParserOps.BoolToObject(true);1141                                    else1142                                        result = new SwitchParameter(true);1143                                }1144                                else1145                                {1146                                    if (LanguagePrimitives.IsBooleanType(toType))1147                                        result = ParserOps.BoolToObject(false);1148                                    else1149                                        result = new SwitchParameter(false);1150                                }1151                            }1152                            else1153                            {1154                                // Invalid types which cannot be associated with a bool1155                                // Since there is a catch block which appropriately1156                                // handles this situation we just throw an exception here1157                                // throw new PSInvalidCastException();1158                                ParameterBindingException pbe =1159                                    new ParameterBindingException(1160                                        ErrorCategory.InvalidArgument,1161                                        this.InvocationInfo,1162                                        GetErrorExtent(argument),1163                                        parameterName,1164                                        toType,1165                                        argumentType,1166                                        ParameterBinderStrings.CannotConvertArgument,1167                                        "CannotConvertArgument",1168                                        boType,1169                                        string.Empty);1170 1171                                throw pbe;1172                            }1173 1174                            break;1175                        }1176 1177                        // NTRAID#Windows OS Bugs-1009284-2004/05/05-JeffJon1178                        // Need to handle other collection types here as well1179 1180                        // Before attempting to encode a collection, we check if we can convert the argument directly via1181                        // a restricted set of conversions (as the general conversion mechanism is far too general, it may1182                        // succeed where it shouldn't.  We don't bother checking arrays parameters because they won't have1183                        // conversions we're allowing.1184                        if (collectionTypeInfo.ParameterCollectionType == ParameterCollectionType.ICollectionGeneric1185                            || collectionTypeInfo.ParameterCollectionType == ParameterCollectionType.IList)1186                        {1187                            object currentValueToConvert = PSObject.Base(currentValue);1188                            if (currentValueToConvert != null)1189                            {1190                                ConversionRank rank = LanguagePrimitives.GetConversionRank(currentValueToConvert.GetType(), toType);1191                                if (rank == ConversionRank.Constructor || rank == ConversionRank.ImplicitCast || rank == ConversionRank.ExplicitCast)1192                                {1193                                    // This conversion will fail in the common case, and when it does, we'll use EncodeCollection below.1194                                    if (LanguagePrimitives.TryConvertTo(currentValue, toType, CultureInfo.CurrentCulture, out result))1195                                    {1196                                        break;1197                                    }1198                                }1199                            }1200                        }

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