MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Management.Automation;7using System.Management.Automation.Internal;8using System.Management.Automation.Language;9 10namespace Microsoft.PowerShell.Commands.Internal.Format11{12 /// <summary>13 /// Facade class to provide context information to process14 /// exceptions.15 /// </summary>16 internal sealed class TerminatingErrorContext17 {18 internal TerminatingErrorContext(PSCmdlet command)19 {20 if (command == null)21 throw PSTraceSource.NewArgumentNullException(nameof(command));22 _command = command;23 }24 25 [System.Diagnostics.CodeAnalysis.DoesNotReturn]26 internal void ThrowTerminatingError(ErrorRecord errorRecord)27 {28 _command.ThrowTerminatingError(errorRecord);29 }30 31 private readonly PSCmdlet _command;32 }33 34 /// <summary>35 /// Helper class to invoke a command in a secondary pipeline.36 /// NOTE: this implementation does not return any error messages37 /// that invoked pipelines might generate.38 /// </summary>39 internal sealed class CommandWrapper : IDisposable40 {41 /// <summary>42 /// Initialize the command before executing.43 /// </summary>44 /// <param name="execContext">ExecutionContext used to create sub pipeline.</param>45 /// <param name="nameOfCommand">Name of the command to run.</param>46 /// <param name="typeOfCommand">Type of the command to run.</param>47 internal void Initialize(ExecutionContext execContext, string nameOfCommand, Type typeOfCommand)48 {49 _context = execContext;50 _commandName = nameOfCommand;51 _commandType = typeOfCommand;52 }53 54 /// <summary>55 /// Add a parameter to the command invocation.56 /// It needs to be called before any execution takes place.57 /// </summary>58 /// <param name="parameterName">Name of the parameter.</param>59 /// <param name="parameterValue">Value of the parameter.</param>60 internal void AddNamedParameter(string parameterName, object parameterValue)61 {62 _commandParameterList.Add(63 CommandParameterInternal.CreateParameterWithArgument(64 /*parameterAst*/null, parameterName, null,65 /*argumentAst*/null, parameterValue,66 false));67 }68 69 /// <summary>70 /// Send an object to the pipeline.71 /// </summary>72 /// <param name="o">Object to process.</param>73 /// <returns>Array of objects out of the success pipeline.</returns>74 internal Array Process(object o)75 {76 if (_pp == null)77 {78 // if this is the first call, we need to initialize the79 // pipeline underneath80 DelayedInternalInitialize();81 }82 83 return _pp.Step(o);84 }85 86 /// <summary>87 /// Shut down the pipeline.88 /// </summary>89 /// <returns>Array of objects out of the success pipeline.</returns>90 internal Array ShutDown()91 {92 if (_pp == null)93 {94 // if Process() never got called, no sub pipeline95 // ever got created, hence we just return an empty array96 return Array.Empty<object>();97 }98 99 PipelineProcessor ppTemp = _pp;100 101 _pp = null;102 return ppTemp.SynchronousExecuteEnumerate(AutomationNull.Value);103 }104 105 private void DelayedInternalInitialize()106 {107 _pp = new PipelineProcessor();108 109 CmdletInfo cmdletInfo = new CmdletInfo(_commandName, _commandType, null, null, _context);110 111 CommandProcessor cp = new CommandProcessor(cmdletInfo, _context);112 113 foreach (CommandParameterInternal par in _commandParameterList)114 {115 cp.AddParameter(par);116 }117 118 _pp.Add(cp);119 }120 121 /// <summary>122 /// Just dispose the pipeline processor.123 /// </summary>124 public void Dispose()125 {126 if (_pp == null)127 return;128 129 _pp.Dispose();130 _pp = null;131 }132 133 private PipelineProcessor _pp = null;134 135 private string _commandName = null;136 private Type _commandType;137 private readonly List<CommandParameterInternal> _commandParameterList = new List<CommandParameterInternal>();138 139 private ExecutionContext _context = null;140 }141 142 /// <summary>143 /// Base class for the command-let's we expose144 /// it contains a reference to the implementation145 /// class it wraps.146 /// </summary>147 public abstract class FrontEndCommandBase : PSCmdlet, IDisposable148 {149 #region Command Line Switches150 /// <summary>151 /// This parameter specifies the current pipeline object.152 /// </summary>153 [Parameter(ValueFromPipeline = true)]154 public PSObject InputObject { get; set; } = AutomationNull.Value;155 156 #endregion157 158 /// <summary>159 /// Hook up the calls from the implementation object160 /// and then call the implementation's Begin()161 /// </summary>162 protected override void BeginProcessing()163 {164 Diagnostics.Assert(this.implementation != null, "this.implementation is null");165 this.implementation.OuterCmdletCall = new ImplementationCommandBase.OuterCmdletCallback(this.OuterCmdletCall);166 this.implementation.InputObjectCall = new ImplementationCommandBase.InputObjectCallback(this.InputObjectCall);167 this.implementation.WriteObjectCall = new ImplementationCommandBase.WriteObjectCallback(this.WriteObjectCall);168 169 this.implementation.CreateTerminatingErrorContext();170 171 implementation.BeginProcessing();172 }173 174 /// <summary>175 /// Call the implementation.176 /// </summary>177 protected override void ProcessRecord()178 {179 implementation.ProcessRecord();180 }181 182 /// <summary>183 /// Call the implementation.184 /// </summary>185 protected override void EndProcessing()186 {187 implementation.EndProcessing();188 }189 190 /// <summary>191 /// Call the implementation.192 /// </summary>193 protected override void StopProcessing()194 {195 implementation.StopProcessing();196 }197 198 /// <summary>199 /// Callback for the implementation to obtain a reference to the Cmdlet object.200 /// </summary>201 /// <returns>Cmdlet reference.</returns>202 protected virtual PSCmdlet OuterCmdletCall()203 {204 return this;205 }206 207 /// <summary>208 /// Callback for the implementation to get the current pipeline object.209 /// </summary>210 /// <returns>Current object from the pipeline.</returns>211 protected virtual PSObject InputObjectCall()212 {213 // just bind to the input object parameter214 return this.InputObject;215 }216 217 /// <summary>218 /// Callback for the implementation to write objects.219 /// </summary>220 /// <param name="value">Object to be written.</param>221 protected virtual void WriteObjectCall(object value)222 {223 // just call Monad API224 this.WriteObject(value);225 }226 227 /// <summary>228 /// Reference to the implementation command that this class229 /// is wrapping.230 /// </summary>231 internal ImplementationCommandBase implementation = null;232 233 #region IDisposable Implementation234 235 /// <summary>236 /// Default implementation just delegates to internal helper.237 /// </summary>238 /// <remarks>This method calls GC.SuppressFinalize</remarks>239 public void Dispose()240 {241 Dispose(true);242 243 GC.SuppressFinalize(this);244 }245 246 /// <summary>247 /// Dispose pattern implementation.248 /// </summary>249 /// <param name="disposing"></param>250 protected virtual void Dispose(bool disposing)251 {252 if (disposing)253 {254 InternalDispose();255 }256 }257 258 /// <summary>259 /// Do-nothing implementation: derived classes will override as see fit.260 /// </summary>261 protected virtual void InternalDispose()262 {263 if (this.implementation == null)264 return;265 266 this.implementation.Dispose();267 this.implementation = null;268 }269 #endregion270 }271 272 /// <summary>273 /// Implementation class to be called by the outer command274 /// In order to properly work, the callbacks have to be properly set by the outer command.275 /// </summary>276 internal class ImplementationCommandBase : IDisposable277 {278 /// <summary>279 /// Inner version of CommandBase.BeginProcessing()280 /// </summary>281 internal virtual void BeginProcessing()282 {283 }284 285 /// <summary>286 /// Inner version of CommandBase.ProcessRecord()287 /// </summary>288 internal virtual void ProcessRecord()289 {290 }291 292 /// <summary>293 /// Inner version of CommandBase.EndProcessing()294 /// </summary>295 internal virtual void EndProcessing()296 {297 }298 299 /// <summary>300 /// Inner version of CommandBase.StopProcessing()301 /// </summary>302 internal virtual void StopProcessing()303 {304 }305 306 /// <summary>307 /// Retrieve the current input pipeline object.308 /// </summary>309 internal virtual PSObject ReadObject()310 {311 // delegate to the front end object312 System.Diagnostics.Debug.Assert(this.InputObjectCall != null, "this.InputObjectCall is null");313 return this.InputObjectCall();314 }315 316 /// <summary>317 /// Write an object to the pipeline.318 /// </summary>319 /// <param name="o">Object to write to the pipeline.</param>320 internal virtual void WriteObject(object o)321 {322 // delegate to the front end object323 System.Diagnostics.Debug.Assert(this.WriteObjectCall != null, "this.WriteObjectCall is null");324 this.WriteObjectCall(o);325 }326 327 // callback methods to get to the outer Monad Cmdlet328 /// <summary>329 /// Get a hold of the Monad outer Cmdlet.330 /// </summary>331 /// <returns></returns>332 internal virtual PSCmdlet OuterCmdlet()333 {334 // delegate to the front end object335 System.Diagnostics.Debug.Assert(this.OuterCmdletCall != null, "this.OuterCmdletCall is null");336 return this.OuterCmdletCall();337 }338 339 protected TerminatingErrorContext TerminatingErrorContext { get; private set; }340 341 internal void CreateTerminatingErrorContext()342 {343 TerminatingErrorContext = new TerminatingErrorContext(this.OuterCmdlet());344 }345 346 /// <summary>347 /// Delegate definition to get to the outer command-let.348 /// </summary>349 internal delegate PSCmdlet OuterCmdletCallback();350 351 /// <summary>352 /// Callback to get to the outer command-let.353 /// </summary>354 internal OuterCmdletCallback OuterCmdletCall;355 356 // callback to the methods to get an object and write an object357 /// <summary>358 /// Delegate definition to get to the current pipeline input object.359 /// </summary>360 internal delegate PSObject InputObjectCallback();361 362 /// <summary>363 /// Delegate definition to write object.364 /// </summary>365 internal delegate void WriteObjectCallback(object o);366 367 /// <summary>368 /// Callback to read object.369 /// </summary>370 internal InputObjectCallback InputObjectCall;371 372 /// <summary>373 /// Callback to write object.374 /// </summary>375 internal WriteObjectCallback WriteObjectCall;376 377 #region IDisposable Implementation378 379 /// <summary>380 /// Default implementation just delegates to internal helper.381 /// </summary>382 /// <remarks>This method calls GC.SuppressFinalize</remarks>383 public void Dispose()384 {385 Dispose(true);386 387 GC.SuppressFinalize(this);388 }389 390 private void Dispose(bool disposing)391 {392 if (disposing)393 {394 InternalDispose();395 }396 }397 398 /// <summary>399 /// Do-nothing implementation: derived classes will override as see fit.400 /// </summary>401 protected virtual void InternalDispose()402 {403 }404 #endregion405 406 }407}408 