MegaBites-AI/Windows-powershell
0372
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 