Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
InvocationInfo.cs538 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics;8using System.IO;9using System.Management.Automation.Internal;10using System.Management.Automation.Language;11 12namespace System.Management.Automation13{14    /// <summary>15    /// Describes how and where this command was invoked.16    /// </summary>17    [DebuggerDisplay("Command = {MyCommand}")]18    public class InvocationInfo19    {20        #region Constructors21 22        /// <summary>23        /// Constructor for InvocationInfo object when the associated command object is present.24        /// </summary>25        /// <param name="command"></param>26        internal InvocationInfo(InternalCommand command)27            : this(command.CommandInfo,28                   command.InvocationExtent ?? PositionUtilities.EmptyExtent)29        {30            CommandOrigin = command.CommandOrigin;31        }32 33        /// <summary>34        /// Constructor for InvocationInfo object.35        /// </summary>36        /// <param name="commandInfo">37        /// The command information the invocation info represents.38        /// </param>39        /// <param name="scriptPosition">40        /// The position representing the invocation, or the position representing the error.41        /// </param>42        internal InvocationInfo(CommandInfo commandInfo, IScriptExtent scriptPosition)43            : this(commandInfo, scriptPosition, null)44        {45            // nothing to do here46        }47 48        /// <summary>49        /// Constructor for InvocationInfo object.50        /// </summary>51        /// <param name="commandInfo">52        /// The command information the invocation info represents.53        /// </param>54        /// <param name="scriptPosition">55        /// The position representing the invocation, or the position representing the error.56        /// </param>57        /// <param name="context">58        /// The context in which the InvocationInfo is being created.59        /// </param>60        internal InvocationInfo(CommandInfo commandInfo, IScriptExtent scriptPosition, ExecutionContext context)61        {62            MyCommand = commandInfo;63            CommandOrigin = CommandOrigin.Internal;64            _scriptPosition = scriptPosition;65 66            ExecutionContext contextToUse = null;67            if ((commandInfo != null) && (commandInfo.Context != null))68            {69                contextToUse = commandInfo.Context;70            }71            else if (context != null)72            {73                contextToUse = context;74            }75 76            // Populate the history ID of this command77            if (contextToUse != null)78            {79                Runspaces.LocalRunspace localRunspace = contextToUse.CurrentRunspace as Runspaces.LocalRunspace;80                if (localRunspace != null && localRunspace.History != null)81                {82                    HistoryId = localRunspace.History.GetNextHistoryId();83                }84            }85        }86 87        /// <summary>88        /// Creates an InformationalRecord from an instance serialized as a PSObject by ToPSObjectForRemoting.89        /// </summary>90        internal InvocationInfo(PSObject psObject)91        {92            CommandOrigin = (CommandOrigin)SerializationUtilities.GetPsObjectPropertyBaseObject(psObject, "InvocationInfo_CommandOrigin");93            ExpectingInput = (bool)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_ExpectingInput");94            _invocationName = (string)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_InvocationName");95            HistoryId = (long)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_HistoryId");96            PipelineLength = (int)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_PipelineLength");97            PipelinePosition = (int)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_PipelinePosition");98 99            string scriptName = (string)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_ScriptName");100            int scriptLineNumber = (int)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_ScriptLineNumber");101            int offsetInLine = (int)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_OffsetInLine");102            string line = (string)SerializationUtilities.GetPropertyValue(psObject, "InvocationInfo_Line");103            var scriptPosition = new ScriptPosition(scriptName, scriptLineNumber, offsetInLine, line);104 105            ScriptPosition scriptEndPosition;106            if (!string.IsNullOrEmpty(line))107            {108                int endColumn = line.Length + 1;109                scriptEndPosition = new ScriptPosition(scriptName, scriptLineNumber, endColumn, line);110            }111            else112            {113                scriptEndPosition = scriptPosition;114            }115 116            _scriptPosition = new ScriptExtent(scriptPosition, scriptEndPosition);117 118            MyCommand = RemoteCommandInfo.FromPSObjectForRemoting(psObject);119 120            //121            // Arrays are de-serialized as ArrayList so we need to convert the deserialized122            // object into an int[] before assigning to pipelineIterationInfo.123            //124            var list = (ArrayList)SerializationUtilities.GetPsObjectPropertyBaseObject(psObject, "InvocationInfo_PipelineIterationInfo");125            if (list != null)126            {127                PipelineIterationInfo = (int[])list.ToArray(typeof(int));128            }129            else130            {131                PipelineIterationInfo = Array.Empty<int>();132            }133 134            //135            // Dictionaries are de-serialized as Hashtables so we need to convert the deserialized object into a dictionary136            // before assigning to CommandLineParameters.137            //138            Hashtable hashtable = (Hashtable)SerializationUtilities.GetPsObjectPropertyBaseObject(psObject, "InvocationInfo_BoundParameters");139 140            Dictionary<string, object> dictionary = new Dictionary<string, object>();141 142            if (hashtable != null)143            {144                foreach (DictionaryEntry entry in hashtable)145                {146                    dictionary.Add((string)entry.Key, entry.Value);147                }148            }149 150            _boundParameters = dictionary;151 152            //153            // The unbound parameters are de-serialized as an ArrayList, which we need to convert to a List154            //155            var unboundArguments = (ArrayList)SerializationUtilities.GetPsObjectPropertyBaseObject(psObject, "InvocationInfo_UnboundArguments");156 157            _unboundArguments = new List<object>();158 159            if (unboundArguments != null)160            {161                foreach (object o in unboundArguments)162                {163                    _unboundArguments.Add(o);164                }165            }166 167            object value = SerializationUtilities.GetPropertyValue(psObject, "SerializeExtent");168            bool serializeExtent = false;169 170            if (value != null)171                serializeExtent = (bool)value;172 173            if (serializeExtent)174                DisplayScriptPosition = ScriptExtent.FromPSObjectForRemoting(psObject);175        }176 177        #endregion Constructors178 179        #region Private Data180 181        private IScriptExtent _scriptPosition;182        private string _invocationName;183        private Dictionary<string, object> _boundParameters;184        private List<object> _unboundArguments;185 186        #endregion Internal or Private187 188        #region Public Members189 190        /// <summary>191        /// Provide basic information about the command.192        /// </summary>193        /// <value>may be null</value>194        public CommandInfo MyCommand { get; }195 196        /// <summary>197        /// This member provides a dictionary of the parameters that were bound for this198        /// script or command.199        /// </summary>200        public Dictionary<string, object> BoundParameters201        {202            get203            {204                return _boundParameters ??= new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);205            }206 207            internal set208            {209                _boundParameters = value;210            }211        }212 213        /// <summary>214        /// This member provides a list of the arguments that were not bound to any parameter.215        /// </summary>216        public List<object> UnboundArguments217        {218            get { return _unboundArguments ??= new List<object>(); }219 220            internal set { _unboundArguments = value; }221        }222 223        /// <summary>224        /// The line number in the executing script that contained this cmdlet.225        /// </summary>226        /// <value>The script line number or -1 if not executing in a script.</value>227        public int ScriptLineNumber228        {229            get { return ScriptPosition.StartLineNumber; }230        }231 232        /// <summary>233        /// Command's character offset in that line. If the command was234        /// executed directly through the host interfaces, this will be -1.235        /// </summary>236        /// <value>The line offset or -1 if not executed from a text line.</value>237        public int OffsetInLine238        {239            get { return ScriptPosition.StartColumnNumber; }240        }241 242        /// <summary>243        /// History ID that represents the command. If unavailable, this will be -1.244        /// </summary>245        /// <value>The history ID or -1 if not available.</value>246        public long HistoryId { get; internal set; } = -1;247 248        /// <summary>249        /// The name of the script containing the cmdlet.250        /// </summary>251        /// <value>The script name or "" if there was no script.</value>252        public string ScriptName253        {254            get { return ScriptPosition.File ?? string.Empty; }255        }256 257        /// <summary>258        /// The text of the line that contained this cmdlet invocation.259        /// </summary>260        /// <value>Line that was entered to invoke this command</value>261        public string Line262        {263            get264            {265                if (ScriptPosition.StartScriptPosition != null)266                {267                    return ScriptPosition.StartScriptPosition.Line;268                }269 270                return string.Empty;271            }272        }273 274        /// <summary>275        /// The full text of the invocation statement, may span multiple lines.276        /// </summary>277        /// <value>Statement that was entered to invoke this command.</value>278        public string Statement279        {280            get281            {282                return ScriptPosition.Text;283            }284        }285 286        /// <summary>287        /// Formatted message indicating where the cmdlet appeared288        /// in the line.289        /// </summary>290        /// <value>Formatted string indicating the command's position in the line</value>291        public string PositionMessage292        {293            get { return PositionUtilities.VerboseMessage(ScriptPosition); }294        }295 296        /// <summary>297        /// This property tells you the directory from where you were being invoked.298        /// </summary>299        public string PSScriptRoot300        {301            get302            {303                if (!string.IsNullOrEmpty(ScriptPosition.File))304                {305                    return Path.GetDirectoryName(ScriptPosition.File);306                }307                else308                {309                    return string.Empty;310                }311            }312        }313 314        /// <summary>315        /// This property tells you the full path to the command from where you were being invoked.316        /// </summary>317        public string PSCommandPath318        {319            get { return ScriptPosition.File; }320        }321 322        /// <summary>323        /// Command name used to invoke this string - if invoked through an alias, then324        /// this would be the alias name.325        /// </summary>326        /// <value>The name string.</value>327        public string InvocationName328        {329            get { return _invocationName ?? string.Empty; }330 331            internal set { _invocationName = value; }332        }333 334        /// <summary>335        /// How many elements are in the containing pipeline.336        /// </summary>337        /// <value>number of elements in the containing pipeline</value>338        public int PipelineLength { get; internal set; }339 340        /// <summary>341        /// Which element this command was in the containing pipeline.342        /// </summary>343        /// <value>which element this command was in the containing pipeline</value>344        public int PipelinePosition { get; internal set; }345 346        /// <summary>347        /// Is true if this command is expecting input...348        /// </summary>349        public bool ExpectingInput { get; internal set; }350 351        /// <summary>352        /// This property tells you if you were being invoked inside the runspace or353        /// if it was an external request.354        /// </summary>355        public CommandOrigin CommandOrigin { get; internal set; }356 357        /// <summary>358        /// The position for the invocation or error.359        /// </summary>360        public IScriptExtent DisplayScriptPosition { get; set; }361 362        /// <summary>363        /// Create.364        /// </summary>365        /// <param name="commandInfo"></param>366        /// <param name="scriptPosition"></param>367        /// <returns></returns>368        public static InvocationInfo Create(369            CommandInfo commandInfo,370            IScriptExtent scriptPosition)371        {372            var invocationInfo = new InvocationInfo(commandInfo, scriptPosition);373            invocationInfo.DisplayScriptPosition = scriptPosition;374 375            return invocationInfo;376        }377 378        #endregion Public Members379 380        #region Internal Members381 382        /// <summary>383        /// The position for the invocation or error.384        /// </summary>385        internal IScriptExtent ScriptPosition386        {387            get388            {389                if (DisplayScriptPosition != null)390                {391                    return DisplayScriptPosition;392                }393                else394                {395                    return _scriptPosition;396                }397            }398 399            set400            {401                _scriptPosition = value;402            }403        }404 405        /// <summary>406        /// Returns the full text of the script for this invocation info.407        /// </summary>408        internal string GetFullScript()409        {410            return (ScriptPosition != null) && (ScriptPosition.StartScriptPosition != null) ?411                ScriptPosition.StartScriptPosition.GetFullScript() : null;412        }413 414        /// <summary>415        /// Index of the ProcessRecord iteration for each of the commands in the pipeline.416        /// </summary>417        /// <remarks>418        /// All the commands in a given pipeline share the same PipelinePositionInfo.419        /// </remarks>420        internal int[] PipelineIterationInfo { get; set; } = Array.Empty<int>();421 422        /// <summary>423        /// Adds the information about this informational record to a PSObject as note properties.424        /// The PSObject is used to serialize the record during remote operations.425        /// </summary>426        /// <remarks>427        /// InvocationInfos are usually serialized as part of another object, so we add "InvocationInfo_" to428        /// the note properties to prevent collisions with any properties set by the containing object.429        /// </remarks>430        internal void ToPSObjectForRemoting(PSObject psObject)431        {432            RemotingEncoder.AddNoteProperty<object>(psObject, "InvocationInfo_BoundParameters", () => this.BoundParameters);433            RemotingEncoder.AddNoteProperty<CommandOrigin>(psObject, "InvocationInfo_CommandOrigin", () => this.CommandOrigin);434            RemotingEncoder.AddNoteProperty<bool>(psObject, "InvocationInfo_ExpectingInput", () => this.ExpectingInput);435            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_InvocationName", () => this.InvocationName);436            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_Line", () => this.Line);437            RemotingEncoder.AddNoteProperty<int>(psObject, "InvocationInfo_OffsetInLine", () => this.OffsetInLine);438            RemotingEncoder.AddNoteProperty<long>(psObject, "InvocationInfo_HistoryId", () => this.HistoryId);439            RemotingEncoder.AddNoteProperty<int[]>(psObject, "InvocationInfo_PipelineIterationInfo", () => this.PipelineIterationInfo);440            RemotingEncoder.AddNoteProperty<int>(psObject, "InvocationInfo_PipelineLength", () => this.PipelineLength);441            RemotingEncoder.AddNoteProperty<int>(psObject, "InvocationInfo_PipelinePosition", () => this.PipelinePosition);442            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_PSScriptRoot", () => this.PSScriptRoot);443            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_PSCommandPath", () => this.PSCommandPath);444            // PositionMessage is ignored when deserializing because it is synthesized from the other position related fields, but445            // it is serialized for backwards compatibility.446            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_PositionMessage", () => this.PositionMessage);447            RemotingEncoder.AddNoteProperty<int>(psObject, "InvocationInfo_ScriptLineNumber", () => this.ScriptLineNumber);448            RemotingEncoder.AddNoteProperty<string>(psObject, "InvocationInfo_ScriptName", () => this.ScriptName);449            RemotingEncoder.AddNoteProperty<object>(psObject, "InvocationInfo_UnboundArguments", () => this.UnboundArguments);450 451            ScriptExtent extent = DisplayScriptPosition as ScriptExtent;452            if (extent != null)453            {454                extent.ToPSObjectForRemoting(psObject);455                RemotingEncoder.AddNoteProperty(psObject, "SerializeExtent", static () => true);456            }457            else458            {459                RemotingEncoder.AddNoteProperty(psObject, "SerializeExtent", static () => false);460            }461 462            RemoteCommandInfo.ToPSObjectForRemoting(this.MyCommand, psObject);463        }464 465        #endregion Internal Members466    }467 468    /// <summary>469    /// A CommandInfo that has been serialized/deserialized as part of an InvocationInfo during a remote invocation.470    /// </summary>471    public class RemoteCommandInfo : CommandInfo472    {473        /// <summary>474        /// </summary>475        private RemoteCommandInfo(string name, CommandTypes type)476            : base(name, type)477        {478            // nothing to do here479        }480 481        /// <summary>482        /// A string representing the definition of the command.483        /// </summary>484        public override string Definition { get { return _definition; } }485 486        /// <summary>487        /// Creates a RemoteCommandInfo from an instance serialized as a PSObject by ToPSObjectForRemoting.488        /// </summary>489        internal static RemoteCommandInfo FromPSObjectForRemoting(PSObject psObject)490        {491            RemoteCommandInfo commandInfo = null;492 493            object ctype = SerializationUtilities.GetPsObjectPropertyBaseObject(psObject, "CommandInfo_CommandType");494 495            if (ctype != null)496            {497                CommandTypes type = RemotingDecoder.GetPropertyValue<CommandTypes>(psObject, "CommandInfo_CommandType");498                string name = RemotingDecoder.GetPropertyValue<string>(psObject, "CommandInfo_Name");499 500                commandInfo = new RemoteCommandInfo(name, type);501                commandInfo._definition = RemotingDecoder.GetPropertyValue<string>(psObject, "CommandInfo_Definition");502                commandInfo.Visibility = RemotingDecoder.GetPropertyValue<SessionStateEntryVisibility>(psObject, "CommandInfo_Visibility");503            }504 505            return commandInfo;506        }507 508        /// <summary>509        /// Adds the information about this instance to a PSObject as note properties.510        /// The PSObject is used to serialize the CommandInfo during remote operations.511        /// </summary>512        /// <remarks>513        /// CommandInfos are usually serialized as part of InvocationInfos, so we add "CommandInfo_" to514        /// the note properties to prevent collisions with any properties set by the containing object.515        /// </remarks>516        internal static void ToPSObjectForRemoting(CommandInfo commandInfo, PSObject psObject)517        {518            if (commandInfo != null)519            {520                RemotingEncoder.AddNoteProperty<CommandTypes>(psObject, "CommandInfo_CommandType", () => commandInfo.CommandType);521                RemotingEncoder.AddNoteProperty<string>(psObject, "CommandInfo_Definition", () => commandInfo.Definition);522                RemotingEncoder.AddNoteProperty<string>(psObject, "CommandInfo_Name", () => commandInfo.Name);523                RemotingEncoder.AddNoteProperty<SessionStateEntryVisibility>(psObject, "CommandInfo_Visibility", () => commandInfo.Visibility);524            }525        }526 527        /// <summary>528        /// NYI.529        /// </summary>530        public override ReadOnlyCollection<PSTypeName> OutputType531        {532            get { return null; }533        }534 535        private string _definition;536    }537}538