2018-02-13 09:23:53 -08:00
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
// Licensed under the MIT License.
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Management.Automation;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Management.Automation.Internal;
|
|
|
|
|
using System.Management.Automation.Language;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.PowerShell.Commands.Internal.Format
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// facade class to provide context information to process
|
|
|
|
|
/// exceptions
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal sealed class TerminatingErrorContext
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
internal TerminatingErrorContext(PSCmdlet command)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
if (command == null)
|
2016-07-29 13:02:49 -07:00
|
|
|
throw PSTraceSource.NewArgumentNullException("command");
|
2016-03-30 14:20:52 -07:00
|
|
|
_command = command;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
internal void ThrowTerminatingError(ErrorRecord errorRecord)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
_command.ThrowTerminatingError(errorRecord);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PSCmdlet _command;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// helper class to invoke a command in a secondary pipeline.
|
|
|
|
|
/// NOTE: this implementation does not return any error messages
|
|
|
|
|
/// that invoked pipelines might generate
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal sealed class CommandWrapper : IDisposable
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initialize the command before executing
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="execContext">ExecutionContext used to create sub pipeline</param>
|
|
|
|
|
/// <param name="nameOfCommand">name of the command to run</param>
|
|
|
|
|
/// <param name="typeOfCommand">Type of the command to run</param>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal void Initialize(ExecutionContext execContext, string nameOfCommand, Type typeOfCommand)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
_context = execContext;
|
|
|
|
|
_commandName = nameOfCommand;
|
|
|
|
|
_commandType = typeOfCommand;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// add a parameter to the command invocation.
|
|
|
|
|
/// It needs to be called before any execution takes place
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="parameterName">name of the parameter</param>
|
|
|
|
|
/// <param name="parameterValue">value of the parameter</param>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal void AddNamedParameter(string parameterName, object parameterValue)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
_commandParameterList.Add(
|
2016-03-30 14:20:52 -07:00
|
|
|
CommandParameterInternal.CreateParameterWithArgument(
|
2017-10-20 19:28:02 -07:00
|
|
|
/*parameterAst*/null, parameterName, null,
|
|
|
|
|
/*argumentAst*/null, parameterValue,
|
2016-03-30 14:20:52 -07:00
|
|
|
false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// send an object to the pipeline
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="o">object to process</param>
|
|
|
|
|
/// <returns>Array of objects out of the success pipeline</returns>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal Array Process(object o)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_pp == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// if this is the first call, we need to initialize the
|
|
|
|
|
// pipeline underneath
|
2016-07-29 13:02:49 -07:00
|
|
|
DelayedInternalInitialize();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
return _pp.Step(o);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// shut down the pipeline
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Array of objects out of the success pipeline</returns>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal Array ShutDown()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_pp == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// if Process() never got called, no sub pipeline
|
|
|
|
|
// ever got created, hence we just return an empty array
|
|
|
|
|
return new object[0];
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
PipelineProcessor ppTemp = _pp;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
_pp = null;
|
2016-03-30 14:20:52 -07:00
|
|
|
return ppTemp.SynchronousExecuteEnumerate(AutomationNull.Value);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
private void DelayedInternalInitialize()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
_pp = new PipelineProcessor();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
CmdletInfo cmdletInfo = new CmdletInfo(_commandName, _commandType, null, null, _context);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
CommandProcessor cp = new CommandProcessor(cmdletInfo, _context);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
foreach (CommandParameterInternal par in _commandParameterList)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
cp.AddParameter(par);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
_pp.Add(cp);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// just dispose the pipeline processor
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
if (_pp == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
return;
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
_pp.Dispose();
|
|
|
|
|
_pp = null;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
private PipelineProcessor _pp = null;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
private string _commandName = null;
|
|
|
|
|
private Type _commandType;
|
|
|
|
|
private List<CommandParameterInternal> _commandParameterList = new List<CommandParameterInternal>();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
private ExecutionContext _context = null;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// base class for the command-let's we expose
|
|
|
|
|
/// it contains a reference to the implementation
|
|
|
|
|
/// class it wraps
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class FrontEndCommandBase : PSCmdlet, IDisposable
|
|
|
|
|
{
|
|
|
|
|
#region Command Line Switches
|
|
|
|
|
/// <summary>
|
2017-01-16 13:31:14 -08:00
|
|
|
/// This parameter specifies the current pipeline object
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
[Parameter(ValueFromPipeline = true)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public PSObject InputObject { set; get; } = AutomationNull.Value;
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// hook up the calls from the implementation object
|
|
|
|
|
/// and then call the implementation's Begin()
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected override void BeginProcessing()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
Diagnostics.Assert(this.implementation != null, "this.implementation is null");
|
|
|
|
|
this.implementation.OuterCmdletCall = new ImplementationCommandBase.OuterCmdletCallback(this.OuterCmdletCall);
|
|
|
|
|
this.implementation.InputObjectCall = new ImplementationCommandBase.InputObjectCallback(this.InputObjectCall);
|
|
|
|
|
this.implementation.WriteObjectCall = new ImplementationCommandBase.WriteObjectCallback(this.WriteObjectCall);
|
|
|
|
|
|
|
|
|
|
this.implementation.CreateTerminatingErrorContext();
|
|
|
|
|
|
|
|
|
|
implementation.BeginProcessing();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// call the implementation
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected override void ProcessRecord()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
implementation.ProcessRecord();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// call the implementation
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected override void EndProcessing()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
implementation.EndProcessing();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// call the implementation
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void StopProcessing()
|
|
|
|
|
{
|
|
|
|
|
implementation.StopProcessing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback for the implementation to obtain a reference to the Cmdlet object
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Cmdlet reference</returns>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected virtual PSCmdlet OuterCmdletCall()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback for the implementation to get the current pipeline object
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>current object from the pipeline</returns>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected virtual PSObject InputObjectCall()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// just bind to the input object parameter
|
|
|
|
|
return this.InputObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback for the implementation to write objects
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="value">object to be written</param>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected virtual void WriteObjectCall(object value)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// just call Monad API
|
|
|
|
|
this.WriteObject(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// reference to the implementation command that this class
|
|
|
|
|
/// is wrapping
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal ImplementationCommandBase implementation = null;
|
|
|
|
|
|
|
|
|
|
#region IDisposable Implementation
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// default implementation just delegates to internal helper
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>This method calls GC.SuppressFinalize</remarks>
|
2016-07-29 13:02:49 -07:00
|
|
|
public void Dispose()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Dispose pattern implementation
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="disposing"></param>
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
InternalDispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Do-nothing implementation: derived classes will override as see fit
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected virtual void InternalDispose()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
if (this.implementation == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
this.implementation.Dispose();
|
2016-03-30 14:20:52 -07:00
|
|
|
this.implementation = null;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// implementation class to be called by the outer command
|
|
|
|
|
/// In order to properly work, the callbacks have to be properly set by the outer command
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal class ImplementationCommandBase : IDisposable
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// inner version of CommandBase.BeginProcessing()
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual void BeginProcessing()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// inner version of CommandBase.ProcessRecord()
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual void ProcessRecord()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// inner version of CommandBase.EndProcessing()
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual void EndProcessing()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// inner version of CommandBase.StopProcessing()
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal virtual void StopProcessing()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// retrieve the current input pipeline object
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual PSObject ReadObject()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// delegate to the front end object
|
2016-07-29 13:02:49 -07:00
|
|
|
System.Diagnostics.Debug.Assert(this.InputObjectCall != null, "this.InputObjectCall is null");
|
|
|
|
|
return this.InputObjectCall();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// write an object to the pipeline
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="o">object to write to the pipeline</param>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual void WriteObject(object o)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// delegate to the front end object
|
2016-07-29 13:02:49 -07:00
|
|
|
System.Diagnostics.Debug.Assert(this.WriteObjectCall != null, "this.WriteObjectCall is null");
|
|
|
|
|
this.WriteObjectCall(o);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// callback methods to get to the outer Monad Cmdlet
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// get a hold of the Monad outer Cmdlet
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal virtual PSCmdlet OuterCmdlet()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// delegate to the front end object
|
2016-07-29 13:02:49 -07:00
|
|
|
System.Diagnostics.Debug.Assert(this.OuterCmdletCall != null, "this.OuterCmdletCall is null");
|
|
|
|
|
return this.OuterCmdletCall();
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-02 13:29:09 -07:00
|
|
|
protected TerminatingErrorContext TerminatingErrorContext { get; private set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
internal void CreateTerminatingErrorContext()
|
|
|
|
|
{
|
2016-08-02 13:29:09 -07:00
|
|
|
TerminatingErrorContext = new TerminatingErrorContext(this.OuterCmdlet());
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// delegate definition to get to the outer command-let
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal delegate PSCmdlet OuterCmdletCallback();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback to get to the outer command-let
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal OuterCmdletCallback OuterCmdletCall;
|
|
|
|
|
|
|
|
|
|
// callback to the methods to get an object and write an object
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// delegate definition to get to the current pipeline input object
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal delegate PSObject InputObjectCallback();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// delegate definition to write object
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
internal delegate void WriteObjectCallback(object o);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback to read object
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal InputObjectCallback InputObjectCall;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// callback to write object
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal WriteObjectCallback WriteObjectCall;
|
|
|
|
|
|
|
|
|
|
#region IDisposable Implementation
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// default implementation just delegates to internal helper
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>This method calls GC.SuppressFinalize</remarks>
|
2016-07-29 13:02:49 -07:00
|
|
|
public void Dispose()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
InternalDispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Do-nothing implementation: derived classes will override as see fit
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
protected virtual void InternalDispose()
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|