MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#define TRACE5 6using System.Reflection;7using System.Management.Automation.Internal;8 9namespace System.Management.Automation10{11 /// <summary>12 /// An PSTraceSource is a representation of a System.Diagnostics.TraceSource instance13 /// that is used in the PowerShell components to produce trace output.14 /// </summary>15 /// <remarks>16 /// It is permitted to subclass <see cref="PSTraceSource"/>17 /// but there is no established scenario for doing this, nor has it been tested.18 /// </remarks>19 /// <!--20 /// IF YOU ARE NOT PART OF THE PowerShell DEVELOPMENT TEAM PLEASE21 /// DO NOT USE THIS CLASS!!!!!22 ///23 /// The PSTraceSource class is derived from Switch to provide granular24 /// control over the tracing in a program. An instance of PSTraceSource25 /// is created for each category of tracing such that separate flags26 /// (filters) can be set. Each flag enables one or more method for tracing.27 ///28 /// For instance, the Exception flag will enable tracing on these methods:29 /// TraceException.30 /// </summary>31 /// <remarks>32 /// To get an instance of this class a user should define a public static33 /// field of the type PSTraceSource, decorated it with an attribute of34 /// PSTraceSourceAttribute, and assign the results of GetTracer to it.35 /// <newpara/>36 /// <example>37 /// <code>38 /// [PSTraceSourceAttribute("category", "description")]39 /// public static PSTraceSource tracer = GetTracer("category", "description");40 /// </code>41 /// </example>42 /// <newpara/>43 /// Other than initial creation of this class through the GetTracer method,44 /// this class should throw no exceptions. Any call to a PSTraceSource method45 /// that results in an exception being thrown will be ignored.46 /// -->47 public partial class PSTraceSource48 {49 /// <summary>50 /// Lock object for the GetTracer method.51 /// </summary>52 private static readonly object s_getTracerLock = new object();53 54 /// <summary>55 /// A helper to get an instance of the PSTraceSource class.56 /// </summary>57 /// <param name="name">58 /// The name of the category that this class59 /// will control the tracing for.60 /// </param>61 /// <param name="description">62 /// The description to describe what the category63 /// is used for.64 /// </param>65 /// <returns>66 /// An instance of the PSTraceSource class which is initialized67 /// to trace for the specified category. If multiple callers ask for the same category,68 /// the same PSTraceSource will be returned.69 /// </returns>70 internal static PSTraceSource GetTracer(71 string name,72 string description)73 {74 return PSTraceSource.GetTracer(name, description, true);75 }76 77 /// <summary>78 /// A helper to get an instance of the PSTraceSource class.79 /// </summary>80 /// <param name="name">81 /// The name of the category that this class82 /// will control the tracing for.83 /// </param>84 /// <param name="description">85 /// The description to describe what the category86 /// is used for.87 /// </param>88 /// <param name="traceHeaders">89 /// If true, the line headers will be traced, if false, only the trace message will be traced.90 /// </param>91 /// <returns>92 /// An instance of the PSTraceSource class which is initialized93 /// to trace for the specified category. If multiple callers ask for the same category,94 /// the same PSTraceSource will be returned.95 /// </returns>96 internal static PSTraceSource GetTracer(97 string name,98 string description,99 bool traceHeaders)100 {101 ArgumentException.ThrowIfNullOrEmpty(name);102 103 lock (PSTraceSource.s_getTracerLock)104 {105 PSTraceSource result = null;106 107 // See if we can find an PSTraceSource for this category in the catalog.108 PSTraceSource.TraceCatalog.TryGetValue(name, out result);109 110 // If it's not already in the catalog, see if we can find it in the111 // pre-configured trace source list112 113 if (result == null)114 {115 string keyName = name;116 if (!PSTraceSource.PreConfiguredTraceSource.ContainsKey(keyName))117 {118 if (keyName.Length > 16)119 {120 keyName = keyName.Substring(0, 16);121 if (!PSTraceSource.PreConfiguredTraceSource.ContainsKey(keyName))122 {123 keyName = null;124 }125 }126 else127 {128 keyName = null;129 }130 }131 132 if (keyName != null)133 {134 // Get the pre-configured trace source from the catalog135 PSTraceSource preconfiguredSource = PSTraceSource.PreConfiguredTraceSource[keyName];136 137 result = PSTraceSource.GetNewTraceSource(keyName, description, traceHeaders);138 result.Options = preconfiguredSource.Options;139 result.Listeners.Clear();140 result.Listeners.AddRange(preconfiguredSource.Listeners);141 142 // Add it to the TraceCatalog143 PSTraceSource.TraceCatalog.Add(keyName, result);144 145 // Remove it from the pre-configured catalog146 PSTraceSource.PreConfiguredTraceSource.Remove(keyName);147 }148 }149 150 // Even if there was a PSTraceSource in the catalog, let's replace151 // it with an PSTraceSource to get the added functionality. Anyone using152 // a StructuredTraceSource should be able to do so even with the PSTraceSource153 // instance.154 155 if (result == null)156 {157 result = PSTraceSource.GetNewTraceSource(name, description, traceHeaders);158 PSTraceSource.TraceCatalog[result.FullName] = result;159 }160 161 if (result.Options != PSTraceSourceOptions.None &&162 traceHeaders)163 {164 result.TraceGlobalAppDomainHeader();165 166 // Trace the object specific tracer information167 result.TracerObjectHeader(Assembly.GetCallingAssembly());168 }169 170 return result;171 }172 }173 174 internal static PSTraceSource GetNewTraceSource(175 string name,176 string description,177 bool traceHeaders)178 {179 // Note, all callers should have already verified the name before calling this180 // API, so this exception should never be exposed to an end-user.181 ArgumentException.ThrowIfNullOrEmpty(name);182 183 // Keep the fullName as it was passed, but truncate or pad184 // the category name to 16 characters. This allows for185 // uniform output186 187 string fullName = name;188 /*189 // This is here to ensure all the trace category names are 16 characters,190 // the problem is that the app-config file would need to contain the same191 // trailing spaces if this actually does pad the name.192 193 name =194 string.Format(195 System.Globalization.CultureInfo.InvariantCulture,196 "{0,-16}",197 name);198 */199 PSTraceSource result =200 new PSTraceSource(201 fullName,202 name,203 description,204 traceHeaders);205 return result;206 }207 208 #region TraceFlags.New*Exception methods/helpers209 210 /// <summary>211 /// Traces the Message and StackTrace properties of the exception212 /// and returns the new exception. This is not allowed to call other213 /// Throw*Exception variants, since they call this.214 /// </summary>215 /// <param name="paramName">216 /// The name of the parameter whose argument value was null217 /// </param>218 /// <returns>Exception instance ready to throw.</returns>219 internal static PSArgumentNullException NewArgumentNullException(string paramName)220 {221 ArgumentException.ThrowIfNullOrEmpty(paramName);222 223 string message = StringUtil.Format(AutomationExceptions.ArgumentNull, paramName);224 var e = new PSArgumentNullException(paramName, message);225 226 return e;227 }228 229 /// <summary>230 /// Traces the Message and StackTrace properties of the exception231 /// and returns the new exception. This variant allows the caller to232 /// specify alternate template text, but only in assembly S.M.A.Core.233 /// </summary>234 /// <param name="paramName">235 /// The name of the parameter whose argument value was invalid236 /// </param>237 /// <param name="resourceString">238 /// The template string for this error239 /// </param>240 /// <param name="args">241 /// Objects corresponding to {0}, {1}, etc. in the resource string242 /// </param>243 /// <returns>Exception instance ready to throw.</returns>244 internal static PSArgumentNullException NewArgumentNullException(245 string paramName, string resourceString, params object[] args)246 {247 if (string.IsNullOrEmpty(paramName))248 {249 throw NewArgumentNullException(nameof(paramName));250 }251 252 if (string.IsNullOrEmpty(resourceString))253 {254 throw NewArgumentNullException(nameof(resourceString));255 }256 257 string message = StringUtil.Format(resourceString, args);258 259 // Note that the paramName param comes first260 var e = new PSArgumentNullException(paramName, message);261 262 return e;263 }264 265 /// <summary>266 /// Traces the Message and StackTrace properties of the exception267 /// and returns the new exception. This variant uses the default268 /// ArgumentException template text. This is not allowed to call269 /// other Throw*Exception variants, since they call this.270 /// </summary>271 /// <param name="paramName">272 /// The name of the parameter whose argument value was invalid273 /// </param>274 /// <returns>Exception instance ready to throw.</returns>275 internal static PSArgumentException NewArgumentException(string paramName)276 {277 ArgumentException.ThrowIfNullOrEmpty(paramName);278 279 string message = StringUtil.Format(AutomationExceptions.Argument, paramName);280 281 // Note that the message param comes first282 var e = new PSArgumentException(message, paramName);283 284 return e;285 }286 287 /// <summary>288 /// Traces the Message and StackTrace properties of the exception289 /// and returns the new exception. This variant allows the caller to290 /// specify alternate template text, but only in assembly S.M.A.Core.291 /// </summary>292 /// <param name="paramName">293 /// The name of the parameter whose argument value was invalid294 /// </param>295 /// <param name="resourceString">296 /// The template string for this error297 /// </param>298 /// <param name="args">299 /// Objects corresponding to {0}, {1}, etc. in the resource string300 /// </param>301 /// <returns>Exception instance ready to throw.</returns>302 internal static PSArgumentException NewArgumentException(303 string paramName, string resourceString, params object[] args)304 {305 if (string.IsNullOrEmpty(paramName))306 {307 throw NewArgumentNullException(nameof(paramName));308 }309 310 if (string.IsNullOrEmpty(resourceString))311 {312 throw NewArgumentNullException(nameof(resourceString));313 }314 315 string message = StringUtil.Format(resourceString, args);316 317 // Note that the message param comes first318 var e = new PSArgumentException(message, paramName);319 320 return e;321 }322 323 /// <summary>324 /// Traces the Message and StackTrace properties of the exception325 /// and returns the new exception.326 /// </summary>327 /// <returns>Exception instance ready to throw.</returns>328 internal static PSInvalidOperationException NewInvalidOperationException()329 {330 string message = StringUtil.Format(AutomationExceptions.InvalidOperation,331 new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name);332 var e = new PSInvalidOperationException(message);333 334 return e;335 }336 337 /// <summary>338 /// Traces the Message and StackTrace properties of the exception339 /// and returns the new exception. This variant allows the caller to340 /// specify alternate template text, but only in assembly S.M.A.Core.341 /// </summary>342 /// <param name="resourceString">343 /// The template string for this error344 /// </param>345 /// <param name="args">346 /// Objects corresponding to {0}, {1}, etc. in the resource string347 /// </param>348 /// <returns>Exception instance ready to throw.</returns>349 internal static PSInvalidOperationException NewInvalidOperationException(350 string resourceString, params object[] args)351 {352 if (string.IsNullOrEmpty(resourceString))353 {354 throw NewArgumentNullException(nameof(resourceString));355 }356 357 string message = StringUtil.Format(resourceString, args);358 359 var e = new PSInvalidOperationException(message);360 return e;361 }362 363 /// <summary>364 /// Traces the Message and StackTrace properties of the exception365 /// and returns the new exception. This variant allows the caller to366 /// specify alternate template text, but only in assembly S.M.A.Core.367 /// </summary>368 /// <param name="innerException">369 /// This is the InnerException for the InvalidOperationException370 /// </param>371 /// <param name="resourceString">372 /// The template string for this error373 /// </param>374 /// <param name="args">375 /// Objects corresponding to {0}, {1}, etc. in the resource string376 /// </param>377 /// <returns>Exception instance ready to throw.</returns>378 internal static PSInvalidOperationException NewInvalidOperationException(379 Exception innerException,380 string resourceString, params object[] args)381 {382 if (string.IsNullOrEmpty(resourceString))383 {384 throw NewArgumentNullException(nameof(resourceString));385 }386 387 string message = StringUtil.Format(resourceString, args);388 389 var e = new PSInvalidOperationException(message, innerException);390 return e;391 }392 393 /// <summary>394 /// Traces the Message and StackTrace properties of the exception395 /// and returns the new exception. This is not allowed to call other396 /// Throw*Exception variants, since they call this.397 /// </summary>398 /// <returns>Exception instance ready to throw.</returns>399 internal static PSNotSupportedException NewNotSupportedException()400 {401 string message = StringUtil.Format(AutomationExceptions.NotSupported,402 new System.Diagnostics.StackTrace().GetFrame(0).ToString());403 var e = new PSNotSupportedException(message);404 405 return e;406 }407 408 /// <summary>409 /// Traces the Message and StackTrace properties of the exception410 /// and returns the new exception. This is not allowed to call other411 /// Throw*Exception variants, since they call this.412 /// </summary>413 /// <param name="resourceString">414 /// The template string for this error415 /// </param>416 /// <param name="args">417 /// Objects corresponding to {0}, {1}, etc. in the resource string418 /// </param>419 /// <returns>Exception instance ready to throw.</returns>420 internal static PSNotSupportedException NewNotSupportedException(421 string resourceString,422 params object[] args)423 {424 if (string.IsNullOrEmpty(resourceString))425 {426 throw NewArgumentNullException(nameof(resourceString));427 }428 429 string message = StringUtil.Format(resourceString, args);430 var e = new PSNotSupportedException(message);431 432 return e;433 }434 435 /// <summary>436 /// Traces the Message and StackTrace properties of the exception437 /// and returns the new exception. This is not allowed to call other438 /// Throw*Exception variants, since they call this.439 /// </summary>440 /// <returns>Exception instance ready to throw.</returns>441 internal static PSNotImplementedException NewNotImplementedException()442 {443 string message = StringUtil.Format(AutomationExceptions.NotImplemented,444 new System.Diagnostics.StackTrace().GetFrame(0).ToString());445 var e = new PSNotImplementedException(message);446 447 return e;448 }449 450 /// <summary>451 /// Traces the Message and StackTrace properties of the exception452 /// and returns the new exception. This variant uses the default453 /// ArgumentOutOfRangeException template text. This is not allowed to call454 /// other Throw*Exception variants, since they call this.455 /// </summary>456 /// <param name="paramName">457 /// The name of the parameter whose argument value was out of range458 /// </param>459 /// <param name="actualValue">460 /// The value of the argument causing the exception461 /// </param>462 /// <returns>Exception instance ready to throw.</returns>463 internal static PSArgumentOutOfRangeException NewArgumentOutOfRangeException(string paramName, object actualValue)464 {465 ArgumentException.ThrowIfNullOrEmpty(paramName);466 467 string message = StringUtil.Format(AutomationExceptions.ArgumentOutOfRange, paramName);468 var e = new PSArgumentOutOfRangeException(paramName, actualValue, message);469 470 return e;471 }472 473 /// <summary>474 /// Traces the Message and StackTrace properties of the exception475 /// and returns the new exception. This variant allows the caller to476 /// specify alternate template text, but only in assembly S.M.A.Core.477 /// </summary>478 /// <param name="paramName">479 /// The name of the parameter whose argument value was invalid480 /// </param>481 /// <param name="actualValue">482 /// The value of the argument causing the exception483 /// </param>484 /// <param name="resourceString">485 /// The template string for this error486 /// </param>487 /// <param name="args">488 /// Objects corresponding to {0}, {1}, etc. in the resource string489 /// </param>490 /// <returns>Exception instance ready to throw.</returns>491 internal static PSArgumentOutOfRangeException NewArgumentOutOfRangeException(492 string paramName, object actualValue, string resourceString, params object[] args)493 {494 if (string.IsNullOrEmpty(paramName))495 {496 throw NewArgumentNullException(nameof(paramName));497 }498 499 if (string.IsNullOrEmpty(resourceString))500 {501 throw NewArgumentNullException(nameof(resourceString));502 }503 504 string message = StringUtil.Format(resourceString, args);505 var e = new PSArgumentOutOfRangeException(paramName, actualValue, message);506 507 return e;508 }509 510 /// <summary>511 /// Traces the Message and StackTrace properties of the exception512 /// and returns the new exception. This variant uses the default513 /// ObjectDisposedException template text. This is not allowed to call514 /// other Throw*Exception variants, since they call this.515 /// </summary>516 /// <param name="objectName">517 /// The name of the disposed object518 /// </param>519 /// <returns>Exception instance ready to throw.</returns>520 /// <remarks>521 /// Note that the parameter is the object name and not the message.522 /// </remarks>523 internal static PSObjectDisposedException NewObjectDisposedException(string objectName)524 {525 if (string.IsNullOrEmpty(objectName))526 {527 throw NewArgumentNullException(nameof(objectName));528 }529 530 string message = StringUtil.Format(AutomationExceptions.ObjectDisposed, objectName);531 var e = new PSObjectDisposedException(objectName, message);532 533 return e;534 }535 536 #endregion TraceFlags.New*Exception methods/helpers537 }538}539 