MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#pragma warning disable 1634, 16915#pragma warning disable 565066 7using System.Collections;8using System.Collections.ObjectModel;9using System.Globalization;10using System.Management.Automation.Runspaces;11using System.Text;12using System.Resources;13using System.Runtime.Serialization;14using System.Reflection;15using System.Management.Automation.Language;16using System.Security.Permissions;17 18namespace System.Management.Automation19{20 /// <summary>21 /// Errors reported by PowerShell will be in one of these categories.22 /// </summary>23 /// <remarks>24 /// Do not specify ErrorCategory.NotSpecified when creating an25 /// <see cref="System.Management.Automation.ErrorRecord"/>.26 /// Choose the best match from among the other values.27 /// </remarks>28 public enum ErrorCategory29 {30 /// <summary>31 /// <para>32 /// No error category is specified, or the error category is invalid.33 /// </para>34 /// <para>35 /// Do not specify ErrorCategory.NotSpecified when creating an36 /// <see cref="System.Management.Automation.ErrorRecord"/>.37 /// Choose the best match from among the other values.38 /// </para>39 /// </summary>40 NotSpecified = 0,41 42 /// <summary>43 /// </summary>44 OpenError = 1,45 46 /// <summary>47 /// </summary>48 CloseError = 2,49 50 /// <summary>51 /// </summary>52 DeviceError = 3,53 54 /// <summary>55 /// </summary>56 DeadlockDetected = 4,57 58 /// <summary>59 /// </summary>60 InvalidArgument = 5,61 62 /// <summary>63 /// </summary>64 InvalidData = 6,65 66 /// <summary>67 /// </summary>68 InvalidOperation = 7,69 70 /// <summary>71 /// </summary>72 InvalidResult = 8,73 74 /// <summary>75 /// </summary>76 InvalidType = 9,77 78 /// <summary>79 /// </summary>80 MetadataError = 10,81 82 /// <summary>83 /// </summary>84 NotImplemented = 11,85 86 /// <summary>87 /// </summary>88 NotInstalled = 12,89 90 /// <summary>91 /// Object can not be found (file, directory, computer, system resource, etc.)92 /// </summary>93 ObjectNotFound = 13,94 95 /// <summary>96 /// </summary>97 OperationStopped = 14,98 99 /// <summary>100 /// </summary>101 OperationTimeout = 15,102 103 /// <summary>104 /// </summary>105 SyntaxError = 16,106 107 /// <summary>108 /// </summary>109 ParserError = 17,110 111 /// <summary>112 /// Operation not permitted.113 /// </summary>114 PermissionDenied = 18,115 116 /// <summary>117 /// </summary>118 ResourceBusy = 19,119 120 /// <summary>121 /// </summary>122 ResourceExists = 20,123 124 /// <summary>125 /// </summary>126 ResourceUnavailable = 21,127 128 /// <summary>129 /// </summary>130 ReadError = 22,131 132 /// <summary>133 /// </summary>134 WriteError = 23,135 136 /// <summary>137 /// <para>138 /// A native command reported an error to its STDERR pipe.139 /// </para>140 /// <para>141 /// The Engine uses this ErrorCategory when it executes a native142 /// console applications and captures the errors reported by the143 /// native application. Avoid using ErrorCategory.FromStdErr144 /// in other circumstances.145 /// </para>146 /// </summary>147 FromStdErr = 24,148 149 /// <summary>150 /// Used for security exceptions.151 /// </summary>152 SecurityError = 25,153 154 /// <summary>155 /// The contract of a protocol is not being followed. Should not happen156 /// with well-behaved components.157 /// </summary>158 ProtocolError = 26,159 160 /// <summary>161 /// The operation depends on a network connection that cannot be162 /// established or maintained.163 /// </summary>164 ConnectionError = 27,165 166 /// <summary>167 /// Could not authenticate the user to the service. Could mean that the168 /// credentials are invalid or the authentication system is not169 /// functioning properly.170 /// </summary>171 AuthenticationError = 28,172 173 /// <summary>174 /// Internal limits prevent the operation from being executed.175 /// </summary>176 LimitsExceeded = 29,177 178 /// <summary>179 /// Controls on the use of traffic or resources prevent the operation180 /// from being executed.181 /// </summary>182 QuotaExceeded = 30,183 184 /// <summary>185 /// The operation attempted to use functionality that is currently186 /// disabled.187 /// </summary>188 NotEnabled = 31,189 }190 191 /// <summary>192 /// Contains auxiliary information about an193 /// <see cref="System.Management.Automation.ErrorRecord"/>194 /// </summary>195 public class ErrorCategoryInfo196 {197 #region ctor198 internal ErrorCategoryInfo(ErrorRecord errorRecord)199 {200 ArgumentNullException.ThrowIfNull(errorRecord);201 202 _errorRecord = errorRecord;203 }204 #endregion ctor205 206 #region Properties207 /// <summary></summary>208 /// <see cref="System.Management.Automation.ErrorCategory"/>209 /// for this error210 public ErrorCategory Category211 {212 get { return _errorRecord._category; }213 }214 215 /// <summary>216 /// Text description of the operation which217 /// encountered the error.218 /// </summary>219 /// <value>text description of the operation</value>220 /// <remarks>221 /// By default, this is the cmdlet name.222 /// The default can be overridden by calling Set with a223 /// non-empty value, for example "Delete".224 /// </remarks>225 public string Activity226 {227 get228 {229 if (!string.IsNullOrEmpty(_errorRecord._activityOverride))230 {231 return _errorRecord._activityOverride;232 }233 234 if (_errorRecord.InvocationInfo != null235 && (_errorRecord.InvocationInfo.MyCommand is CmdletInfo || _errorRecord.InvocationInfo.MyCommand is IScriptCommandInfo)236 && !string.IsNullOrEmpty(_errorRecord.InvocationInfo.MyCommand.Name)237 )238 {239 return _errorRecord.InvocationInfo.MyCommand.Name;240 }241 242 return string.Empty;243 }244 245 set246 {247 _errorRecord._activityOverride = value;248 }249 }250 251 /// <summary>252 /// Text description of the error.253 /// </summary>254 /// <value>text description of the error</value>255 /// <remarks>256 /// By default, this is the exception type.257 /// The default can be overridden by calling Set with a258 /// non-empty value, for example "Permission Denied".259 /// </remarks>260 public string Reason261 {262 get263 {264 _reasonIsExceptionType = false;265 if (!string.IsNullOrEmpty(_errorRecord._reasonOverride))266 {267 return _errorRecord._reasonOverride;268 }269 270 if (_errorRecord.Exception != null)271 {272 _reasonIsExceptionType = true;273 return _errorRecord.Exception.GetType().Name;274 }275 276 return string.Empty;277 }278 279 set280 {281 _errorRecord._reasonOverride = value;282 }283 }284 285 private bool _reasonIsExceptionType;286 287 /// <summary>288 /// Text description of the target object.289 /// </summary>290 /// <value>text description of the target object</value>291 /// <remarks>292 /// By default, this is TargetObject.ToString(), or the empty string293 /// if the target object is null.294 /// The default can be overridden by calling Set with a295 /// non-empty value, for example "John Doe".296 /// </remarks>297 public string TargetName298 {299 get300 {301 if (!string.IsNullOrEmpty(_errorRecord._targetNameOverride))302 {303 return _errorRecord._targetNameOverride;304 }305 306 if (_errorRecord.TargetObject != null)307 {308 string targetInString;309 try310 {311 targetInString = _errorRecord.TargetObject.ToString();312 }313 catch (Exception)314 {315 targetInString = null;316 }317 318 return ErrorRecord.NotNull(targetInString);319 }320 321 return string.Empty;322 }323 324 set325 {326 _errorRecord._targetNameOverride = value;327 }328 }329 330 /// <summary>331 /// Text description of the type of the target object.332 /// </summary>333 /// <value>text description of the type of the target object</value>334 /// <remarks>335 /// By default, this is TargetObject.GetType().ToString(),336 /// or the empty string if the target object is null.337 /// The default can be overridden by calling Set with a338 /// non-empty value, for example "Active Directory User".339 /// </remarks>340 public string TargetType341 {342 get343 {344 if (!string.IsNullOrEmpty(_errorRecord._targetTypeOverride))345 {346 return _errorRecord._targetTypeOverride;347 }348 349 if (_errorRecord.TargetObject != null)350 {351 return _errorRecord.TargetObject.GetType().Name;352 }353 354 return string.Empty;355 }356 357 set358 {359 _errorRecord._targetTypeOverride = value;360 }361 }362 363 #endregion Properties364 365 #region Methods366 /// <summary>367 /// Concise text description based on368 /// <see cref="System.Management.Automation.ErrorCategoryInfo.Category"/>369 /// </summary>370 /// <returns>Concise text description.</returns>371 /// <remarks>372 /// GetMessage returns a concise string which categorizes the error,373 /// based on374 /// <see cref="System.Management.Automation.ErrorCategoryInfo.Category"/>375 /// and including the other fields of376 /// <see cref="System.Management.Automation.ErrorCategoryInfo"/>377 /// as appropriate. This string is much shorter378 /// than379 /// <see cref="System.Management.Automation.ErrorDetails.Message"/> or380 /// <see cref="System.Exception.Message"/>, since it only381 /// categorizes the error and does not contain a full description382 /// or recommended actions. The default host will display this383 /// string instead of the full message if shell variable384 /// $ErrorView is set to "CategoryView".385 /// </remarks>386 public string GetMessage()387 {388 /* Remoting not in E12389 if (!string.IsNullOrEmpty (_errorRecord._serializedErrorCategoryMessageOverride))390 return _errorRecord._serializedErrorCategoryMessageOverride;391 */392 393 return GetMessage(CultureInfo.CurrentUICulture);394 }395 396 /// <summary>397 /// Concise text description based on398 /// <see cref="System.Management.Automation.ErrorCategoryInfo.Category"/>399 /// </summary>400 /// <param name="uiCultureInfo">Culture in which to display message.</param>401 /// <returns>Concise text description.</returns>402 /// <remarks>403 /// GetMessage returns a concise string which categorizes the error,404 /// based on405 /// <see cref="System.Management.Automation.ErrorCategoryInfo.Category"/>406 /// and including the other fields of407 /// <see cref="System.Management.Automation.ErrorCategoryInfo"/>408 /// as appropriate. This string is much shorter409 /// than410 /// <see cref="System.Management.Automation.ErrorDetails.Message"/> or411 /// <see cref="System.Exception.Message"/>, since it only412 /// categorizes the error and does not contain a full description413 /// or recommended actions. The default host will display this414 /// string instead of the full message if shell variable415 /// $ErrorView is set to "CategoryView".416 /// </remarks>417 public string GetMessage(CultureInfo uiCultureInfo)418 {419 // get template text420 string errorCategoryString = Category.ToString();421 if (string.IsNullOrEmpty(errorCategoryString))422 {423 // this probably indicates an invalid ErrorCategory value424 errorCategoryString = nameof(ErrorCategory.NotSpecified);425 }426 427 string templateText = ErrorCategoryStrings.ResourceManager.GetString(errorCategoryString, uiCultureInfo);428 429 if (string.IsNullOrEmpty(templateText))430 {431 // this probably indicates an invalid ErrorCategory value432 templateText = ErrorCategoryStrings.NotSpecified;433 }434 435 Diagnostics.Assert(!string.IsNullOrEmpty(templateText),436 "ErrorCategoryStrings.resx resource failure");437 438 string activityInUse = Ellipsize(uiCultureInfo, Activity);439 string targetNameInUse = Ellipsize(uiCultureInfo, TargetName);440 string targetTypeInUse = Ellipsize(uiCultureInfo, TargetType);441 // if the reason is a exception type name, we should output the whole name442 string reasonInUse = Reason;443 reasonInUse = _reasonIsExceptionType ? reasonInUse : Ellipsize(uiCultureInfo, reasonInUse);444 445 // assemble final string446 try447 {448 return string.Format(uiCultureInfo, templateText,449 activityInUse,450 targetNameInUse,451 targetTypeInUse,452 reasonInUse,453 errorCategoryString);454 }455 catch (FormatException)456 {457 templateText = ErrorCategoryStrings.InvalidErrorCategory;458 459 return string.Format(uiCultureInfo, templateText,460 activityInUse,461 targetNameInUse,462 targetTypeInUse,463 reasonInUse,464 errorCategoryString);465 }466 }467 468 /// <summary>469 /// Same as470 /// <see cref="System.Management.Automation.ErrorCategoryInfo.GetMessage()"/>471 /// </summary>472 /// <returns>Developer-readable identifier.</returns>473 public override string ToString()474 {475 return GetMessage(CultureInfo.CurrentUICulture);476 }477 #endregion Methods478 479 #region Private480 // back-reference for facade class481 private readonly ErrorRecord _errorRecord;482 483 /// <summary>484 /// The Activity, Reason, TargetName and TargetType strings in485 /// ErrorCategoryInfo can be of unlimited length. In order to486 /// control the maximum length of the GetMessage() string, we487 /// ellipsize these strings. The current heuristic is to take488 /// strings longer than 40 characters and ellipsize them to489 /// the first and last 19 characters plus "..." in the middle.490 /// </summary>491 /// <param name="uiCultureInfo">Culture to retrieve template if needed.</param>492 /// <param name="original">Original string.</param>493 /// <returns>Ellipsized version of string.</returns>494 /// <remarks>495 /// "Please do not make this public as ellipsize is not a word."496 /// </remarks>497 internal static string Ellipsize(CultureInfo uiCultureInfo, string original)498 {499 if (original.Length <= 40)500 {501 return original;502 }503 504 // We are splitting a string > 40 chars in half, so left and right can be505 // at most 19 characters to include the ellipsis in the middle.506 const int MaxHalfWidth = 19;507 string first = original.Substring(0, MaxHalfWidth);508 string last = original.Substring(original.Length - MaxHalfWidth, MaxHalfWidth);509 return510 string.Format(uiCultureInfo, ErrorPackage.Ellipsize, first, last);511 }512 #endregion Private513 }514 515 /// <summary>516 /// Additional details about an517 /// <see cref="System.Management.Automation.ErrorRecord"/>518 /// </summary>519 /// <remarks>520 /// ErrorDetails represents additional details about an521 /// <see cref="System.Management.Automation.ErrorRecord"/>,522 /// starting with a replacement Message. Clients can use ErrorDetails523 /// when they want to display a more specific Message than the one524 /// contained in a particular Exception, without having to create525 /// a new Exception or define a new Exception class.526 ///527 /// It is permitted to subclass <see cref="ErrorDetails"/>528 /// but there is no established scenario for doing this, nor has it been tested.529 /// </remarks>530 public class ErrorDetails : ISerializable531 {532 #region Constructor533 /// <summary>534 /// Creates an instance of ErrorDetails specifying a Message.535 /// </summary>536 /// <remarks>537 /// It is preferred for Cmdlets to use538 /// <see cref="ErrorDetails(Cmdlet,string,string,object[])"/>,539 /// for CmdletProviders to use540 /// <see cref="ErrorDetails(IResourceSupplier,string,string,object[])"/>,541 /// and for other localizable code to use542 /// <see cref="ErrorDetails(Assembly,string,string,object[])"/>543 /// where possible.544 /// </remarks>545 /// <param name="message"></param>546 public ErrorDetails(string message)547 {548 _message = message;549 }550 551 #region UseResourceId552 /// <summary>553 /// Creates an instance of ErrorDetails specifying a Message.554 /// This variant is used by cmdlets.555 /// </summary>556 /// <param name="cmdlet">Cmdlet containing the template string.</param>557 /// <param name="baseName">by default, the558 /// <see cref="System.Resources.ResourceManager"/>559 /// name</param>560 /// <param name="resourceId">561 /// by default, the resourceId in the562 /// <see cref="System.Resources.ResourceManager"/>563 /// </param>564 /// <param name="args">565 /// <see cref="string.Format(IFormatProvider,string,object[])"/>566 /// insertion parameters567 /// </param>568 /// <remarks>569 /// This variant is a shortcut to build an instance of570 /// <see cref="System.Management.Automation.ErrorDetails"/>571 /// reducing the steps which localizable code generally has to duplicate when it572 /// generates a localizable string. This variant is preferred over573 /// <see cref="System.Management.Automation.ErrorDetails(string)"/>,574 /// since the improved575 /// information about the error may help enable future scenarios.576 ///577 /// This constructor first loads the error message template string using578 /// <see cref="Cmdlet.GetResourceString"/>.579 /// The default implementation of580 /// <see cref="Cmdlet.GetResourceString"/>581 /// will load a string resource from the cmdlet assembly using582 /// <paramref name="baseName"/> and <paramref name="resourceId"/>;583 /// however, specific cmdlets can override this behavior584 /// by overriding virtual method585 /// <see cref="Cmdlet.GetResourceString"/>.586 /// This constructor then inserts the specified args using587 /// <see cref="string.Format(IFormatProvider,string,object[])"/>.588 /// </remarks>589 public ErrorDetails(590 Cmdlet cmdlet,591 string baseName,592 string resourceId,593 params object[] args)594 {595 _message = BuildMessage(cmdlet, baseName, resourceId, args);596 }597 /// <summary>598 /// Creates an instance of ErrorDetails specifying a Message.599 /// This variant is used by CmdletProviders.600 /// </summary>601 /// <param name="resourceSupplier">602 /// Resource supplier, most often an instance of603 /// <see cref="Provider.CmdletProvider"/>.604 /// </param>605 /// <param name="baseName">by default, the606 /// <see cref="System.Resources.ResourceManager"/>607 /// name</param>608 /// <param name="resourceId">609 /// by default, the resourceId in the610 /// <see cref="System.Resources.ResourceManager"/>611 /// </param>612 /// <param name="args">613 /// <see cref="string.Format(IFormatProvider,string,object[])"/>614 /// insertion parameters615 /// </param>616 /// <remarks>617 /// This variant is a shortcut to build an instance of618 /// <see cref="System.Management.Automation.ErrorDetails"/>619 /// reducing the steps which localizable code generally has to duplicate when it620 /// generates a localizable string. This variant is preferred over621 /// <see cref="System.Management.Automation.ErrorDetails(string)"/>,622 /// since the improved623 /// information about the error may help enable future scenarios.624 ///625 /// This constructor first loads a template string using626 /// <see cref="System.Management.Automation.IResourceSupplier.GetResourceString"/>.627 /// The default implementation of628 /// <see cref="Provider.CmdletProvider.GetResourceString"/>629 /// will load a string resource from the CmdletProvider assembly using630 /// <paramref name="baseName"/> and <paramref name="resourceId"/>;631 /// however, specific CmdletProviders can override this behavior632 /// by overriding virtual method633 /// <see cref="Provider.CmdletProvider.GetResourceString"/>,634 /// and it is also possible that PSSnapin custom classes635 /// which are not instances of636 /// <see cref="Provider.CmdletProvider"/>637 /// will implement638 /// <see cref="IResourceSupplier"/>.639 /// The constructor then inserts the specified args using640 /// <see cref="string.Format(IFormatProvider,string,object[])"/>.641 /// </remarks>642 public ErrorDetails(643 IResourceSupplier resourceSupplier,644 string baseName,645 string resourceId,646 params object[] args)647 {648 _message = BuildMessage(resourceSupplier, baseName, resourceId, args);649 }650 /// <summary>651 /// Creates an instance of ErrorDetails specifying a Message.652 /// This variant is used by other code without a reference to653 /// a <see cref="Cmdlet"/> or <see cref="Provider.CmdletProvider"/> instance.654 /// </summary>655 /// <param name="assembly">656 /// assembly containing the template string657 /// </param>658 /// <param name="baseName">by default, the659 /// <see cref="System.Resources.ResourceManager"/>660 /// name</param>661 /// <param name="resourceId">662 /// by default, the resourceId in the663 /// <see cref="System.Resources.ResourceManager"/>664 /// </param>665 /// <param name="args">666 /// <see cref="string.Format(IFormatProvider,string,object[])"/>667 /// insertion parameters668 /// </param>669 /// <remarks>670 /// This variant is a shortcut to build an instance of671 /// <see cref="System.Management.Automation.ErrorDetails"/>672 /// reducing the steps which localizable code generally has to duplicate when it673 /// generates a localizable string. This variant is preferred over674 /// <see cref="System.Management.Automation.ErrorDetails(string)"/>,675 /// since the improved676 /// information about the error may help enable future scenarios.677 ///678 /// This constructor first loads a template string from the assembly using679 /// <see cref="System.Resources.ResourceManager.GetString(string)"/>.680 /// The constructor then inserts the specified args using681 /// <see cref="string.Format(IFormatProvider,string,object[])"/>.682 /// </remarks>683 public ErrorDetails(684 System.Reflection.Assembly assembly,685 string baseName,686 string resourceId,687 params object[] args)688 {689 _message = BuildMessage(assembly, baseName, resourceId, args);690 }691 #endregion UseResourceId692 693 // deep-copy constructor694 internal ErrorDetails(ErrorDetails errorDetails)695 {696 _message = errorDetails._message;697 _recommendedAction = errorDetails._recommendedAction;698 }699 #endregion Constructor700 701 #region Serialization702 /// <summary>703 /// Initializes a new instance of the ErrorDetails class704 /// using data serialized via705 /// <see cref="ISerializable"/>706 /// </summary>707 /// <param name="info">Serialization information.</param>708 /// <param name="context">Streaming context.</param>709 /// <returns>Constructed object.</returns>710 protected ErrorDetails(SerializationInfo info,711 StreamingContext context)712 {713 _message = info.GetString("ErrorDetails_Message");714 _recommendedAction = info.GetString(715 "ErrorDetails_RecommendedAction");716 }717 718 /// <summary>719 /// Serializer for <see cref="ISerializable"/>720 /// </summary>721 /// <param name="info">Serialization information.</param>722 /// <param name="context">Streaming context.</param>723 public virtual void GetObjectData(SerializationInfo info, StreamingContext context)724 {725 if (info != null)726 {727 info.AddValue("ErrorDetails_Message", _message);728 info.AddValue("ErrorDetails_RecommendedAction",729 _recommendedAction);730 }731 }732 #endregion Serialization733 734 #region Public Properties735 /// <summary>736 /// Message which replaces737 /// <see cref="System.Exception.Message"/> in738 /// <see cref="System.Management.Automation.ErrorRecord.Exception"/>739 /// </summary>740 /// <remarks>741 /// When an instance of742 /// <see cref="System.Management.Automation.ErrorRecord"/>743 /// contains a non-null744 /// <see cref="System.Management.Automation.ErrorRecord.ErrorDetails"/>745 /// and746 /// <see cref="System.Management.Automation.ErrorDetails.Message"/>747 /// is non-empty, the default host will display it instead of748 /// the <see cref="System.Exception.Message"/> in749 /// <see cref="System.Management.Automation.ErrorRecord.Exception"/>.750 ///751 /// This should be a grammatically correct localized text string, as with752 /// <see cref="System.Exception.Message"/>753 /// </remarks>754 public string Message755 {756 get { return ErrorRecord.NotNull(_message); }757 }758 759 private readonly string _message = string.Empty;760 761 /// <summary>762 /// Text describing the recommended action in the event that this error763 /// occurs. This is empty unless the code which generates the error764 /// specifies it explicitly.765 /// </summary>766 /// <remarks>767 /// This should be a grammatically correct localized text string.768 /// This may be left empty.769 /// </remarks>770 public string RecommendedAction771 {772 get773 {774 return ErrorRecord.NotNull(_recommendedAction);775 }776 777 set778 {779 _recommendedAction = value;780 }781 }782 783 private string _recommendedAction = string.Empty;784 #endregion Public Properties785 786 #region Internal Properties787 internal Exception TextLookupError788 {789 get { return _textLookupError; }790 791 set { _textLookupError = value; }792 }793 794 private Exception _textLookupError /* = null */;795 #endregion Internal Properties796 797 #region ToString798 /// <summary>799 /// As <see cref="object.ToString()"/>800 /// </summary>801 /// <returns>Developer-readable identifier.</returns>802 public override string ToString()803 {804 return Message;805 }806 #endregion ToString807 808 #region Private809 private string BuildMessage(810 Cmdlet cmdlet,811 string baseName,812 string resourceId,813 params object[] args)814 {815 if (cmdlet == null)816 {817 throw PSTraceSource.NewArgumentNullException(nameof(cmdlet));818 }819 820 if (string.IsNullOrEmpty(baseName))821 {822 throw PSTraceSource.NewArgumentNullException(nameof(baseName));823 }824 825 if (string.IsNullOrEmpty(resourceId))826 {827 throw PSTraceSource.NewArgumentNullException(nameof(resourceId));828 }829 830 string template = string.Empty;831 832 try833 {834 template = cmdlet.GetResourceString(baseName, resourceId);835 }836 catch (MissingManifestResourceException e)837 {838 _textLookupError = e;839 return string.Empty; // fallback to Exception.Message840 }841 catch (ArgumentException e)842 {843 _textLookupError = e;844 return string.Empty; // fallback to Exception.Message845 }846 847 return BuildMessage(template, baseName, resourceId, args);848 }849 850 private string BuildMessage(851 IResourceSupplier resourceSupplier,852 string baseName,853 string resourceId,854 params object[] args)855 {856 if (resourceSupplier == null)857 {858 throw PSTraceSource.NewArgumentNullException(nameof(resourceSupplier));859 }860 861 if (string.IsNullOrEmpty(baseName))862 {863 throw PSTraceSource.NewArgumentNullException(nameof(baseName));864 }865 866 if (string.IsNullOrEmpty(resourceId))867 {868 throw PSTraceSource.NewArgumentNullException(nameof(resourceId));869 }870 871 string template = string.Empty;872 873 try874 {875 template = resourceSupplier.GetResourceString(baseName, resourceId);876 }877 catch (MissingManifestResourceException e)878 {879 _textLookupError = e;880 return string.Empty; // fallback to Exception.Message881 }882 catch (ArgumentException e)883 {884 _textLookupError = e;885 return string.Empty; // fallback to Exception.Message886 }887 888 return BuildMessage(template, baseName, resourceId, args);889 }890 891 private string BuildMessage(892 System.Reflection.Assembly assembly,893 string baseName,894 string resourceId,895 params object[] args)896 {897 if (assembly == null)898 {899 throw PSTraceSource.NewArgumentNullException(nameof(assembly));900 }901 902 if (string.IsNullOrEmpty(baseName))903 {904 throw PSTraceSource.NewArgumentNullException(nameof(baseName));905 }906 907 if (string.IsNullOrEmpty(resourceId))908 {909 throw PSTraceSource.NewArgumentNullException(nameof(resourceId));910 }911 912 string template = string.Empty;913 914 ResourceManager manager =915 ResourceManagerCache.GetResourceManager(916 assembly, baseName);917 try918 {919 template = manager.GetString(920 resourceId,921 CultureInfo.CurrentUICulture);922 }923 catch (MissingManifestResourceException e)924 {925 _textLookupError = e;926 return string.Empty; // fallback to Exception.Message927 }928 929 return BuildMessage(template, baseName, resourceId, args);930 }931 932 private string BuildMessage(933 string template,934 string baseName,935 string resourceId,936 params object[] args)937 {938 if (string.IsNullOrWhiteSpace(template))939 {940 _textLookupError = PSTraceSource.NewInvalidOperationException(941 ErrorPackage.ErrorDetailsEmptyTemplate,942 baseName,943 resourceId);944 return string.Empty; // fallback to Exception.Message945 }946 947 try948 {949 return string.Format(950 CultureInfo.CurrentCulture,951 template,952 args);953 }954 catch (FormatException e)955 {956 _textLookupError = e;957 return string.Empty; // fallback to Exception.Message958 }959 }960 #endregion Private961 962 }963 964 /// <summary>965 /// Represents an error.966 /// </summary>967 /// <remarks>968 /// An ErrorRecord describes an error. It extends the usual information969 /// in <see cref="System.Exception"/> with the additional information in970 /// <see cref="System.Management.Automation.ErrorRecord.ErrorDetails"/>,971 /// <see cref="System.Management.Automation.ErrorRecord.TargetObject"/>,972 /// <see cref="System.Management.Automation.ErrorRecord.CategoryInfo"/>,973 /// <see cref="System.Management.Automation.ErrorRecord.FullyQualifiedErrorId"/>,974 /// <see cref="System.Management.Automation.ErrorRecord.ErrorDetails"/>, and975 /// <see cref="System.Management.Automation.ErrorRecord.InvocationInfo"/>.976 /// Non-terminating errors are stored as977 /// <see cref="System.Management.Automation.ErrorRecord"/>978 /// instances in shell variable979 /// $error.980 ///981 /// Some terminating errors implement982 /// <see cref="System.Management.Automation.IContainsErrorRecord"/>983 /// which gives them an ErrorRecord property containing this additional984 /// information. In this case, ErrorRecord.Exception will be an instance of985 /// <see cref="System.Management.Automation.ParentContainsErrorRecordException"/>.986 /// rather than the actual exception, to avoid the mutual references.987 /// </remarks>988 public class ErrorRecord : ISerializable989 {990 #region Constructor991 992 private ErrorRecord()993 {994 }995 996 /// <summary>997 /// Creates an instance of ErrorRecord.998 /// </summary>999 /// <param name="exception">1000 /// This is an exception which describes the error.1001 /// This argument may not be null, but it is not required1002 /// that the exception have ever been thrown.1003 /// </param>1004 /// <param name="errorId">1005 /// This string will be used to construct the FullyQualifiedErrorId,1006 /// which is a global identifier of the error condition. Pass a1007 /// non-empty string which is specific to this error condition in1008 /// this context.1009 /// </param>1010 /// <param name="errorCategory">1011 /// This is the ErrorCategory which best describes the error.1012 /// </param>1013 /// <param name="targetObject">1014 /// This is the object against which the cmdlet or provider1015 /// was operating when the error occurred. This is optional.1016 /// </param>1017 public ErrorRecord(1018 Exception exception,1019 string errorId,1020 ErrorCategory errorCategory,1021 object targetObject)1022 {1023 if (exception == null)1024 {1025 throw PSTraceSource.NewArgumentNullException(nameof(exception));1026 }1027 1028 errorId ??= string.Empty;1029 1030 // targetObject may be null1031 _error = exception;1032 _errorId = errorId;1033 _category = errorCategory;1034 _target = targetObject;1035 }1036 1037 #region Serialization1038 1039 // We serialize the exception as its original type, ensuring1040 // that the ErrorRecord information arrives in full, but taking1041 // the risk that it cannot be serialized/deserialized at all if1042 // (1) the exception type does not exist on the target machine, or1043 // (2) the exception serializer/deserializer fails or is not1044 // implemented/supported.1045 //1046 // We do not attempt to serialize TargetObject.1047 //1048 // We do not attempt to serialize InvocationInfo. There is1049 // potentially some useful information there, but serializing1050 // InvocationInfo, Token, InternalCommand and its subclasses, and1051 // CommandInfo and its subclasses is too expensive.1052 1053 /// <summary>1054 /// Initializes a new instance of the ErrorRecord class1055 /// using data serialized via1056 /// <see cref="ISerializable"/>1057 /// </summary>1058 /// <param name="info">Serialization information.</param>1059 /// <param name="context">Streaming context.</param>1060 /// <returns>Constructed object.</returns>1061 /// <remarks>1062 /// ErrorRecord instances which are serialized using1063 /// <see cref="ISerializable"/>1064 /// will only be partially reconstructed.1065 /// </remarks>1066 protected ErrorRecord(SerializationInfo info,1067 StreamingContext context)1068 {1069 PSObject psObject = PSObject.ConstructPSObjectFromSerializationInfo(info, context);1070 ConstructFromPSObjectForRemoting(psObject);1071 }1072 1073 /// <summary>1074 /// Deserializer for <see cref="ISerializable"/>1075 /// </summary>1076 /// <param name="info">Serialization information.</param>1077 /// <param name="context">Streaming context.</param>1078 public virtual void GetObjectData(SerializationInfo info, StreamingContext context)1079 {1080 if (info != null)1081 {1082 PSObject psObject = RemotingEncoder.CreateEmptyPSObject();1083 1084 // for binary serialization always serialize the extended info1085 ToPSObjectForRemoting(psObject, true);1086 1087 psObject.GetObjectData(info, context);1088 }1089 }1090 #endregion Serialization1091 1092 #region Remoting1093 1094 /// <summary>1095 /// IsSerialized is set to true if this error record is serialized.1096 /// </summary>1097 private bool _isSerialized = false;1098 1099 /// <summary>1100 /// Is this instance serialized.1101 /// </summary>1102 internal bool IsSerialized { get => _isSerialized; }1103 1104 /// <summary>1105 /// Value for FullyQualifiedErrorId in case of serialized error record.1106 /// </summary>1107 private string _serializedFullyQualifiedErrorId = null;1108 1109 /// <summary>1110 /// Message overridee for CategoryInfo.GetMessage method.1111 /// </summary>1112 internal string _serializedErrorCategoryMessageOverride = null;1113 1114 /// <summary>1115 /// This constructor is used by remoting code to create ErrorRecord.1116 /// Various information is obtained from serialized ErrorRecord.1117 /// </summary>1118 /// <param name="exception"></param>1119 /// <param name="targetObject"></param>1120 /// <param name="fullyQualifiedErrorId"></param>1121 /// <param name="errorCategory"></param>1122 /// <param name="errorCategory_Activity"></param>1123 /// <param name="errorCategory_Reason"></param>1124 /// <param name="errorCategory_TargetName"></param>1125 /// <param name="errorCategory_TargetType"></param>1126 /// <param name="errorCategory_Message"></param>1127 /// <param name="errorDetails_Message"></param>1128 /// <param name="errorDetails_RecommendedAction"></param>1129 internal ErrorRecord(1130 Exception exception,1131 object targetObject,1132 string fullyQualifiedErrorId,1133 ErrorCategory errorCategory,1134 string errorCategory_Activity,1135 string errorCategory_Reason,1136 string errorCategory_TargetName,1137 string errorCategory_TargetType,1138 string errorCategory_Message,1139 string errorDetails_Message,1140 string errorDetails_RecommendedAction)1141 {1142 PopulateProperties(1143 exception, targetObject, fullyQualifiedErrorId, errorCategory, errorCategory_Activity,1144 errorCategory_Reason, errorCategory_TargetName, errorCategory_TargetType,1145 errorCategory_Message, errorDetails_Message, errorDetails_RecommendedAction, null);1146 }1147 1148 private void PopulateProperties(1149 Exception exception,1150 object targetObject,1151 string fullyQualifiedErrorId,1152 ErrorCategory errorCategory,1153 string errorCategory_Activity,1154 string errorCategory_Reason,1155 string errorCategory_TargetName,1156 string errorCategory_TargetType,1157 string errorCategory_Message,1158 string errorDetails_Message,1159 string errorDetails_RecommendedAction,1160 string errorDetails_ScriptStackTrace)1161 {1162 if (exception == null)1163 {1164 throw PSTraceSource.NewArgumentNullException(nameof(exception));1165 }1166 1167 if (fullyQualifiedErrorId == null)1168 {1169 throw PSTraceSource.NewArgumentNullException(nameof(fullyQualifiedErrorId));1170 }1171 1172 // Mark this error record as serialized1173 _isSerialized = true;1174 _error = exception;1175 _target = targetObject;1176 _serializedFullyQualifiedErrorId = fullyQualifiedErrorId;1177 _category = errorCategory;1178 _activityOverride = errorCategory_Activity;1179 _reasonOverride = errorCategory_Reason;1180 _targetNameOverride = errorCategory_TargetName;1181 _targetTypeOverride = errorCategory_TargetType;1182 _serializedErrorCategoryMessageOverride = errorCategory_Message;1183 if (errorDetails_Message != null)1184 {1185 ErrorDetails = new ErrorDetails(errorDetails_Message);1186 if (errorDetails_RecommendedAction != null)1187 {1188 ErrorDetails.RecommendedAction = errorDetails_RecommendedAction;1189 }1190 }1191 1192 _scriptStackTrace = errorDetails_ScriptStackTrace;1193 }1194 1195 /// <summary>1196 /// Adds the information about this error record to PSObject as notes.1197 /// </summary>1198 /// <returns></returns>1199 internal void ToPSObjectForRemoting(PSObject dest)1200 {