Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
MshHostUserInterface.cs1481 linesDownload Raw Back to hostifaces
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.Globalization;8using System.IO;9using System.Management.Automation.Configuration;10using System.Management.Automation.Internal;11using System.Management.Automation.Runspaces;12using System.Security;13using System.Text;14using System.Threading;15using System.Threading.Tasks;16 17namespace System.Management.Automation.Host18{19    /// <summary>20    /// Defines the properties and facilities providing by an hosting application deriving from21    /// <see cref="System.Management.Automation.Host.PSHost"/> that offers dialog-oriented and22    /// line-oriented interactive features.23    /// </summary>24    /// <seealso cref="System.Management.Automation.Host.PSHost"/>25    /// <seealso cref="System.Management.Automation.Host.PSHostRawUserInterface"/>26    public abstract class PSHostUserInterface27    {28        /// <summary>29        /// Gets hosting application's implementation of the30        /// <see cref="System.Management.Automation.Host.PSHostRawUserInterface"/> abstract base class31        /// that implements that class.32        /// </summary>33        /// <value>34        /// A reference to an instance of the hosting application's implementation of a class derived from35        /// <see cref="System.Management.Automation.Host.PSHostUserInterface"/>, or null to indicate that36        /// low-level user interaction is not supported.37        /// </value>38        public abstract System.Management.Automation.Host.PSHostRawUserInterface RawUI39        {40            get;41        }42 43        /// <summary>44        /// Returns true for hosts that support VT100 like virtual terminals.45        /// </summary>46        public virtual bool SupportsVirtualTerminal { get { return false; } }47 48        #region Line-oriented interaction49        /// <summary>50        /// Reads characters from the console until a newline (a carriage return) is encountered.51        /// </summary>52        /// <returns>53        /// The characters typed by the user.54        /// </returns>55        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLineAsSecureString"/>56        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>57        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>58        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>59        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>60        public abstract string ReadLine();61 62        /// <summary>63        /// Same as ReadLine, except that the result is a SecureString, and that the input is not echoed to the user while it is64        /// collected (or is echoed in some obfuscated way, such as showing a dot for each character).65        /// </summary>66        /// <returns>67        /// The characters typed by the user in an encrypted form.68        /// </returns>69        /// <remarks>70        /// Note that credentials (a user name and password) should be gathered with71        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>72        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>73        /// </remarks>74        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>75        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>76        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>77        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>78        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>79        public abstract SecureString ReadLineAsSecureString();80 81        /// <summary>82        /// Writes characters to the screen buffer.  Does not append a carriage return.83        /// <!-- Here we choose to just offer string parameters rather than the 18 overloads from TextWriter -->84        /// </summary>85        /// <param name="value">86        /// The characters to be written.  null is not allowed.87        /// </param>88        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(ConsoleColor, ConsoleColor, string)"/>89        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/>90        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>91        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(System.ConsoleColor, System.ConsoleColor, string)"/>92        public abstract void Write(string value);93 94        /// <summary>95        /// Same as <see cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>,96        /// except that colors can be specified.97        /// </summary>98        /// <param name="foregroundColor">99        /// The foreground color to display the text with.100        /// </param>101        /// <param name="backgroundColor">102        /// The foreground color to display the text with.103        /// </param>104        /// <param name="value">105        /// The characters to be written.  null is not allowed.106        /// </param>107        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>108        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/>109        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>110        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(System.ConsoleColor, System.ConsoleColor, string)"/>111        public abstract void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value);112 113        /// <summary>114        /// The default implementation writes a carriage return to the screen buffer.115        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>116        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.Write(System.ConsoleColor, System.ConsoleColor, string)"/>117        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>118        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(System.ConsoleColor, System.ConsoleColor, string)"/>119        /// </summary>120        public virtual void WriteLine()121        {122            WriteLine(string.Empty);123        }124 125        /// <summary>126        /// Writes characters to the screen buffer, and appends a carriage return.127        /// </summary>128        /// <param name="value">129        /// The characters to be written.  null is not allowed.130        /// </param>131        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>132        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(System.ConsoleColor, System.ConsoleColor, string)"/>133        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/>134        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(System.ConsoleColor, System.ConsoleColor, string)"/>135        public abstract void WriteLine(string value);136 137        /// <summary>138        /// Same as <see cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>,139        /// except that colors can be specified.140        /// </summary>141        /// <param name="foregroundColor">142        /// The foreground color to display the text with.143        /// </param>144        /// <param name="backgroundColor">145        /// The foreground color to display the text with.146        /// </param>147        /// <param name="value">148        /// The characters to be written.  null is not allowed.149        /// </param>150        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>151        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(System.ConsoleColor, System.ConsoleColor, string)"/>152        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/>153        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>154        public virtual void WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value)155        {156            // #pragma warning disable 56506157 158            // expressly not checking for value == null so that attempts to write a null cause an exception159 160            if ((value != null) && (value.Length != 0))161            {162                Write(foregroundColor, backgroundColor, value);163            }164 165            Write("\n");166 167            // #pragma warning restore 56506168        }169 170        /// <summary>171        /// Writes a line to the "error display" of the host, as opposed to the "output display," which is172        /// written to by the variants of173        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>174        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.Write(System.ConsoleColor, System.ConsoleColor, string)"/>175        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/> and176        /// <see cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>177        /// </summary>178        /// <param name="value">179        /// The characters to be written.180        /// </param>181        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(string)"/>182        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Write(System.ConsoleColor, System.ConsoleColor, string)"/>183        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine()"/>184        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteLine(string)"/>185        public abstract void WriteErrorLine(string value);186 187        /// <summary>188        /// Invoked by <see cref="System.Management.Automation.Cmdlet.WriteDebug"/> to display a debugging message189        /// to the user.190        /// </summary>191        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteProgress"/>192        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteVerboseLine"/>193        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteWarningLine"/>194        public abstract void WriteDebugLine(string message);195 196        /// <summary>197        /// Invoked by <see cref="System.Management.Automation.Cmdlet.WriteProgress(Int64, System.Management.Automation.ProgressRecord)"/> to display a progress record.198        /// </summary>199        /// <param name="sourceId">200        /// Unique identifier of the source of the record.  An int64 is used because typically, the 'this' pointer of201        /// the command from whence the record is originating is used, and that may be from a remote Runspace on a 64-bit202        /// machine.203        /// </param>204        /// <param name="record">205        /// The record being reported to the host.206        /// </param>207        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteDebugLine"/>208        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteVerboseLine"/>209        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteWarningLine"/>210        public abstract void WriteProgress(Int64 sourceId, ProgressRecord record);211 212        /// <summary>213        /// Invoked by <see cref="System.Management.Automation.Cmdlet.WriteVerbose"/> to display a verbose processing message to the user.214        /// </summary>215        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteDebugLine"/>216        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteProgress"/>217        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteWarningLine"/>218        public abstract void WriteVerboseLine(string message);219 220        /// <summary>221        /// Invoked by <see cref="System.Management.Automation.Cmdlet.WriteWarning"/> to display a warning processing message to the user.222        /// </summary>223        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteDebugLine"/>224        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteProgress"/>225        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.WriteVerboseLine"/>226        public abstract void WriteWarningLine(string message);227 228        /// <summary>229        /// Invoked by <see cref="System.Management.Automation.Cmdlet.WriteInformation(InformationRecord)"/> to give the host a chance to intercept230        /// informational messages. These should not be displayed to the user by default, but may be useful to display in231        /// a separate area of the user interface.232        /// </summary>233        public virtual void WriteInformation(InformationRecord record) { }234 235        private static bool ShouldOutputPlainText(bool isHost, bool? supportsVirtualTerminal)236        {237            var outputRendering = OutputRendering.PlainText;238 239            if (supportsVirtualTerminal != false)240            {241                switch (PSStyle.Instance.OutputRendering)242                {243                    case OutputRendering.Host:244                        outputRendering = isHost ? OutputRendering.Ansi : OutputRendering.PlainText;245                        break;246                    default:247                        outputRendering = PSStyle.Instance.OutputRendering;248                        break;249                }250            }251 252            return outputRendering == OutputRendering.PlainText;253        }254 255        /// <summary>256        /// The format styles that are supported by the host.257        /// </summary>258        public enum FormatStyle259        {260            /// <summary>261            /// Reset the formatting to the default.262            /// </summary>263            Reset,264 265            /// <summary>266            /// Highlight text used in output formatting.267            /// </summary>268            FormatAccent,269 270            /// <summary>271            /// Highlight for table headers.272            /// </summary>273            TableHeader,274 275            /// <summary>276            /// Highlight for detailed error view.277            /// </summary>278            ErrorAccent,279 280            /// <summary>281            /// Style for error messages.282            /// </summary>283            Error,284 285            /// <summary>286            /// Style for warning messages.287            /// </summary>288            Warning,289 290            /// <summary>291            /// Style for verbose messages.292            /// </summary>293            Verbose,294 295            /// <summary>296            /// Style for debug messages.297            /// </summary>298            Debug,299        }300 301        /// <summary>302        /// Get the ANSI escape sequence for the given format style.303        /// </summary>304        /// <param name="formatStyle">305        /// The format style to get the escape sequence for.306        /// </param>307        /// <returns>308        /// The ANSI escape sequence for the given format style.309        /// </returns>310        public static string GetFormatStyleString(FormatStyle formatStyle)311        {312            if (PSStyle.Instance.OutputRendering == OutputRendering.PlainText)313            {314                return string.Empty;315            }316 317            PSStyle psstyle = PSStyle.Instance;318            switch (formatStyle)319            {320                case FormatStyle.Reset:321                    return psstyle.Reset;322                case FormatStyle.FormatAccent:323                    return psstyle.Formatting.FormatAccent;324                case FormatStyle.TableHeader:325                    return psstyle.Formatting.TableHeader;326                case FormatStyle.ErrorAccent:327                    return psstyle.Formatting.ErrorAccent;328                case FormatStyle.Error:329                    return psstyle.Formatting.Error;330                case FormatStyle.Warning:331                    return psstyle.Formatting.Warning;332                case FormatStyle.Verbose:333                    return psstyle.Formatting.Verbose;334                case FormatStyle.Debug:335                    return psstyle.Formatting.Debug;336                default:337                    return string.Empty;338            }339        }340 341        /// <summary>342        /// Get the appropriate output string based on different criteria.343        /// </summary>344        /// <param name="text">345        /// The text to format.346        /// </param>347        /// <param name="supportsVirtualTerminal">348        /// True if the host supports virtual terminal.349        /// </param>350        /// <returns>351        /// The formatted text.352        /// </returns>353        public static string GetOutputString(string text, bool supportsVirtualTerminal)354        {355            return GetOutputString(text, isHost: true, supportsVirtualTerminal: supportsVirtualTerminal);356        }357 358        internal static string GetOutputString(string text, bool isHost, bool? supportsVirtualTerminal = null)359        {360            var sd = new ValueStringDecorated(text);361 362            if (sd.IsDecorated)363            {364                var outputRendering = OutputRendering.Ansi;365                if (ShouldOutputPlainText(isHost, supportsVirtualTerminal))366                {367                    outputRendering = OutputRendering.PlainText;368                }369 370                text = sd.ToString(outputRendering);371            }372 373            return text;374        }375 376        // Gets the state associated with PowerShell transcription.377        //378        // Ideally, this would be associated with the host instance, but remoting recycles host instances379        // for each command that gets invoked (so that it can keep track of the order of commands and their380        // output.) Therefore, we store this transcription data in the runspace. However, the381        // Runspace.DefaultRunspace property isn't always available (i.e.: when the pipeline is being set up),382        // so we have to cache it the first time it becomes available.383        private TranscriptionData TranscriptionData384        {385            get386            {387                // If we have access to a runspace, use the transcription data for that runspace.388                // This is important when you have multiple runspaces within a host.389                LocalRunspace localRunspace = Runspace.DefaultRunspace as LocalRunspace;390                if (localRunspace != null)391                {392                    _volatileTranscriptionData = localRunspace.TranscriptionData;393                    if (_volatileTranscriptionData != null)394                    {395                        return _volatileTranscriptionData;396                    }397                }398 399                // Otherwise, use the last stored transcription data. This will let us transcribe400                // errors where the runspace has gone away.401                if (_volatileTranscriptionData != null)402                {403                    return _volatileTranscriptionData;404                }405 406                TranscriptionData temporaryTranscriptionData = new TranscriptionData();407                return temporaryTranscriptionData;408            }409        }410 411        private TranscriptionData _volatileTranscriptionData;412 413        /// <summary>414        /// Transcribes a command being invoked.415        /// </summary>416        /// <param name="commandText">The text of the command being invoked.</param>417        /// <param name="invocation">The invocation info of the command being transcribed.</param>418        internal void TranscribeCommand(string commandText, InvocationInfo invocation)419        {420            if (ShouldIgnoreCommand(commandText, invocation))421            {422                return;423            }424 425            if (IsTranscribing)426            {427                // We don't actually log the output here, because there may be multiple command invocations428                // in a single input - especially in the case of API logging, which logs the command and429                // its parameters as separate calls.430                // Instead, we add this to the 'pendingOutput' collection, which we flush when either431                // the command generates output, or when we are told to invoke ignore the next command.432                foreach (TranscriptionOption transcript in TranscriptionData.Transcripts.Prepend<TranscriptionOption>(TranscriptionData.SystemTranscript))433                {434                    if (transcript != null)435                    {436                        lock (transcript.OutputToLog)437                        {438                            if (transcript.OutputToLog.Count == 0)439                            {440                                if (transcript.IncludeInvocationHeader)441                                {442                                    transcript.OutputToLog.Add("**********************");443                                    transcript.OutputToLog.Add(444                                        string.Format(445                                            Globalization.CultureInfo.InvariantCulture, InternalHostUserInterfaceStrings.CommandStartTime,446                                            DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture)));447                                    transcript.OutputToLog.Add("**********************");448                                }449 450                                transcript.OutputToLog.Add(TranscriptionData.PromptText + commandText);451                            }452                            else453                            {454                                transcript.OutputToLog.Add(">> " + commandText);455                            }456                        }457                    }458                }459            }460        }461 462        private bool ShouldIgnoreCommand(string logElement, InvocationInfo invocation)463        {464            string commandName = logElement;465 466            if (invocation != null)467            {468                commandName = invocation.InvocationName;469 470                // Do not transcribe Out-Default471                CmdletInfo invocationCmdlet = invocation.MyCommand as CmdletInfo;472                if (invocationCmdlet != null)473                {474                    if (invocationCmdlet.ImplementingType == typeof(Microsoft.PowerShell.Commands.OutDefaultCommand))475                    {476                        // We will ignore transcribing the command itself, but not call the IgnoreCommand() method477                        // (because that will ignore the results)478                        return true;479                    }480                }481 482                // Don't log internal commands to the transcript.483                if (invocation.CommandOrigin == CommandOrigin.Internal)484                {485                    IgnoreCommand(logElement, invocation);486                    return true;487                }488            }489 490            // Don't log helper commands to the transcript491            string[] helperCommands = { "TabExpansion2", "prompt", "TabExpansion", "PSConsoleHostReadline" };492            foreach (string helperCommand in helperCommands)493            {494                if (string.Equals(helperCommand, commandName, StringComparison.OrdinalIgnoreCase))495                {496                    IgnoreCommand(logElement, invocation);497 498                    // Record that this is a helper command. In this case, we ignore even the results499                    // from Out-Default500                    TranscriptionData.IsHelperCommand = true;501                    return true;502                }503            }504 505            return false;506        }507 508        /// <summary>509        /// Signals that a command being invoked (and its output) should be ignored.510        /// </summary>511        /// <param name="commandText">The text of the command being invoked.</param>512        /// <param name="invocation">The invocation info of the command being transcribed.</param>513        internal void IgnoreCommand(string commandText, InvocationInfo invocation)514        {515            TranscribeCommandComplete(null);516 517            if (TranscriptionData.CommandBeingIgnored == null)518            {519                TranscriptionData.CommandBeingIgnored = commandText;520                TranscriptionData.IsHelperCommand = false;521 522                if ((invocation != null) && (invocation.MyCommand != null))523                {524                    TranscriptionData.CommandBeingIgnored = invocation.MyCommand.Name;525                }526            }527        }528 529        /// <summary>530        /// Flag to determine whether the host is in "Transcribe Only" mode,531        /// so that when content is sent through Out-Default it doesn't532        /// make it to the actual host.533        /// </summary>534        internal bool TranscribeOnly => Interlocked.CompareExchange(ref _transcribeOnlyCount, 0, 0) != 0;535 536        private int _transcribeOnlyCount = 0;537 538        internal IDisposable SetTranscribeOnly() => new TranscribeOnlyCookie(this);539 540        private sealed class TranscribeOnlyCookie : IDisposable541        {542            private readonly PSHostUserInterface _ui;543            private bool _disposed = false;544 545            public TranscribeOnlyCookie(PSHostUserInterface ui)546            {547                _ui = ui;548                Interlocked.Increment(ref _ui._transcribeOnlyCount);549            }550 551            public void Dispose()552            {553                if (!_disposed)554                {555                    Interlocked.Decrement(ref _ui._transcribeOnlyCount);556                    _disposed = true;557                    GC.SuppressFinalize(this);558                }559            }560 561            ~TranscribeOnlyCookie() => Dispose();562        }563 564        /// <summary>565        /// Flag to determine whether the host is transcribing.566        /// </summary>567        internal bool IsTranscribing568        {569            get570            {571                CheckSystemTranscript();572                return (TranscriptionData.Transcripts.Count > 0) || (TranscriptionData.SystemTranscript != null);573            }574        }575 576        private void CheckSystemTranscript()577        {578            lock (TranscriptionData)579            {580                if (TranscriptionData.SystemTranscript == null)581                {582                    TranscriptionData.SystemTranscript = GetSystemTranscriptOption(TranscriptionData.SystemTranscript);583                    if (TranscriptionData.SystemTranscript != null)584                    {585                        LogTranscriptHeader(null, TranscriptionData.SystemTranscript);586                    }587                }588            }589        }590 591        internal void StartTranscribing(string path, System.Management.Automation.Remoting.PSSenderInfo senderInfo, bool includeInvocationHeader, bool useMinimalHeader)592        {593            TranscriptionOption transcript = new TranscriptionOption();594            transcript.Path = path;595            transcript.IncludeInvocationHeader = includeInvocationHeader;596            TranscriptionData.Transcripts.Add(transcript);597 598            LogTranscriptHeader(senderInfo, transcript, useMinimalHeader);599        }600 601        private void LogTranscriptHeader(System.Management.Automation.Remoting.PSSenderInfo senderInfo, TranscriptionOption transcript, bool useMinimalHeader = false)602        {603            // Transcribe the transcript header604            string line;605            if (useMinimalHeader)606            {607                line =608                    string.Format(609                        Globalization.CultureInfo.InvariantCulture,610                        InternalHostUserInterfaceStrings.MinimalTranscriptPrologue,611                        DateTime.Now);612            }613            else614            {615                string username = Environment.UserDomainName + "\\" + Environment.UserName;616                string runAsUser = username;617 618                if (senderInfo != null)619                {620                    username = senderInfo.UserInfo.Identity.Name;621                }622 623                // Add bits from PSVersionTable624                StringBuilder versionInfoFooter = new StringBuilder();625                Hashtable versionInfo = PSVersionInfo.GetPSVersionTable();626                foreach (string versionKey in versionInfo.Keys)627                {628                    object value = versionInfo[versionKey];629 630                    if (value != null)631                    {632                        var arrayValue = value as object[];633                        string valueString = arrayValue != null ? string.Join(", ", arrayValue) : value.ToString();634                        versionInfoFooter.AppendLine(versionKey + ": " + valueString);635                    }636                }637 638                string configurationName = string.Empty;639                if (senderInfo != null && !string.IsNullOrEmpty(senderInfo.ConfigurationName))640                {641                    configurationName = senderInfo.ConfigurationName;642                }643 644                line =645                    string.Format(646                        Globalization.CultureInfo.InvariantCulture,647                        InternalHostUserInterfaceStrings.TranscriptPrologue,648                        DateTime.Now,649                        username,650                        runAsUser,651                        configurationName,652                        Environment.MachineName,653                        Environment.OSVersion.VersionString,654                        string.Join(" ", Environment.GetCommandLineArgs()),655                        Environment.ProcessId,656                        versionInfoFooter.ToString().TrimEnd());657            }658 659            lock (transcript.OutputToLog)660            {661                transcript.OutputToLog.Add(line);662            }663 664            TranscribeCommandComplete(null);665        }666 667        internal string StopTranscribing()668        {669            if (TranscriptionData.Transcripts.Count == 0)670            {671                throw new PSInvalidOperationException(InternalHostUserInterfaceStrings.HostNotTranscribing);672            }673 674            TranscriptionOption stoppedTranscript = TranscriptionData.Transcripts[TranscriptionData.Transcripts.Count - 1];675            LogTranscriptFooter(stoppedTranscript);676            stoppedTranscript.Dispose();677            TranscriptionData.Transcripts.Remove(stoppedTranscript);678 679            return stoppedTranscript.Path;680        }681 682        private void LogTranscriptFooter(TranscriptionOption stoppedTranscript)683        {684            // Transcribe the transcript epilogue685            try686            {687                string message = string.Format(688                    Globalization.CultureInfo.InvariantCulture,689                    InternalHostUserInterfaceStrings.TranscriptEpilogue, DateTime.Now);690 691                lock (stoppedTranscript.OutputToLog)692                {693                    stoppedTranscript.OutputToLog.Add(message);694                }695 696                TranscribeCommandComplete(null);697            }698            catch (Exception)699            {700                // Ignoring errors when stopping transcription (i.e.: file in use, access denied)701                // since this is probably handling exactly that error.702            }703        }704 705        internal void StopAllTranscribing()706        {707            TranscribeCommandComplete(null);708 709            while (TranscriptionData.Transcripts.Count > 0)710            {711                StopTranscribing();712            }713 714            lock (TranscriptionData)715            {716                if (TranscriptionData.SystemTranscript != null)717                {718                    LogTranscriptFooter(TranscriptionData.SystemTranscript);719                    TranscriptionData.SystemTranscript.Dispose();720                    TranscriptionData.SystemTranscript = null;721 722                    lock (s_systemTranscriptLock)723                    {724                        systemTranscript = null;725                    }726                }727            }728        }729 730        /// <summary>731        /// Transcribes the supplied result text to the transcription buffer.732        /// </summary>733        /// <param name="sourceRunspace">The runspace that was used to generate this result, if it is not the current runspace.</param>734        /// <param name="resultText">The text to be transcribed.</param>735        internal void TranscribeResult(Runspace sourceRunspace, string resultText)736        {737            if (IsTranscribing)738            {739                // If the runspace that this result applies to is not the current runspace, update Runspace.DefaultRunspace740                // so that the transcript paths / etc. will be available to the TranscriptionData accessor.741                Runspace originalDefaultRunspace = null;742                if (sourceRunspace != null)743                {744                    originalDefaultRunspace = Runspace.DefaultRunspace;745                    Runspace.DefaultRunspace = sourceRunspace;746                }747 748                try749                {750                    // If we're ignoring a command, ignore its output.751                    if (TranscriptionData.CommandBeingIgnored != null)752                    {753                        // If we're ignoring a prompt, capture the value754                        if (string.Equals("prompt", TranscriptionData.CommandBeingIgnored, StringComparison.OrdinalIgnoreCase))755                        {756                            TranscriptionData.PromptText = resultText;757                        }758 759                        return;760                    }761 762                    resultText = resultText.TrimEnd();763 764                    var text = new ValueStringDecorated(resultText);765                    if (text.IsDecorated)766                    {767                        resultText = text.ToString(OutputRendering.PlainText);768                    }769 770                    foreach (TranscriptionOption transcript in TranscriptionData.Transcripts.Prepend<TranscriptionOption>(TranscriptionData.SystemTranscript))771                    {772                        if (transcript != null)773                        {774                            lock (transcript.OutputToLog)775                            {776                                transcript.OutputToLog.Add(resultText);777                            }778                        }779                    }780                }781                finally782                {783                    if (originalDefaultRunspace != null)784                    {785                        Runspace.DefaultRunspace = originalDefaultRunspace;786                    }787                }788            }789        }790 791        /// <summary>792        /// Transcribes the supplied result text to the transcription buffer.793        /// </summary>794        /// <param name="resultText">The text to be transcribed.</param>795        internal void TranscribeResult(string resultText)796        {797            TranscribeResult(null, resultText);798        }799 800        /// <summary>801        /// Transcribes / records the completion of a command.802        /// </summary>803        /// <param name="invocation"></param>804        internal void TranscribeCommandComplete(InvocationInfo invocation)805        {806            FlushPendingOutput();807 808            if (invocation != null)809            {810                // If we're ignoring a command that was internal, we still want the811                // results of Out-Default. However, if it was a host helper command,812                // ignore all output (including Out-Default)813                string commandNameToCheck = TranscriptionData.CommandBeingIgnored;814                if (TranscriptionData.IsHelperCommand)815                {816                    commandNameToCheck = "Out-Default";817                }818 819                // If we're completing a command that we were ignoring, start transcribing results / etc. again.820                if ((TranscriptionData.CommandBeingIgnored != null) &&821                    (invocation != null) && (invocation.MyCommand != null) &&822                    string.Equals(commandNameToCheck, invocation.MyCommand.Name, StringComparison.OrdinalIgnoreCase))823                {824                    TranscriptionData.CommandBeingIgnored = null;825                    TranscriptionData.IsHelperCommand = false;826                }827            }828        }829 830        internal void TranscribePipelineComplete()831        {832            FlushPendingOutput();833 834            TranscriptionData.CommandBeingIgnored = null;835            TranscriptionData.IsHelperCommand = false;836        }837 838        private void FlushPendingOutput()839        {840            foreach (TranscriptionOption transcript in TranscriptionData.Transcripts.Prepend<TranscriptionOption>(TranscriptionData.SystemTranscript))841            {842                if (transcript != null)843                {844                    lock (transcript.OutputToLog)845                    {846                        if (transcript.OutputToLog.Count == 0)847                        {848                            continue;849                        }850 851                        lock (transcript.OutputBeingLogged)852                        {853                            bool alreadyLogging = transcript.OutputBeingLogged.Count > 0;854 855                            transcript.OutputBeingLogged.AddRange(transcript.OutputToLog);856                            transcript.OutputToLog.Clear();857 858                            // If there is already a thread trying to log output, add this output to its buffer859                            // and don't start a new thread.860                            if (alreadyLogging)861                            {862                                continue;863                            }864                        }865                    }866 867                    // Create the file in the main thread and flush the contents in the background thread.868                    // Transcription should begin only if file generation is successful.869                    // If there is an error in file generation, throw the exception.870                    string baseDirectory = Path.GetDirectoryName(transcript.Path);871                    if (Directory.Exists(transcript.Path) || (string.Equals(baseDirectory, transcript.Path.TrimEnd(Path.DirectorySeparatorChar), StringComparison.Ordinal)))872                    {873                        string errorMessage = string.Format(874                            System.Globalization.CultureInfo.CurrentCulture,875                            InternalHostUserInterfaceStrings.InvalidTranscriptFilePath,876                            transcript.Path);877                        throw new ArgumentException(errorMessage);878                    }879 880                    if (!Directory.Exists(baseDirectory))881                    {882                        Directory.CreateDirectory(baseDirectory);883                    }884 885                    if (!File.Exists(transcript.Path))886                    {887                        File.Create(transcript.Path).Dispose();888                    }889 890                    // Do the actual writing in the background so that it doesn't hold up the UI thread.891                    Task writer = Task.Run(() =>892                    {893                        // System transcripts can have high contention. Do exponential back-off on writing894                        // if needed.895                        int delay = Random.Shared.Next(10) + 1;896                        bool written = false;897 898                        while (!written)899                        {900                            try901                            {902                                transcript.FlushContentToDisk();903                                written = true;904                            }905                            catch (IOException)906                            {907                                System.Threading.Thread.Sleep(delay);908                            }909                            catch (UnauthorizedAccessException)910                            {911                                System.Threading.Thread.Sleep(delay);912                            }913 914                            // If we are trying to log, but weren't able too, back of the sleep.915                            // If we're already sleeping for 1 second between tries, then just continue916                            // at this pace until the write is successful.917                            if (delay < 1000)918                            {919                                delay *= 2;920                            }921                        }922                    });923                }924            }925        }926 927        #endregion Line-oriented interaction928 929        #region Dialog-oriented Interaction930 931        /// <summary>932        /// Constructs a 'dialog' where the user is presented with a number of fields for which to supply values.933        /// </summary>934        /// <param name="caption">935        /// Caption to precede or title the prompt.  E.g. "Parameters for get-foo (instance 1 of 2)"936        /// </param>937        /// <param name="message">938        /// A text description of the set of fields to be prompt.939        /// </param>940        /// <param name="descriptions">941        /// Array of FieldDescriptions that contain information about each field to be prompted for.942        /// </param>943        /// <returns>944        /// A Dictionary object with results of prompting.  The keys are the field names from the FieldDescriptions, the values945        /// are objects representing the values of the corresponding fields as collected from the user. To the extent possible,946        /// the host should return values of the type(s) identified in the FieldDescription.  When that is not possible (for947        /// example, the type is not available to the host), the host should return the value as a string.948        /// </returns>949        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>950        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLineAsSecureString"/>951        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>952        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>953        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>954        public abstract Dictionary<string, PSObject> Prompt(string caption, string message, Collection<FieldDescription> descriptions);955 956        /// <summary>957        /// Prompt for credentials.958        /// <!--In future, when we have Credential object from the security team,959        /// this function will be modified to prompt using secure-path960        /// if so configured.-->961        /// </summary>962        /// <summary>963        /// Prompt for credential.964        /// </summary>965        /// <param name="caption">966        /// Caption for the message.967        /// </param>968        /// <param name="message">969        /// Text description for the credential to be prompt.970        /// </param>971        /// <param name="userName">972        /// Name of the user whose credential is to be prompted for. If set to null or empty973        /// string, the function will prompt for user name first.974        /// </param>975        /// <param name="targetName">976        /// Name of the target for which the credential is being collected.977        /// </param>978        /// <returns>979        /// User input credential.980        /// </returns>981        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>982        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLineAsSecureString"/>983        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>984        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>985        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>986        public abstract PSCredential PromptForCredential(string caption, string message,987            string userName, string targetName988        );989 990        /// <summary>991        /// Prompt for credential.992        /// </summary>993        /// <param name="caption">994        /// Caption for the message.995        /// </param>996        /// <param name="message">997        /// Text description for the credential to be prompt.998        /// </param>999        /// <param name="userName">1000        /// Name of the user whose credential is to be prompted for. If set to null or empty1001        /// string, the function will prompt for user name first.1002        /// </param>1003        /// <param name="targetName">1004        /// Name of the target for which the credential is being collected.1005        /// </param>1006        /// <param name="allowedCredentialTypes">1007        /// Types of credential can be supplied by the user.1008        /// </param>1009        /// <param name="options">1010        /// Options that control the credential gathering UI behavior1011        /// </param>1012        /// <returns>1013        /// User input credential.1014        /// </returns>1015        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>1016        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLineAsSecureString"/>1017        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>1018        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForChoice"/>1019        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>1020        public abstract PSCredential PromptForCredential(string caption, string message,1021            string userName, string targetName, PSCredentialTypes allowedCredentialTypes,1022            PSCredentialUIOptions options1023        );1024 1025        /// <summary>1026        /// Presents a dialog allowing the user to choose an option from a set of options.1027        /// </summary>1028        /// <param name="caption">1029        /// Caption to precede or title the prompt.  E.g. "Parameters for get-foo (instance 1 of 2)"1030        /// </param>1031        /// <param name="message">1032        /// A message that describes what the choice is for.1033        /// </param>1034        /// <param name="choices">1035        /// An Collection of ChoiceDescription objects that describe each choice.1036        /// </param>1037        /// <param name="defaultChoice">1038        /// The index of the label in the choices collection element to be presented to the user as the default choice.  -11039        /// means "no default". Must be a valid index.1040        /// </param>1041        /// <returns>1042        /// The index of the choices element that corresponds to the option selected.1043        /// </returns>1044        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLine"/>1045        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.ReadLineAsSecureString"/>1046        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.Prompt"/>1047        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string)"/>1048        /// <seealso cref="System.Management.Automation.Host.PSHostUserInterface.PromptForCredential(string, string, string, string, System.Management.Automation.PSCredentialTypes, System.Management.Automation.PSCredentialUIOptions)"/>1049        public abstract int PromptForChoice(string caption, string message, Collection<ChoiceDescription> choices, int defaultChoice);1050 1051        #endregion Dialog-oriented interaction1052 1053        /// <summary>1054        /// Creates a new instance of the PSHostUserInterface class.1055        /// </summary>1056        protected PSHostUserInterface()1057        {1058            CheckSystemTranscript();1059        }1060 1061        /// <summary>1062        /// Helper to transcribe an error through formatting and output.1063        /// </summary>1064        /// <param name="context">The Execution Context.</param>1065        /// <param name="invocation">The invocation info associated with the record.</param>1066        /// <param name="errorWrap">The error record.</param>1067        internal void TranscribeError(ExecutionContext context, InvocationInfo invocation, PSObject errorWrap)1068        {1069            context.InternalHost.UI.TranscribeCommandComplete(invocation);1070            InitialSessionState minimalState = InitialSessionState.CreateDefault2();1071            Collection<PSObject> results = PowerShell.Create(minimalState).AddCommand("Out-String").Invoke(1072                new List<PSObject>() { errorWrap });1073            TranscribeResult(results[0].ToString());1074        }1075 1076        /// <summary>1077        /// Get Module Logging information from the registry.1078        /// </summary>1079        internal static TranscriptionOption GetSystemTranscriptOption(TranscriptionOption currentTranscript)1080        {1081            var transcription = InternalTestHooks.BypassGroupPolicyCaching1082                ? Utils.GetPolicySetting<Transcription>(Utils.SystemWideThenCurrentUserConfig)1083                : s_transcriptionSettingCache.Value;1084 1085            if (transcription != null)1086            {1087                // If we have an existing system transcript for this process, use that.1088                // Otherwise, populate the static variable with the result of the group policy setting.1089                //1090                // This way, multiple runspaces opened by the same process will share the same transcript.1091                lock (s_systemTranscriptLock)1092                {1093                    systemTranscript ??= PSHostUserInterface.GetTranscriptOptionFromSettings(transcription, currentTranscript);1094                }1095            }1096 1097            return systemTranscript;1098        }1099 1100        internal static TranscriptionOption systemTranscript = null;1101        private static readonly object s_systemTranscriptLock = new object();1102 1103        private static readonly Lazy<Transcription> s_transcriptionSettingCache = new Lazy<Transcription>(1104            static () => Utils.GetPolicySetting<Transcription>(Utils.SystemWideThenCurrentUserConfig),1105            isThreadSafe: true);1106 1107        private static TranscriptionOption GetTranscriptOptionFromSettings(Transcription transcriptConfig, TranscriptionOption currentTranscript)1108        {1109            TranscriptionOption transcript = null;1110 1111            if (transcriptConfig.EnableTranscripting == true)1112            {1113                if (currentTranscript != null)1114                {1115                    return currentTranscript;1116                }1117 1118                transcript = new TranscriptionOption();1119 1120                // Pull out the transcript path1121                if (transcriptConfig.OutputDirectory != null)1122                {1123                    transcript.Path = GetTranscriptPath(transcriptConfig.OutputDirectory, true);1124                }1125                else1126                {1127                    transcript.Path = GetTranscriptPath();1128                }1129 1130                // Pull out the "enable invocation header"1131                transcript.IncludeInvocationHeader = transcriptConfig.EnableInvocationHeader == true;1132            }1133 1134            return transcript;1135        }1136 1137        internal static string GetTranscriptPath()1138        {1139            string baseDirectory = Platform.GetFolderPath(Environment.SpecialFolder.MyDocuments);1140            return GetTranscriptPath(baseDirectory, false);1141        }1142 1143        internal static string GetTranscriptPath(string baseDirectory, bool includeDate)1144        {1145            if (string.IsNullOrEmpty(baseDirectory))1146            {1147                baseDirectory = Platform.GetFolderPath(Environment.SpecialFolder.MyDocuments);1148            }1149            else1150            {1151                if (!Path.IsPathRooted(baseDirectory))1152                {1153                    baseDirectory = Path.Combine(1154                        Platform.GetFolderPath(Environment.SpecialFolder.MyDocuments),1155                        baseDirectory);1156                }1157            }1158 1159            if (string.IsNullOrEmpty(baseDirectory))1160            {1161                return string.Empty;1162            }1163 1164            if (includeDate)1165            {1166                baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture));1167            }1168 1169            // transcriptPath includes some randomness so that files can be collected on a central share,1170            // and an attacker can't guess the filename and read the contents if the ACL was poor.1171            // After testing, a computer can do about 10,000 remote path tests per second. So 61172            // bytes of randomness (2^48 = 2.8e14) would take an attacker about 891 years to guess1173            // a filename (assuming they knew the time the transcript was started).1174            // (5 bytes = 3 years, 4 bytes = about a month)1175            Span<byte> randomBytes = stackalloc byte[6];1176            System.Security.Cryptography.RandomNumberGenerator.Fill(randomBytes);1177            string filename = string.Format(1178                        Globalization.CultureInfo.InvariantCulture,1179                        "PowerShell_transcript.{0}.{1}.{2:yyyyMMddHHmmss}.txt",1180                        Environment.MachineName,1181                        Convert.ToBase64String(randomBytes).Replace('/', '_'),1182                        DateTime.Now);1183 1184            string transcriptPath = System.IO.Path.Combine(baseDirectory, filename);1185            return transcriptPath;1186        }1187    }1188 1189    // Holds runspace-wide transcription data / settings for PowerShell transcription1190    internal class TranscriptionData1191    {1192        internal TranscriptionData()1193        {1194            Transcripts = new List<TranscriptionOption>();1195            SystemTranscript = null;1196            CommandBeingIgnored = null;1197            IsHelperCommand = false;1198            PromptText = "PS>";1199        }1200 

Showing the first 1,200 of 1481 lines. Download the file for the rest.