Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
scriptparameterbindercontroller.cs232 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.Management.Automation.Internal;7 8namespace System.Management.Automation9{10    /// <summary>11    /// This is the interface between the ScriptCommandProcessor and the12    /// parameter binders required to bind parameters to a shell function.13    /// </summary>14    internal class ScriptParameterBinderController : ParameterBinderController15    {16        #region ctor17 18        /// <summary>19        /// Initializes the cmdlet parameter binder controller for20        /// the specified cmdlet and engine context.21        /// </summary>22        /// <param name="script">23        /// The script that contains the parameter metadata.24        /// </param>25        /// <param name="invocationInfo">26        /// The invocation information about the code being run.27        /// </param>28        /// <param name="context">29        /// The engine context the cmdlet is run in.30        /// </param>31        /// <param name="command">32        /// The command that the parameters will be bound to.33        /// </param>34        /// <param name="localScope">35        /// The scope that the parameter binder will use to set parameters.36        /// </param>37        internal ScriptParameterBinderController(38            ScriptBlock script,39            InvocationInfo invocationInfo,40            ExecutionContext context,41            InternalCommand command,42            SessionStateScope localScope)43            : base(invocationInfo, context, new ScriptParameterBinder(script, invocationInfo, context, command, localScope))44        {45            this.DollarArgs = new List<object>();46 47            // Add the script parameter metadata to the bindable parameters48            // And add them to the unbound parameters list49 50            if (script.HasDynamicParameters)51            {52                UnboundParameters = this.BindableParameters.ReplaceMetadata(script.ParameterMetadata);53            }54            else55            {56                _bindableParameters = script.ParameterMetadata;57                UnboundParameters = new List<MergedCompiledCommandParameter>(_bindableParameters.BindableParameters.Values);58            }59        }60 61        #endregion ctor62 63        /// <summary>64        /// Holds the set of parameters that were not bound to any argument (i.e $args)65        /// </summary>66        internal List<object> DollarArgs { get; }67 68        /// <summary>69        /// Binds the command line parameters for shell functions/filters/scripts/scriptblocks.70        /// </summary>71        /// <param name="arguments">72        ///     The arguments to be bound.73        /// </param>74        /// <returns>75        /// True if binding was successful or false otherwise.76        /// </returns>77        internal void BindCommandLineParameters(Collection<CommandParameterInternal> arguments)78        {79            // Add the passed in arguments to the unboundArguments collection80            InitUnboundArguments(arguments);81            ReparseUnboundArguments();82 83            UnboundArguments = BindNamedParameters(uint.MaxValue, UnboundArguments);84 85            ParameterBindingException parameterBindingError;86            UnboundArguments =87                BindPositionalParameters(88                    UnboundArguments,89                    uint.MaxValue,90                    uint.MaxValue,91                    out parameterBindingError);92 93            try94            {95                this.DefaultParameterBinder.RecordBoundParameters = false;96 97                // If there are any unbound parameters that have default values, then98                // set those default values.99                BindUnboundScriptParameters();100 101                // If there are any unbound arguments, stick them into $args102                HandleRemainingArguments(UnboundArguments);103            }104            finally105            {106                this.DefaultParameterBinder.RecordBoundParameters = true;107            }108 109            return;110        }111 112        /// <summary>113        /// Passes the binding directly through to the parameter binder.114        /// It does no verification against metadata.115        /// </summary>116        /// <param name="argument">117        /// The name and value of the variable to bind.118        /// </param>119        /// <param name="flags">120        /// Ignored.121        /// </param>122        /// <returns>123        /// True if the parameter was successfully bound. Any error condition124        /// produces an exception.125        /// </returns>126        internal override bool BindParameter(CommandParameterInternal argument, ParameterBindingFlags flags)127        {128            // Just pass the binding straight through.  No metadata to verify the parameter against.129            DefaultParameterBinder.BindParameter(argument.ParameterName, argument.ArgumentValue, parameterMetadata: null);130            return true;131        }132 133        /// <summary>134        /// Takes the remaining arguments that haven't been bound, and binds135        /// them to $args.136        /// </summary>137        /// <param name="arguments">138        ///     The remaining unbound arguments.139        /// </param>140        /// <remarks>141        /// An array containing the values that were bound to $args.142        /// </remarks>143        private void HandleRemainingArguments(Collection<CommandParameterInternal> arguments)144        {145            List<object> args = new List<object>();146 147            foreach (CommandParameterInternal parameter in arguments)148            {149                object argValue = parameter.ArgumentSpecified ? parameter.ArgumentValue : null;150 151                // Proper automatic proxy generation requires the ability to prevent unbound arguments152                // in the proxy from binding to positional parameters in the proxied command.  We use153                // a special key ("$args") when splatting @CommandLineArguments to package up $args.154                // This special key is not created automatically because it is useful to splat @args,155                // just not in the automatically generated proxy.156                //157                // Example usage:158                //159                //   function foo { param($a, $b) $a; $b; $args }160                //   function foo_proxy { param($a) ; $CommandLineArguments.Add('$args', $args); foo @CommandLineArguments }161                //   foo_proxy 1 2 3162                //163                // Then in foo, $a=1, $b=, $args=2,3164                //165                // Here, we want $b in foo to be unbound because the proxy doesn't have $b (an Exchange scenario.)166                // So we pass $args (2,3) in the special entry in @CommandLineArguments.  If we had instead written:167                //168                //   function foo_proxy { param($a) ; foo @CommandLineArguments @args }169                //   foo_proxy 1 2 3170                //171                // Then in foo, $a=1, $b=2, $args=3172                //173                // Note that the name $args is chosen to be:174                //   * descriptive175                //   * obscure (it can't be a property/field name in C#, and is an unlikely variable in script)176                // So we shouldn't have any real conflict.  Note that if someone actually puts ${$args} in their177                // param block, then the value will be bound and we won't have an unbound argument for "$args" here.178                if (parameter.ParameterAndArgumentSpecified &&179                    parameter.ParameterName.Equals("$args", StringComparison.OrdinalIgnoreCase))180                {181                    // $args is normally an object[], but because this feature is accessible from script, it's possible182                    // for it to contain anything.183                    if (argValue is object[])184                    {185                        args.AddRange(argValue as object[]);186                    }187                    else188                    {189                        args.Add(argValue);190                    }191 192                    continue;193                }194 195                if (parameter.ParameterNameSpecified)196                {197                    // Add a property to the string so we can tell the difference between:198                    //    foo -abc199                    //    foo "-abc"200                    // This is important when splatting, we reconstruct the parameter if the201                    // value is splatted.202                    var parameterText = new PSObject(new string(parameter.ParameterText));203                    if (parameterText.Properties[NotePropertyNameForSplattingParametersInArgs] == null)204                    {205                        var noteProperty = new PSNoteProperty(NotePropertyNameForSplattingParametersInArgs,206                                                              parameter.ParameterName)207                        { IsHidden = true };208                        parameterText.Properties.Add(noteProperty);209                    }210 211                    args.Add(parameterText);212                }213 214                if (parameter.ArgumentSpecified)215                {216                    args.Add(argValue);217                }218            }219 220            object[] argsArray = args.ToArray();221 222            DefaultParameterBinder.BindParameter(SpecialVariables.Args, argsArray, parameterMetadata: null);223 224            DollarArgs.AddRange(argsArray);225 226            return;227        }228 229        internal const string NotePropertyNameForSplattingParametersInArgs = "<CommandParameterName>";230    }231}232