Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
CommandProcessor.cs868 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.ObjectModel;7using System.Diagnostics;8using System.Linq.Expressions;9using System.Management.Automation.Internal;10 11using Microsoft.PowerShell.Commands;12 13using Dbg = System.Management.Automation.Diagnostics;14 15namespace System.Management.Automation16{17    /// <summary>18    /// Class definition of CommandProcessor - This class provides interface to create19    /// and execute commands written in CLS compliant languages.20    /// </summary>21    internal class CommandProcessor : CommandProcessorBase22    {23        #region ctor24 25        static CommandProcessor()26        {27            s_constructInstanceCache = new ConcurrentDictionary<Type, Func<Cmdlet>>();28 29            // Avoid jitting constructors some of the more commonly used cmdlets in SMA.dll - not meant to be30            // exhaustive b/c many cmdlets aren't called at all, so we'd never even need an entry in the cache.31            s_constructInstanceCache.GetOrAdd(typeof(ForEachObjectCommand), () => new ForEachObjectCommand());32            s_constructInstanceCache.GetOrAdd(typeof(WhereObjectCommand), () => new WhereObjectCommand());33            s_constructInstanceCache.GetOrAdd(typeof(ImportModuleCommand), () => new ImportModuleCommand());34            s_constructInstanceCache.GetOrAdd(typeof(GetModuleCommand), () => new GetModuleCommand());35            s_constructInstanceCache.GetOrAdd(typeof(GetHelpCommand), () => new GetHelpCommand());36            s_constructInstanceCache.GetOrAdd(typeof(InvokeCommandCommand), () => new InvokeCommandCommand());37            s_constructInstanceCache.GetOrAdd(typeof(GetCommandCommand), () => new GetCommandCommand());38            s_constructInstanceCache.GetOrAdd(typeof(OutDefaultCommand), () => new OutDefaultCommand());39            s_constructInstanceCache.GetOrAdd(typeof(OutHostCommand), () => new OutHostCommand());40            s_constructInstanceCache.GetOrAdd(typeof(OutNullCommand), () => new OutNullCommand());41            s_constructInstanceCache.GetOrAdd(typeof(SetStrictModeCommand), () => new SetStrictModeCommand());42            s_constructInstanceCache.GetOrAdd(typeof(FormatDefaultCommand), () => new FormatDefaultCommand());43            s_constructInstanceCache.GetOrAdd(typeof(OutLineOutputCommand), () => new OutLineOutputCommand());44        }45 46        /// <summary>47        /// Initializes the new instance of CommandProcessor class.48        /// </summary>49        /// <param name="cmdletInfo">50        /// The information about the cmdlet.51        /// </param>52        /// <param name="context">53        /// PowerShell engine execution context for this command.54        /// </param>55        /// <exception cref="CommandNotFoundException">56        /// If there was a failure creating an instance of the cmdlet type.57        /// </exception>58        internal CommandProcessor(CmdletInfo cmdletInfo, ExecutionContext context) : base(cmdletInfo)59        {60            this._context = context;61            Init(cmdletInfo);62        }63 64        /// <summary>65        /// This is the constructor for script as cmdlet.66        /// </summary>67        /// <param name="scriptCommandInfo">68        /// The information about the cmdlet.69        /// </param>70        /// <param name="context">71        /// PowerShell engine execution context for this command.72        /// </param>73        /// <param name="useLocalScope"></param>74        /// <param name="sessionState"></param>75        /// <param name="fromScriptFile">True when the script to be executed came from a file (as opposed to a function, or interactive input).</param>76        internal CommandProcessor(IScriptCommandInfo scriptCommandInfo, ExecutionContext context, bool useLocalScope, bool fromScriptFile, SessionStateInternal sessionState)77            : base(scriptCommandInfo as CommandInfo)78        {79            this._context = context;80            this._useLocalScope = useLocalScope;81            this._fromScriptFile = fromScriptFile;82            this.CommandSessionState = sessionState;83            Init(scriptCommandInfo);84        }85 86        #endregion ctor87 88        #region internal members89 90        /// <summary>91        /// Returns a CmdletParameterBinderController for the specified command.92        /// </summary>93        /// <param name="command">94        /// The cmdlet to bind parameters to.95        /// </param>96        /// <returns>97        /// A new instance of a CmdletParameterBinderController.98        /// </returns>99        /// <exception cref="ArgumentException">100        /// if <paramref name="command"/> is not a Cmdlet.101        /// </exception>102        internal ParameterBinderController NewParameterBinderController(InternalCommand command)103        {104            if (command is not Cmdlet cmdlet)105            {106                throw PSTraceSource.NewArgumentException(nameof(command));107            }108 109            ParameterBinderBase parameterBinder;110            IScriptCommandInfo scriptCommandInfo = CommandInfo as IScriptCommandInfo;111            if (scriptCommandInfo != null)112            {113                parameterBinder = new ScriptParameterBinder(scriptCommandInfo.ScriptBlock, cmdlet.MyInvocation, this._context, cmdlet, CommandScope);114            }115            else116            {117                parameterBinder = new ReflectionParameterBinder(cmdlet, cmdlet);118            }119 120            _cmdletParameterBinderController = new CmdletParameterBinderController(cmdlet, CommandInfo.CommandMetadata, parameterBinder);121 122            return _cmdletParameterBinderController;123        }124 125        internal CmdletParameterBinderController CmdletParameterBinderController126        {127            get128            {129                if (_cmdletParameterBinderController == null)130                {131                    NewParameterBinderController(this.Command);132                }133 134                return _cmdletParameterBinderController;135            }136        }137 138        private CmdletParameterBinderController _cmdletParameterBinderController;139 140        /// <summary>141        /// Get the ObsoleteAttribute of the current command.142        /// </summary>143        internal override ObsoleteAttribute ObsoleteAttribute144        {145            get { return _obsoleteAttribute; }146        }147 148        private ObsoleteAttribute _obsoleteAttribute;149 150        /// <summary>151        /// Binds the specified command-line parameters to the target.152        /// </summary>153        /// <returns>154        /// true if encode succeeds otherwise false.155        /// </returns>156        /// <exception cref="ParameterBindingException">157        /// If any parameters fail to bind,158        /// or159        /// If any mandatory parameters are missing.160        /// </exception>161        /// <exception cref="MetadataException">162        /// If there is an error generating the metadata for dynamic parameters.163        /// </exception>164        internal void BindCommandLineParameters()165        {166            using (commandRuntime.AllowThisCommandToWrite(false))167            {168                Diagnostics.Assert(169                    this.CmdletParameterBinderController != null,170                    "A parameter binder controller should always be available");171 172                // Always set the hash table on MyInvocation so it's available for both interpreted cmdlets173                // as well as compiled ones.174                this.CmdletParameterBinderController.CommandLineParameters.UpdateInvocationInfo(this.Command.MyInvocation);175                this.Command.MyInvocation.UnboundArguments = new Collections.Generic.List<object>();176 177                this.CmdletParameterBinderController.BindCommandLineParameters(arguments);178            }179        }180 181        /// <summary>182        /// Prepares the command. Encodes the command-line parameters183        /// JonN     2003-04-02 Split from Execute()184        /// </summary>185        /// <exception cref="ParameterBindingException">186        /// If any parameters fail to bind,187        /// or188        /// If any mandatory parameters are missing.189        /// </exception>190        /// <exception cref="MetadataException">191        /// If there is an error generating the metadata for dynamic parameters.192        /// </exception>193        internal override void Prepare(IDictionary psDefaultParameterValues)194        {195            // Note that Prepare() and DoBegin() should NOT be combined.196            // Reason: Encoding of commandline parameters happen as part of197            // Prepare(). If they are combined, the first command's198            // DoBegin() will be called before the next command's Prepare().199            // Since BeginProcessing() can write objects to the downstream200            // commandlet, it will end up calling DoExecute() (from Pipe.Add())201            // before Prepare.202 203            // Steps involved:204            // (1) Backup the default parameter values205            // (2) Handle input objects - add them to the input pipe.206            // (3) Bind the parameters to properties (encoding)207            // (4) Execute the command method using DoExecute() (repeatedly)208 209            this.CmdletParameterBinderController.DefaultParameterValues = psDefaultParameterValues;210 211            Diagnostics.Assert(212                this.Command != null,213                "CommandProcessor did not initialize Command\n" + this.CommandInfo.Name);214 215            PSLanguageMode? oldLanguageMode = null;216            bool? oldLangModeTransitionStatus = null;217            try218            {219                var scriptCmdletInfo = this.CommandInfo as IScriptCommandInfo;220                if (scriptCmdletInfo != null &&221                    scriptCmdletInfo.ScriptBlock.LanguageMode.HasValue &&222                    scriptCmdletInfo.ScriptBlock.LanguageMode != Context.LanguageMode)223                {224                    // Set the language mode before parameter binding if it's necessary for a script cmdlet, so that the language225                    // mode is appropriately applied for evaluating parameter defaults and argument type conversion.226                    oldLanguageMode = Context.LanguageMode;227                    Context.LanguageMode = scriptCmdletInfo.ScriptBlock.LanguageMode.Value;228 229                    // If it's from ConstrainedLanguage to FullLanguage, indicate the transition before parameter binding takes place.230                    // When transitioning to FullLanguage mode, we don't want any ConstrainedLanguage restrictions or incorrect Audit messages.231                    if (oldLanguageMode == PSLanguageMode.ConstrainedLanguage && Context.LanguageMode == PSLanguageMode.FullLanguage)232                    {233                        oldLangModeTransitionStatus = Context.LanguageModeTransitionInParameterBinding;234                        Context.LanguageModeTransitionInParameterBinding = true;235                    }236                }237 238                BindCommandLineParameters();239            }240            finally241            {242                if (oldLanguageMode.HasValue)243                {244                    // Revert to the original language mode after doing the parameter binding245                    Context.LanguageMode = oldLanguageMode.Value;246                }247 248                if (oldLangModeTransitionStatus.HasValue)249                {250                    // Revert the transition state to old value after doing the parameter binding251                    Context.LanguageModeTransitionInParameterBinding = oldLangModeTransitionStatus.Value;252                }253            }254        }255 256        protected override void OnSetCurrentScope()257        {258            // When dotting a script cmdlet, push the locals of automatic variables to259            // the 'DottedScopes' of the current scope.260            PSScriptCmdlet scriptCmdlet = this.Command as PSScriptCmdlet;261            if (scriptCmdlet != null && !UseLocalScope)262            {263                scriptCmdlet.PushDottedScope(CommandSessionState.CurrentScope);264            }265        }266 267        protected override void OnRestorePreviousScope()268        {269            // When dotting a script cmdlet, pop the locals of automatic variables from270            // the 'DottedScopes' of the current scope.271            PSScriptCmdlet scriptCmdlet = this.Command as PSScriptCmdlet;272            if (scriptCmdlet != null && !UseLocalScope)273            {274                scriptCmdlet.PopDottedScope(CommandSessionState.CurrentScope);275            }276        }277 278        /// <summary>279        /// Execute BeginProcessing part of command.280        /// </summary>281        internal override void DoBegin()282        {283            if (!RanBeginAlready && CmdletParameterBinderController.ObsoleteParameterWarningList != null)284            {285                using (CommandRuntime.AllowThisCommandToWrite(false))286                {287                    // Write out warning messages for the bound obsolete parameters.288                    // The warning message are generated during parameter binding, but we delay writing289                    // them out until now so that the -WarningAction will be respected as expected.290                    foreach (WarningRecord warningRecord in CmdletParameterBinderController.ObsoleteParameterWarningList)291                    {292                        CommandRuntime.WriteWarning(warningRecord);293                    }294                }295 296                // Clear up the warning message list297                CmdletParameterBinderController.ObsoleteParameterWarningList.Clear();298            }299 300            base.DoBegin();301        }302 303        /// <summary>304        /// This calls the command.  It assumes that Prepare() has already been called.305        /// JonN     2003-04-02 Split from Execute()306        /// </summary>307        /// <exception cref="PipelineStoppedException">308        /// a terminating error occurred, or the pipeline was otherwise stopped309        /// </exception>310        internal override void ProcessRecord()311        {312            // Invoke the Command method with the request object313            if (!this.RanBeginAlready)314            {315                RanBeginAlready = true;316                try317                {318                    using (commandRuntime.AllowThisCommandToWrite(true))319                    {320                        if (Context._debuggingMode > 0 && Command is not PSScriptCmdlet)321                        {322                            Context.Debugger.CheckCommand(this.Command.MyInvocation);323                        }324 325                        Command.DoBeginProcessing();326                    }327                }328                catch (Exception e)329                {330                    // This cmdlet threw an exception, so wrap it and bubble it up.331                    throw ManageInvocationException(e);332                }333            }334 335            Debug.Assert(this.Command.MyInvocation.PipelineIterationInfo != null); // this should have been allocated when the pipeline was started336 337            while (Read())338            {339                Pipe oldErrorOutputPipe = _context.ShellFunctionErrorOutputPipe;340                Exception exceptionToThrow = null;341                try342                {343                    //344                    // On V1 the output pipe was redirected to the command's output pipe only when it345                    // was already redirected. This is the original comment explaining this behaviour:346                    //347                    //      NTRAID#Windows Out of Band Releases-926183-2005-12-15348                    //      MonadTestHarness has a bad dependency on an artifact of the current implementation349                    //      The following code only redirects the output pipe if it's already redirected350                    //      to preserve the artifact. The test suites need to be fixed and then this351                    //      the check can be removed and the assignment always done.352                    //353                    // However, this makes the hosting APIs behave differently than commands executed354                    // from the command-line host (for example, see bugs Win7:415915 and Win7:108670).355                    // The RedirectShellErrorOutputPipe flag is used by the V2 hosting API to force the356                    // redirection.357                    //358                    if (this.RedirectShellErrorOutputPipe || _context.ShellFunctionErrorOutputPipe != null)359                    {360                        _context.ShellFunctionErrorOutputPipe = this.commandRuntime.ErrorOutputPipe;361                    }362 363                    // NOTICE-2004/06/08-JonN 959638364                    using (commandRuntime.AllowThisCommandToWrite(true))365                    using (ParameterBinderBase.bindingTracer.TraceScope("CALLING ProcessRecord"))366                    {367                        if (CmdletParameterBinderController.ObsoleteParameterWarningList != null &&368                            CmdletParameterBinderController.ObsoleteParameterWarningList.Count > 0)369                        {370                            // Write out warning messages for the pipeline-value-bound obsolete parameters.371                            // The warning message are generated during parameter binding, but we delay writing372                            // them out until now so that the -WarningAction will be respected as expected.373                            foreach (WarningRecord warningRecord in CmdletParameterBinderController.ObsoleteParameterWarningList)374                            {375                                CommandRuntime.WriteWarning(warningRecord);376                            }377 378                            // Clear up the warning message list379                            CmdletParameterBinderController.ObsoleteParameterWarningList.Clear();380                        }381 382                        this.Command.MyInvocation.PipelineIterationInfo[this.Command.MyInvocation.PipelinePosition]++;383 384                        Command.DoProcessRecord();385                    }386                }387                catch (RuntimeException rte)388                {389                    // Most exceptions get wrapped here, but an exception that originated from390                    // a throw statement should not get wrapped, so it is just rethrown.391                    if (rte.WasThrownFromThrowStatement)392                    {393                        throw;394                    }395 396                    exceptionToThrow = rte;397                }398                catch (LoopFlowException)399                {400                    // Don't wrap LoopFlowException, we incorrectly raise a PipelineStoppedException401                    // which gets caught by a script try/catch if we wrap here.402                    throw;403                }404                catch (Exception e)405                {406                    // Catch-all OK, 3rd party callout.407                    exceptionToThrow = e;408                }409                finally410                {411                    _context.ShellFunctionErrorOutputPipe = oldErrorOutputPipe;412                }413 414                if (exceptionToThrow != null)415                {416                    // This cmdlet threw an exception, so417                    // wrap it and bubble it up.418                    throw ManageInvocationException(exceptionToThrow);419                }420            }421        }422 423        #endregion public_methods424 425        #region helper_methods426 427        /// <summary>428        /// Tells whether it is the first call to Read.429        /// </summary>430        private bool _firstCallToRead = true;431 432        /// <summary>433        /// Tells whether to bail out in the next call to Read.434        /// </summary>435        private bool _bailInNextCall;436 437        /// <summary>438        /// Populates the parameters specified from the pipeline.439        /// </summary>440        /// <returns>441        /// A bool indicating whether read succeeded.442        /// </returns>443        /// <exception cref="ParameterBindingException">444        /// If a parameter fails to bind.445        /// or446        /// If a mandatory parameter is missing.447        /// </exception>448        /// <exception cref="PipelineStoppedException">449        /// The pipeline was already stopped.450        /// </exception>451        // 2003/10/07-JonN was public, now internal452        internal sealed override bool Read()453        {454            // (1) If Read() is called for the first time and with pipe closed and455            //     no object in the input pipe and456            //     (typically for the first cmdlet in the pipe & during programmatic457            //     execution of a command), Read() will succeed (return true) for458            //     only one time (so that the459            // (2) If Read() is called with some input objects in the pipeline, it460            //     processes the input461            //     object one at a time and adds parameters from the input object462            //     to the list of parameters. If463            //     added to the error pipe and Read() will continue to read the464            //     next object in the pipe.465            // (3) Read() will return false if there are no objects in the pipe466            //     for processing.467            // (4) Read() will return true if the parameters are encoded in the468            //     request - signals ready for execution.469            // (5) Read() will refresh the properties that are encoded via pipeline470            //     parameters in the next471            //     call to Read() [To their default values, so that the472            //     next execution of the command will473            //     not work on previously specified parameter].474            // If the flag 'bail in next call' is true, then bail out returning false.475            if (_bailInNextCall)476                return false;477 478            // ProcessRecord() will loop on Command.Read(), and continue calling479            // ProcessRecord() until the incoming pipe is empty.  We need to480            // stop this loop if a downstream cmdlet broke guidelines and481            // "swallowed" a PipelineStoppedException.482            Command.ThrowIfStopping();483 484            // Prepare the default value parameter list if this is the first call to Read485            if (_firstCallToRead)486            {487                _firstCallToRead = false;488                if (!IsPipelineInputExpected())489                {490                    // Cmdlet should operate only with command-line parameters491                    // Let the command Execute with the specified command line parameters492                    // And Read should return false in the next call.493                    _bailInNextCall = true;494                    return true;495                }496            }497 498            // If this cmdlet has any members that could be bound499            // from the pipeline, do that now. In fact, we always try and500            // do it once anyway because this BindPipelineParameters() does501            // the final binding stage in before executing the cmdlet.502 503            bool mandatoryParametersSpecified = false;504 505            while (!mandatoryParametersSpecified)506            {507                // Retrieve the object from the input pipeline508                object inputObject = this.commandRuntime.InputPipe.Retrieve();509 510                if (inputObject == AutomationNull.Value)511                {512                    // no object in the pipeline, stop reading513                    Command.CurrentPipelineObject = null;514                    return false;515                }516 517                // If we are reading input for the first command in the pipeline increment PipelineIterationInfo[0], which is the number of items read from the input518                if (this.Command.MyInvocation.PipelinePosition == 1)519                {520                    this.Command.MyInvocation.PipelineIterationInfo[0]++;521                }522 523                try524                {525                    // Process the input pipeline object526                    if (!ProcessInputPipelineObject(inputObject))527                    {528                        // The input object was not bound to any parameters of the cmdlet.529                        // Write a non-terminating error and continue with the next input530                        // object.531                        WriteInputObjectError(532                            inputObject,533                            ParameterBinderStrings.InputObjectNotBound,534                            "InputObjectNotBound");535                        continue;536                    }537                }538                catch (ParameterBindingException bindingError)539                {540                    // Set the target and write the error541                    bindingError.ErrorRecord.SetTargetObject(inputObject);542 543                    ErrorRecord errorRecord =544                        new ErrorRecord(545                            bindingError.ErrorRecord,546                            bindingError);547 548                    this.commandRuntime._WriteErrorSkipAllowCheck(errorRecord);549                    continue;550                }551 552                Collection<MergedCompiledCommandParameter> missingMandatoryParameters;553 554                using (ParameterBinderBase.bindingTracer.TraceScope(555                    "MANDATORY PARAMETER CHECK on cmdlet [{0}]",556                    this.CommandInfo.Name))557                {558                    // Check for unbound mandatory parameters but don't prompt559                    mandatoryParametersSpecified =560                        this.CmdletParameterBinderController.HandleUnboundMandatoryParameters(out missingMandatoryParameters);561                }562 563                if (!mandatoryParametersSpecified)564                {565                    string missingParameters =566                        CmdletParameterBinderController.BuildMissingParamsString(missingMandatoryParameters);567 568                    // Since the input object did not satisfy all mandatory parameters569                    // for the command, write an ErrorRecord to the error pipe with570                    // the target as the input object.571 572                    WriteInputObjectError(573                        inputObject,574                        ParameterBinderStrings.InputObjectMissingMandatory,575                        "InputObjectMissingMandatory",576                        missingParameters);577                }578            }579 580            return true;581        }582 583        /// <summary>584        /// Writes an ErrorRecord to the commands error pipe because the specified585        /// input object was not bound to the command.586        /// </summary>587        /// <param name="inputObject">588        /// The pipeline input object that was not bound.589        /// </param>590        /// <param name="resourceString">591        /// The error message.592        /// </param>593        /// <param name="errorId">594        /// The resource ID of the error message is also used as error ID595        /// of the ErrorRecord.596        /// </param>597        /// <param name="args">598        /// Additional arguments to be formatted into the error message that represented in <paramref name="resourceString"/>.599        /// </param>600        private void WriteInputObjectError(601            object inputObject,602            string resourceString,603            string errorId,604            params object[] args)605        {606            Type inputObjectType = inputObject?.GetType();607 608            ParameterBindingException bindingException = new ParameterBindingException(609                ErrorCategory.InvalidArgument,610                this.Command.MyInvocation,611                null,612                null,613                null,614                inputObjectType,615                resourceString,616                errorId,617                args);618 619            ErrorRecord errorRecord =620                new ErrorRecord(621                    bindingException,622                    errorId,623                    ErrorCategory.InvalidArgument,624                    inputObject);625 626            errorRecord.SetInvocationInfo(this.Command.MyInvocation);627 628            this.commandRuntime._WriteErrorSkipAllowCheck(errorRecord);629        }630 631        /// <summary>632        /// Reads an object from an input pipeline and attempts to bind the parameters.633        /// </summary>634        /// <param name="inputObject">635        /// The pipeline input object to be processed.636        /// </param>637        /// <returns>638        /// False the pipeline input object was not bound in any way to the command.639        /// </returns>640        /// <exception cref="ParameterBindingException">641        /// If a ShouldProcess parameter is specified but the cmdlet does not support642        /// ShouldProcess.643        /// or644        /// If an error occurred trying to bind a parameter from the pipeline object.645        /// </exception>646        private bool ProcessInputPipelineObject(object inputObject)647        {648            PSObject inputToOperateOn = null;649 650            // Use ETS to retrieve properties from the input object651            // turn it into a shell object if it isn't one already...652            // we depend on PSObject.AsPSObject() being idempotent - if653            // it's already a shell object, don't encapsulate it again.654            if (inputObject != null)655            {656                inputToOperateOn = PSObject.AsPSObject(inputObject);657            }658 659            Command.CurrentPipelineObject = inputToOperateOn;660 661            return this.CmdletParameterBinderController.BindPipelineParameters(inputToOperateOn);662        }663 664        private static readonly ConcurrentDictionary<Type, Func<Cmdlet>> s_constructInstanceCache;665 666        private static Cmdlet ConstructInstance(Type type)667        {668            // Call the default constructor if type derives from Cmdlet.669            // Return null (and the caller will generate an appropriate error) if670            // type does not derive from Cmdlet.  We do it this way so the expensive type check671            // is performed just once per type.672 673            return s_constructInstanceCache.GetOrAdd(type,674                t => Expression.Lambda<Func<Cmdlet>>(675                     typeof(Cmdlet).IsAssignableFrom(t)676                        ? (Expression)Expression.New(t)677                        : Expression.Constant(null, typeof(Cmdlet))).Compile())();678        }679 680        /// <summary>681        /// Initializes the command's request object.682        /// </summary>683        /// <param name="cmdletInformation">684        /// The information about the cmdlet.685        /// </param>686        /// <exception cref="CmdletInvocationException">687        /// If the constructor for the cmdlet threw an exception.688        /// </exception>689        /// <exception cref="MemberAccessException">690        /// The type referenced by <paramref name="cmdletInformation"/> referred to an691        /// abstract type or them member was invoked via a late-binding mechanism.692        /// </exception>693        /// <exception cref="TypeLoadException">694        /// If <paramref name="cmdletInformation"/> refers to a type that is invalid.695        /// </exception>696        private void Init(CmdletInfo cmdletInformation)697        {698            Diagnostics.Assert(cmdletInformation != null, "Constructor should throw exception if LookupCommand returned null.");699 700            Cmdlet newCmdlet = null;701            Exception initError = null;702            string errorIdAndResourceId = null;703            string resourceStr = null;704            try705            {706                // Create the request object707                newCmdlet = ConstructInstance(cmdletInformation.ImplementingType);708                if (newCmdlet == null)709                {710                    // We could test the inheritance before constructing, but that's711                    // expensive.  Much cheaper to just check for null.712                    initError = new InvalidCastException();713                    errorIdAndResourceId = "CmdletDoesNotDeriveFromCmdletType";714                    resourceStr = DiscoveryExceptions.CmdletDoesNotDeriveFromCmdletType;715                }716            }717            catch (MemberAccessException memberAccessException)718            {719                initError = memberAccessException;720            }721            catch (TypeLoadException typeLoadException)722            {723                initError = typeLoadException;724            }725            catch (Exception e) // Catch-all OK, 3rd party callout.726            {727                // We don't have a Command or InvocationInfo at this point,728                // since the command failed to initialize.729                var commandException = new CmdletInvocationException(e, null);730 731                // Log a command health event732                MshLog.LogCommandHealthEvent(733                    this._context,734                    commandException,735                    Severity.Warning);736 737                throw commandException;738            }739 740            if (initError != null)741            {742                // Log a command health event743                MshLog.LogCommandHealthEvent(744                    this._context,745                    initError,746                    Severity.Warning);747 748                CommandNotFoundException exception =749                    new CommandNotFoundException(750                        cmdletInformation.Name,751                        initError,752                        errorIdAndResourceId ?? "CmdletNotFoundException",753                        resourceStr ?? DiscoveryExceptions.CmdletNotFoundException,754                        initError.Message);755                throw exception;756            }757 758            this.Command = newCmdlet;759            this.CommandScope = Context.EngineSessionState.CurrentScope;760 761            InitCommon();762        }763 764        private void Init(IScriptCommandInfo scriptCommandInfo)765        {766            var scriptCmdlet = new PSScriptCmdlet(scriptCommandInfo.ScriptBlock, UseLocalScope, FromScriptFile, _context);767            this.Command = scriptCmdlet;768            this.CommandScope = UseLocalScope769                                    ? this.CommandSessionState.NewScope(_fromScriptFile)770                                    : this.CommandSessionState.CurrentScope;771 772            if (UseLocalScope)773            {774                // Set the 'LocalsTuple' of the new scope to that of the scriptCmdlet775                scriptCmdlet.SetLocalsTupleForNewScope(CommandScope);776            }777 778            InitCommon();779 780            // If the script has been dotted, throw an error if it's from a different language mode.781            if (!this.UseLocalScope)782            {783                ValidateCompatibleLanguageMode(scriptCommandInfo.ScriptBlock, _context, Command.MyInvocation);784            }785        }786 787        private void InitCommon()788        {789            // set the metadata790            this.Command.CommandInfo = this.CommandInfo;791 792            // set the ObsoleteAttribute of the current command793            _obsoleteAttribute = this.CommandInfo.CommandMetadata.Obsolete;794 795            // set the execution context796            this.Command.Context = this._context;797 798            // Now set up the command runtime for this command.799            try800            {801                this.commandRuntime = new MshCommandRuntime(_context, this.CommandInfo, this.Command);802                this.Command.commandRuntime = this.commandRuntime;803            }804            catch (Exception e) // Catch-all OK, 3rd party callout.805            {806                // Log a command health event807 808                MshLog.LogCommandHealthEvent(809                    this._context,810                    e,811                    Severity.Warning);812 813                throw;814            }815        }816 817        /// <summary>818        /// Checks if user has requested help (for example passing "-?" parameter for a cmdlet)819        /// and if yes, then returns the help target to display.820        /// </summary>821        /// <param name="helpTarget">Help target to request.</param>822        /// <param name="helpCategory">Help category to request.</param>823        /// <returns><see langword="true"/> if user requested help; <see langword="false"/> otherwise.</returns>824        internal override bool IsHelpRequested(out string helpTarget, out HelpCategory helpCategory)825        {826            if (this.arguments != null)827            {828                foreach (CommandParameterInternal parameter in this.arguments)829                {830                    Dbg.Assert(parameter != null, "CommandProcessor.arguments shouldn't have any null arguments");831                    if (parameter.IsDashQuestion())832                    {833                        helpCategory = HelpCategory.All;834                        // using InvocationName mainly to avoid bogus this.CommandInfo.Name835                        // (when CmdletInfo.Name is initialized from "cmdlet" declaration836                        //  of a scriptblock and when "cmdlet" declaration doesn't specify any name)837                        if ((this.Command != null) && (this.Command.MyInvocation != null) &&838                            (!string.IsNullOrEmpty(this.Command.MyInvocation.InvocationName)))839                        {840                            helpTarget = this.Command.MyInvocation.InvocationName;841                            // Win8: 391035 get-help does not work properly for aliased cmdlets842                            // For aliased cmdlets/functions,example Initialize-Volume -> Format-Volume,843                            // MyInvocation.InvocationName is different from CommandInfo.Name844                            // - CommandInfo.Name points to Format-Volume845                            // - MyInvocation.InvocationName points to Initialize-Volume846                            if (string.Equals(this.Command.MyInvocation.InvocationName, this.CommandInfo.Name, StringComparison.OrdinalIgnoreCase))847                            {848                                helpCategory = this.CommandInfo.HelpCategory;849                            }850                        }851                        else852                        {853                            helpTarget = this.CommandInfo.Name;854                            helpCategory = this.CommandInfo.HelpCategory;855                        }856 857                        return true;858                    }859                }860            }861 862            return base.IsHelpRequested(out helpTarget, out helpCategory);863        }864 865        #endregion helper_methods866    }867}868