MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.Generic;7using System.Diagnostics.CodeAnalysis;8using System.Globalization;9using System.Linq;10using System.Management.Automation.Internal;11using System.Management.Automation.Language;12using System.Management.Automation.Security;13using System.Runtime.CompilerServices;14using System.Text.RegularExpressions;15using System.Threading.Tasks;16 17namespace System.Management.Automation.Internal18{19 /// <summary>20 /// Serves as the base class for Metadata attributes.21 /// </summary>22 /// <remarks>23 /// PSSnapins may not create custom attributes derived directly from <see cref="CmdletMetadataAttribute"/>,24 /// since it has no public constructor. Only the public subclasses <see cref="ValidateArgumentsAttribute"/>25 /// and <see cref="ArgumentTransformationAttribute"/> are available.26 /// </remarks>27 /// <seealso cref="CmdletMetadataAttribute"/>28 /// <seealso cref="ValidateArgumentsAttribute"/>29 /// <seealso cref="ArgumentTransformationAttribute"/>30 [AttributeUsage(AttributeTargets.All)]31 public abstract class CmdletMetadataAttribute : Attribute32 {33 /// <summary>34 /// Default constructor.35 /// </summary>36 internal CmdletMetadataAttribute()37 {38 }39 }40 41 /// <summary>42 /// Serves as the base class for Metadata attributes that serve as guidance to the parser and parameter binder.43 /// </summary>44 /// <remarks>45 /// PSSnapins may not create custom attributes derived from <see cref="ParsingBaseAttribute"/>, since it46 /// has no public constructor. Only the sealed public subclasses <see cref="ParameterAttribute"/> and47 /// <see cref="AliasAttribute"/> are available.48 /// </remarks>49 /// <seealso cref="ParsingBaseAttribute"/>50 /// <seealso cref="ParameterAttribute"/>51 /// <seealso cref="AliasAttribute"/>52 [AttributeUsage(AttributeTargets.All)]53 public abstract class ParsingBaseAttribute : CmdletMetadataAttribute54 {55 /// <summary>56 /// Constructor with no parameters.57 /// </summary>58 internal ParsingBaseAttribute()59 {60 }61 }62}63 64namespace System.Management.Automation65{66 #region Base Metadata Classes67 68 /// <summary>69 /// Serves as the base class for Validate attributes that validate parameter arguments.70 /// </summary>71 /// <remarks>72 /// Argument validation attributes can be attached to <see cref="Cmdlet"/> and73 /// <see cref="Provider.CmdletProvider"/> parameters to ensure that the Cmdlet or CmdletProvider will74 /// not be invoked with invalid values of the parameter. Existing validation attributes include75 /// <see cref="ValidateCountAttribute"/>,76 /// <see cref="ValidateNotNullAttribute"/>,77 /// <see cref="ValidateNotNullOrEmptyAttribute"/>,78 /// <see cref="ValidateArgumentsAttribute"/>,79 /// <see cref="ValidateLengthAttribute"/>,80 /// <see cref="ValidateRangeAttribute"/>,81 /// <see cref="ValidatePatternAttribute"/>, and82 /// <see cref="ValidateSetAttribute"/>.83 /// PSSnapins wishing to create custom argument validation attributes should derive from84 /// <see cref="ValidateArgumentsAttribute"/> and override the85 /// <see cref="ValidateArgumentsAttribute.Validate"/> abstract method, after which they can apply the86 /// attribute to their parameters.87 /// <see cref="ValidateArgumentsAttribute"/> validates the argument as a whole. If the argument value may88 /// be an enumerable, you can derive from <see cref="ValidateEnumeratedArgumentsAttribute"/>89 /// which will take care of unrolling the enumerable and validate each element individually.90 /// It is also recommended to override <see cref="object.ToString"/> to return a readable string91 /// similar to the attribute declaration, for example "[ValidateRangeAttribute(5,10)]".92 /// If this attribute is applied to a string parameter, the string command argument will be validated.93 /// If this attribute is applied to a string[] parameter, the string[] command argument will be validated.94 /// </remarks>95 /// <seealso cref="ValidateEnumeratedArgumentsAttribute"/>96 /// <seealso cref="ValidateCountAttribute"/>97 /// <seealso cref="ValidateNotNullAttribute"/>98 /// <seealso cref="ValidateNotNullOrEmptyAttribute"/>99 /// <seealso cref="ValidateArgumentsAttribute"/>100 /// <seealso cref="ValidateLengthAttribute"/>101 /// <seealso cref="ValidateRangeAttribute"/>102 /// <seealso cref="ValidatePatternAttribute"/>103 /// <seealso cref="ValidateSetAttribute"/>104 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]105 public abstract class ValidateArgumentsAttribute : CmdletMetadataAttribute106 {107 /// <summary>108 /// Verify that the value of <paramref name="arguments"/> is valid.109 /// </summary>110 /// <param name="arguments">Argument value to validate.</param>111 /// <param name="engineIntrinsics">112 /// The engine APIs for the context under which the prerequisite is being evaluated.113 /// </param>114 /// <exception cref="ValidationMetadataException">Should be thrown for any validation failure.</exception>115 protected abstract void Validate(object arguments, EngineIntrinsics engineIntrinsics);116 117 /// <summary>118 /// Method that the command processor calls for data validate processing.119 /// </summary>120 /// <param name="o">Object to validate.</param>121 /// <param name="engineIntrinsics">122 /// The engine APIs for the context under which the prerequisite is being evaluated.123 /// </param>124 /// <returns>True if the validation succeeded.</returns>125 /// <exception cref="ValidationMetadataException">126 /// Whenever any exception occurs during data validation.127 /// Additionally, all the system exceptions are wrapped in ValidationMetadataException.128 /// </exception>129 /// <exception cref="ArgumentException">For invalid arguments.</exception>130 internal void InternalValidate(object o, EngineIntrinsics engineIntrinsics) => Validate(o, engineIntrinsics);131 132 /// <summary>133 /// Initializes a new instance of a class derived from <see cref="ValidateArgumentsAttribute"/>.134 /// </summary>135 protected ValidateArgumentsAttribute()136 {137 }138 }139 140 /// <summary>141 /// A variant of <see cref="ValidateArgumentsAttribute"/> which unrolls enumeration values and validates142 /// each element individually.143 /// </summary>144 /// <remarks>145 /// <see cref="ValidateEnumeratedArgumentsAttribute"/> is like <see cref="ValidateArgumentsAttribute"/>,146 /// except that if the argument value is enumerable, <see cref="ValidateEnumeratedArgumentsAttribute"/>147 /// will unroll the enumeration and validate each item individually.148 /// Existing enumerated validation attributes include149 /// <see cref="ValidateLengthAttribute"/>,150 /// <see cref="ValidateRangeAttribute"/>,151 /// <see cref="ValidatePatternAttribute"/>, and152 /// <see cref="ValidateSetAttribute"/>.153 /// PSSnapins wishing to create custom enumerated argument validation attributes should derive from154 /// <seealso cref="ValidateEnumeratedArgumentsAttribute"/> and override the155 /// <seealso cref="ValidateEnumeratedArgumentsAttribute.ValidateElement"/>156 /// abstract method, after which they can apply the attribute to their parameters.157 /// It is also recommended to override <see cref="object.ToString"/> to return a readable string158 /// similar to the attribute declaration, for example "[ValidateRangeAttribute(5,10)]".159 /// If this attribute is applied to a string parameter, the string command argument will be validated.160 /// If this attribute is applied to a string[] parameter, each string command argument will be validated.161 /// </remarks>162 /// <seealso cref="ValidateArgumentsAttribute"/>163 /// <seealso cref="ValidateLengthAttribute"/>164 /// <seealso cref="ValidateRangeAttribute"/>165 /// <seealso cref="ValidatePatternAttribute"/>166 /// <seealso cref="ValidateSetAttribute"/>167 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]168 public abstract class ValidateEnumeratedArgumentsAttribute : ValidateArgumentsAttribute169 {170 /// <summary>171 /// Initializes a new instance of a class derived from <see cref="ValidateEnumeratedArgumentsAttribute"/>.172 /// </summary>173 protected ValidateEnumeratedArgumentsAttribute() : base()174 {175 }176 177 /// <summary>178 /// Abstract method to be overridden by subclasses, implementing the validation of each parameter argument.179 /// </summary>180 /// <remarks>181 /// Validate that the value of <paramref name="element"/> is valid, and throw182 /// <see cref="ValidationMetadataException"/> if it is invalid.183 /// </remarks>184 /// <param name="element">One of the parameter arguments.</param>185 /// <exception cref="ValidationMetadataException">Should be thrown for any validation failure.</exception>186 protected abstract void ValidateElement(object element);187 188 /// <summary>189 /// Calls ValidateElement in each element in the enumeration argument value.190 /// </summary>191 /// <param name="arguments">Object to validate.</param>192 /// <param name="engineIntrinsics">193 /// The engine APIs for the context under which the prerequisite is being evaluated.194 /// </param>195 /// <remarks>196 /// PSSnapins should override <see cref="ValidateElement"/> instead.197 /// </remarks>198 /// <exception cref="ValidationMetadataException">Should be thrown for any validation failure.</exception>199 protected sealed override void Validate(object arguments, EngineIntrinsics engineIntrinsics)200 {201 if (LanguagePrimitives.IsNull(arguments))202 {203 throw new ValidationMetadataException(204 "ArgumentIsEmpty",205 null,206 Metadata.ValidateNotNullOrEmptyCollectionFailure);207 }208 209 var enumerator = _getEnumeratorSite.Target.Invoke(_getEnumeratorSite, arguments);210 211 if (enumerator == null)212 {213 ValidateElement(arguments);214 return;215 }216 217 // arguments is IEnumerator218 while (enumerator.MoveNext())219 {220 ValidateElement(enumerator.Current);221 }222 223 enumerator.Reset();224 }225 226 private readonly CallSite<Func<CallSite, object, IEnumerator>> _getEnumeratorSite =227 CallSite<Func<CallSite, object, IEnumerator>>.Create(PSEnumerableBinder.Get());228 }229 230 #endregion Base Metadata Classes231 232 #region Misc Attributes233 234 /// <summary>235 /// To specify RunAs behavior for the class236 /// /// </summary>237 public enum DSCResourceRunAsCredential238 {239 /// <summary>Default is same as optional.</summary>240 Default,241 /// <summary>242 /// PsDscRunAsCredential can not be used for this DSC Resource.243 /// </summary>244 NotSupported,245 /// <summary>246 /// PsDscRunAsCredential is mandatory for resource.247 /// </summary>248 Mandatory,249 /// <summary>250 /// PsDscRunAsCredential can or can not be specified.251 /// </summary>252 Optional = Default,253 }254 255 /// <summary>256 /// Indicates the class defines a DSC resource.257 /// </summary>258 [AttributeUsage(AttributeTargets.Class)]259 public class DscResourceAttribute : CmdletMetadataAttribute260 {261 /// <summary>262 /// To specify RunAs Behavior for the resource.263 /// </summary>264 public DSCResourceRunAsCredential RunAsCredential { get; set; }265 }266 267 /// <summary>268 /// When specified on a property or field of a DSC Resource, the property269 /// can or must be specified in a configuration, unless it is marked270 /// <see cref="DscPropertyAttribute.NotConfigurable"/>, in which case it is271 /// returned by the Get() method of the resource.272 /// </summary>273 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]274 public class DscPropertyAttribute : CmdletMetadataAttribute275 {276 /// <summary>277 /// Indicates the property is a required key property for a DSC resource.278 /// </summary>279 public bool Key { get; set; }280 281 /// <summary>282 /// Indicates the property is a required property for a DSC resource.283 /// </summary>284 public bool Mandatory { get; set; }285 286 /// <summary>287 /// Indicates the property is not a parameter to the DSC resource, but the288 /// property will contain a value after the Get() method of the resource is called.289 /// </summary>290 public bool NotConfigurable { get; set; }291 }292 293 /// <summary>294 /// Indication the configuration is for local configuration manager, also known as meta configuration.295 /// </summary>296 [AttributeUsage(AttributeTargets.Class)]297 public class DscLocalConfigurationManagerAttribute : CmdletMetadataAttribute298 {299 }300 301 /// <summary>302 /// Contains information about a cmdlet's metadata.303 /// </summary>304 [AttributeUsage(AttributeTargets.Class)]305 public abstract class CmdletCommonMetadataAttribute : CmdletMetadataAttribute306 {307 /// <summary>308 /// Gets or sets the cmdlet default parameter set.309 /// </summary>310 public string DefaultParameterSetName { get; set; }311 312 /// <summary>313 /// Gets or sets a Boolean value that indicates the Cmdlet supports ShouldProcess. By default314 /// the value is false, meaning the cmdlet doesn't support ShouldProcess.315 /// </summary>316 public bool SupportsShouldProcess { get; set; } = false;317 318 /// <summary>319 /// Gets or sets a Boolean value that indicates the Cmdlet supports Paging. By default320 /// the value is false, meaning the cmdlet doesn't support Paging.321 /// </summary>322 public bool SupportsPaging { get; set; } = false;323 324 /// <summary>325 /// Gets or sets a Boolean value that indicates the Cmdlet supports Transactions. By default326 /// the value is false, meaning the cmdlet doesn't support Transactions.327 /// </summary>328 public bool SupportsTransactions329 {330 get331 {332 return _supportsTransactions;333 }334 335 set336 {337#if !CORECLR338 _supportsTransactions = value;339#else340 // Disable 'SupportsTransactions' in CoreCLR341 // No transaction supported on CSS due to the lack of System.Transactions namespace342 _supportsTransactions = false;343#endif344 }345 }346 347 private bool _supportsTransactions = false;348 349 private ConfirmImpact _confirmImpact = ConfirmImpact.Medium;350 351 /// <summary>352 /// Gets or sets a ConfirmImpact value that indicates the "destructiveness" of the operation353 /// and when it should be confirmed. This should only be used when SupportsShouldProcess is354 /// specified.355 /// </summary>356 public ConfirmImpact ConfirmImpact357 {358 get => SupportsShouldProcess ? _confirmImpact : ConfirmImpact.None;359 set => _confirmImpact = value;360 }361 362 /// <summary>363 /// Gets or sets a HelpUri value that indicates the location of online help. This is used by364 /// Get-Help to retrieve help content when -Online is specified.365 /// </summary>366 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]367 public string HelpUri { get; set; } = string.Empty;368 369 /// <summary>370 /// Gets or sets the RemotingBehavior value that declares how this cmdlet should interact371 /// with ambient remoting.372 /// </summary>373 public RemotingCapability RemotingCapability { get; set; } = RemotingCapability.PowerShell;374 }375 376 /// <summary>377 /// Identifies a class as a cmdlet and specifies the verb and noun identifying this cmdlet.378 /// </summary>379 [AttributeUsage(AttributeTargets.Class)]380 public sealed class CmdletAttribute : CmdletCommonMetadataAttribute381 {382 /// <summary>383 /// Gets the cmdlet noun.384 /// </summary>385 public string NounName { get; }386 387 /// <summary>388 /// Gets the cmdlet verb.389 /// </summary>390 public string VerbName { get; }391 392 /// <summary>393 /// Initializes a new instance of the CmdletAttribute class.394 /// </summary>395 /// <param name="verbName">Verb for the command.</param>396 /// <param name="nounName">Noun for the command.</param>397 /// <exception cref="ArgumentException">For invalid arguments.</exception>398 public CmdletAttribute(string verbName, string nounName)399 {400 // NounName,VerbName have to be Non-Null strings401 if (string.IsNullOrEmpty(nounName))402 {403 throw PSTraceSource.NewArgumentException(nameof(nounName));404 }405 406 if (string.IsNullOrEmpty(verbName))407 {408 throw PSTraceSource.NewArgumentException(nameof(verbName));409 }410 411 NounName = nounName;412 VerbName = verbName;413 }414 }415 416 /// <summary>417 /// Identifies PowerShell script code as behaving like a cmdlet and hence uses cmdlet parameter binding418 /// instead of script parameter binding.419 /// </summary>420 [AttributeUsage(AttributeTargets.Class)]421 public class CmdletBindingAttribute : CmdletCommonMetadataAttribute422 {423 /// <summary>424 /// When true, the script will auto-generate appropriate parameter metadata to support positional425 /// parameters if the script hasn't already specified multiple parameter sets or specified positions426 /// explicitly via the <see cref="ParameterAttribute"/>.427 /// </summary>428 public bool PositionalBinding { get; set; } = true;429 }430 431 /// <summary>432 /// OutputTypeAttribute is used to specify the type of objects output by a cmdlet or script.433 /// </summary>434 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]435 [SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments")]436 public sealed class OutputTypeAttribute : CmdletMetadataAttribute437 {438 /// <summary>439 /// Construct the attribute from a <see>System.Type</see>440 /// </summary>441 internal OutputTypeAttribute(Type type)442 {443 Type = new[] { new PSTypeName(type) };444 }445 446 /// <summary>447 /// Construct the attribute from a type name.448 /// </summary>449 internal OutputTypeAttribute(string typeName)450 {451 Type = new[] { new PSTypeName(typeName) };452 }453 454 /// <summary>455 /// Construct the attribute from an array of <see>System.Type</see>456 /// </summary>457 /// <param name="type">The types output by the cmdlet.</param>458 public OutputTypeAttribute(params Type[] type)459 {460 if (type?.Length > 0)461 {462 Type = new PSTypeName[type.Length];463 for (int i = 0; i < type.Length; i++)464 {465 Type[i] = new PSTypeName(type[i]);466 }467 }468 else469 {470 Type = Array.Empty<PSTypeName>();471 }472 }473 474 /// <summary>475 /// Construct the attribute from an array of names of types.476 /// </summary>477 /// <param name="type">The types output by the cmdlet.</param>478 public OutputTypeAttribute(params string[] type)479 {480 if (type?.Length > 0)481 {482 Type = new PSTypeName[type.Length];483 for (int i = 0; i < type.Length; i++)484 {485 Type[i] = new PSTypeName(type[i]);486 }487 }488 else489 {490 Type = Array.Empty<PSTypeName>();491 }492 }493 494 /// <summary>495 /// The types specified by the attribute.496 /// </summary>497 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]498 [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]499 public PSTypeName[] Type { get; }500 501 /// <summary>502 /// Attributes implemented by a provider can use:503 /// [OutputType(ProviderCmdlet='cmdlet', typeof(...))]504 /// To specify the provider specific objects returned for a given cmdlet.505 /// </summary>506 public string ProviderCmdlet { get; set; }507 508 /// <summary>509 /// The list of parameter sets this OutputType specifies.510 /// </summary>511 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]512 public string[] ParameterSetName513 {514 get => _parameterSetName ??= new[] { ParameterAttribute.AllParameterSets };515 516 set => _parameterSetName = value;517 }518 519 private string[] _parameterSetName;520 }521 522 /// <summary>523 /// This attribute is used on a dynamic assembly to mark it as one that is used to implement524 /// a set of classes defined in a PowerShell script.525 /// </summary>526 [AttributeUsage(AttributeTargets.Assembly)]527 public class DynamicClassImplementationAssemblyAttribute : Attribute528 {529 /// <summary>530 /// The (possibly null) path to the file defining this class.531 /// </summary>532 public string ScriptFile { get; set; }533 }534 535 #endregion Misc Attributes536 537 #region Parsing guidelines Attributes538 /// <summary>539 /// Declares an alternative name for a parameter, cmdlet, or function.540 /// </summary>541 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]542 public sealed class AliasAttribute : ParsingBaseAttribute543 {544 internal string[] aliasNames;545 546 /// <summary>547 /// Gets the alias names passed to the constructor.548 /// </summary>549 public IList<string> AliasNames { get => this.aliasNames; }550 551 /// <summary>552 /// Initializes a new instance of the AliasAttribute class.553 /// </summary>554 /// <param name="aliasNames">The name for this alias.</param>555 /// <exception cref="ArgumentException">For invalid arguments.</exception>556 public AliasAttribute(params string[] aliasNames)557 {558 if (aliasNames == null)559 {560 throw PSTraceSource.NewArgumentNullException(nameof(aliasNames));561 }562 563 this.aliasNames = aliasNames;564 }565 }566 567 /// <summary>568 /// Identifies parameters to Cmdlets.569 /// </summary>570 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]571 public sealed class ParameterAttribute : ParsingBaseAttribute572 {573 /// <summary>574 /// ParameterSetName referring to all ParameterSets.575 /// </summary>576 public const string AllParameterSets = "__AllParameterSets";577 578 /// <summary>579 /// Initializes a new instance of the ParameterAttribute class.580 /// </summary>581 public ParameterAttribute()582 {583 }584 585 /// <summary>586 /// Initializes a new instance that is associated with an experimental feature.587 /// </summary>588 public ParameterAttribute(string experimentName, ExperimentAction experimentAction)589 {590 ExperimentalAttribute.ValidateArguments(experimentName, experimentAction);591 ExperimentName = experimentName;592 ExperimentAction = experimentAction;593 }594 595 private string _parameterSetName = ParameterAttribute.AllParameterSets;596 597 private string _helpMessage;598 private string _helpMessageBaseName;599 private string _helpMessageResourceId;600 601 #region Experimental Feature Related Properties602 603 /// <summary>604 /// Gets the name of the experimental feature this attribute is associated with.605 /// </summary>606 public string ExperimentName { get; }607 608 /// <summary>609 /// Gets the action for the engine to take when the experimental feature is enabled.610 /// </summary>611 public ExperimentAction ExperimentAction { get; }612 613 internal bool ToHide => EffectiveAction == ExperimentAction.Hide;614 615 internal bool ToShow => EffectiveAction == ExperimentAction.Show;616 617 /// <summary>618 /// Gets the effective action to take at run time.619 /// </summary>620 private ExperimentAction EffectiveAction621 {622 get623 {624 if (_effectiveAction == ExperimentAction.None)625 {626 _effectiveAction = ExperimentalFeature.GetActionToTake(ExperimentName, ExperimentAction);627 }628 629 return _effectiveAction;630 }631 }632 633 private ExperimentAction _effectiveAction = default(ExperimentAction);634 635 #endregion636 637 /// <summary>638 /// Gets or sets the parameter position.639 /// If not set, the parameter is named.640 /// </summary>641 public int Position { get; set; } = int.MinValue;642 643 /// <summary>644 /// Gets or sets the name of the parameter set this parameter belongs to.645 /// When it is not specified, <see cref="ParameterAttribute.AllParameterSets"/> is assumed.646 /// </summary>647 public string ParameterSetName648 {649 get => _parameterSetName;650 651 set => _parameterSetName = string.IsNullOrEmpty(value) ? ParameterAttribute.AllParameterSets : value;652 }653 654 /// <summary>655 /// Gets or sets a flag specifying if this parameter is Mandatory.656 /// When it is not specified, false is assumed and the parameter is considered optional.657 /// </summary>658 public bool Mandatory { get; set; } = false;659 660 /// <summary>661 /// Gets or sets a flag that specifies that this parameter can take values from the incoming pipeline662 /// object.663 /// When it is not specified, false is assumed.664 /// </summary>665 public bool ValueFromPipeline { get; set; }666 667 /// <summary>668 /// Gets or sets a flag that specifies that this parameter can take values from a property in the669 /// incoming pipeline object with the same name as the parameter or an alias of the parameter.670 /// When it is not specified, false is assumed.671 /// </summary>672 public bool ValueFromPipelineByPropertyName { get; set; }673 674 /// <summary>675 /// Gets or sets a flag that specifies that the remaining command line parameters should be676 /// associated with this parameter in the form of an array.677 /// When it is not specified, false is assumed.678 /// </summary>679 public bool ValueFromRemainingArguments { get; set; } = false;680 681 /// <summary>682 /// Gets or sets a short description for this parameter, suitable for presentation as a tool tip.683 /// </summary>684 /// <exception cref="ArgumentException">For a null or empty value when setting.</exception>685 public string HelpMessage686 {687 get => _helpMessage;688 689 set690 {691 if (string.IsNullOrEmpty(value))692 {693 throw PSTraceSource.NewArgumentException(nameof(HelpMessage));694 }695 696 _helpMessage = value;697 }698 }699 700 /// <summary>701 /// Gets or sets the base name of the resource for a help message.702 /// When this field is specified, HelpMessageResourceId must also be specified.703 /// </summary>704 /// <exception cref="ArgumentException">For a null or empty value when setting.</exception>705 public string HelpMessageBaseName706 {707 get => _helpMessageBaseName;708 709 set710 {711 if (string.IsNullOrEmpty(value))712 {713 throw PSTraceSource.NewArgumentException(nameof(HelpMessageBaseName));714 }715 716 _helpMessageBaseName = value;717 }718 }719 720 /// <summary>721 /// Gets or sets the Id of the resource for a help message.722 /// When this field is specified, HelpMessageBaseName must also be specified.723 /// </summary>724 /// <exception cref="ArgumentException">For a null or empty value when setting.</exception>725 public string HelpMessageResourceId726 {727 get => _helpMessageResourceId;728 729 set730 {731 if (string.IsNullOrEmpty(value))732 {733 throw PSTraceSource.NewArgumentException(nameof(HelpMessageResourceId));734 }735 736 _helpMessageResourceId = value;737 }738 }739 740 /// <summary>741 /// Indicates that this parameter should not be shown to the user in this like intellisense742 /// This is primarily to be used in functions that are implementing the logic for dynamic keywords.743 /// </summary>744 public bool DontShow { get; set; }745 }746 747 /// <summary>748 /// Specifies PSTypeName of a cmdlet or function parameter.749 /// </summary>750 /// <remarks>751 /// This attribute is used to restrict the type name of the parameter, when the type goes beyond the .NET type system.752 /// For example one could say: [PSTypeName("System.Management.ManagementObject#root\cimv2\Win32_Process")]753 /// to only allow Win32_Process objects to be bound to the parameter.754 /// </remarks>755 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]756 public class PSTypeNameAttribute : Attribute757 {758 /// <summary>759 /// </summary>760 public string PSTypeName { get; }761 762 /// <summary>763 /// Creates a new PSTypeNameAttribute.764 /// </summary>765 /// <param name="psTypeName"></param>766 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]767 public PSTypeNameAttribute(string psTypeName)768 {769 if (string.IsNullOrEmpty(psTypeName))770 {771 throw PSTraceSource.NewArgumentException(nameof(psTypeName));772 }773 774 this.PSTypeName = psTypeName;775 }776 }777 778 /// <summary>779 /// Specifies that a parameter supports wildcards.780 /// </summary>781 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]782 public sealed class SupportsWildcardsAttribute : ParsingBaseAttribute783 {784 }785 786 /// <summary>787 /// Specify a default value and/or help comment for a command parameter. This attribute788 /// does not have any semantic meaning, it is simply an aid to tools to make it simpler789 /// to know the true default value of a command parameter (which may or may not have790 /// any correlation with, e.g., the backing store of the Parameter's property or field.791 /// </summary>792 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]793 public sealed class PSDefaultValueAttribute : ParsingBaseAttribute794 {795 /// <summary>796 /// Specify the default value of a command parameter. The PowerShell engine does not797 /// use this value in any way, it exists for other tools that want to reflect on cmdlets.798 /// </summary>799 public object Value { get; set; }800 801 /// <summary>802 /// Specify the help string for the default value of a command parameter.803 /// </summary>804 public string Help { get; set; }805 }806 807 /// <summary>808 /// Specify that the member is hidden for the purposes of cmdlets like Get-Member and that the809 /// member is not displayed by default by Format-* cmdlets.810 /// </summary>811 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Event)]812 public sealed class HiddenAttribute : ParsingBaseAttribute813 {814 }815 816 #endregion Parsing guidelines Attributes817 818 #region Data validate Attributes819 820 /// <summary>821 /// Validates that the length of each parameter argument's Length falls in the range specified by822 /// <see cref="MinLength"/> and <see cref="MaxLength"/>.823 /// </summary>824 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]825 public sealed class ValidateLengthAttribute : ValidateEnumeratedArgumentsAttribute826 {827 /// <summary>828 /// Gets the attribute's minimum length.829 /// </summary>830 public int MinLength { get; }831 832 /// <summary>833 /// Gets the attribute's maximum length.834 /// </summary>835 public int MaxLength { get; }836 837 /// <summary>838 /// Validates that the length of each parameter argument's Length falls in the range specified839 /// by <see cref="MinLength"/> and <see cref="MaxLength"/>.840 /// </summary>841 /// <param name="element">Object to validate.</param>842 /// <exception cref="ValidationMetadataException">If <paramref name="element"/> is not a string843 /// with length between minLength and maxLength</exception>844 /// <exception cref="ArgumentException">For invalid arguments.</exception>845 protected override void ValidateElement(object element)846 {847 if (element is not string objectString)848 {849 throw new ValidationMetadataException(850 "ValidateLengthNotString",851 null,852 Metadata.ValidateLengthNotString);853 }854 855 int len = objectString.Length;856 857 if (len < MinLength)858 {859 throw new ValidationMetadataException(860 "ValidateLengthMinLengthFailure",861 null,862 Metadata.ValidateLengthMinLengthFailure,863 MinLength, len);864 }865 866 if (len > MaxLength)867 {868 throw new ValidationMetadataException(869 "ValidateLengthMaxLengthFailure",870 null,871 Metadata.ValidateLengthMaxLengthFailure,872 MaxLength, len);873 }874 }875 876 /// <summary>877 /// Initializes a new instance of the <see cref="ValidateLengthAttribute"/> class.878 /// </summary>879 /// <param name="minLength">Minimum required length.</param>880 /// <param name="maxLength">Maximum required length.</param>881 /// <exception cref="ArgumentOutOfRangeException">For invalid arguments.</exception>882 /// <exception cref="ValidationMetadataException">If maxLength is less than minLength.</exception>883 public ValidateLengthAttribute(int minLength, int maxLength) : base()884 {885 if (minLength < 0)886 {887 throw PSTraceSource.NewArgumentOutOfRangeException(nameof(minLength), minLength);888 }889 890 if (maxLength <= 0)891 {892 throw PSTraceSource.NewArgumentOutOfRangeException(nameof(maxLength), maxLength);893 }894 895 if (maxLength < minLength)896 {897 throw new ValidationMetadataException(898 "ValidateLengthMaxLengthSmallerThanMinLength",899 null,900 Metadata.ValidateLengthMaxLengthSmallerThanMinLength);901 }902 903 MinLength = minLength;904 MaxLength = maxLength;905 }906 }907 908 /// <summary>909 /// Predefined range kind to use with ValidateRangeAttribute.910 /// </summary>911 public enum ValidateRangeKind912 {913 /// <summary>914 /// Range is greater than 0.915 /// </summary>916 Positive,917 918 /// <summary>919 /// Range is greater than or equal to 0.920 /// </summary>921 NonNegative,922 923 /// <summary>924 /// Range is less than 0.925 /// </summary>926 Negative,927 928 /// <summary>929 /// Range is less than or equal to 0.930 /// </summary>931 NonPositive932 }933 /// <summary>934 /// Validates that each parameter argument falls in the range specified by <see cref="MinRange"/>935 /// and <see cref="MaxRange"/>.936 /// </summary>937 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]938 public sealed class ValidateRangeAttribute : ValidateEnumeratedArgumentsAttribute939 {940 /// <summary>941 /// Gets the attribute's minimum range.942 /// </summary>943 public object MinRange { get; }944 945 private readonly IComparable _minComparable;946 947 /// <summary>948 /// Gets the attribute's maximum range.949 /// </summary>950 public object MaxRange { get; }951 952 private readonly IComparable _maxComparable;953 954 /// <summary>955 /// The range values and the value to validate will all be converted to the promoted type.956 /// If minRange and maxRange are the same type,957 /// </summary>958 private readonly Type _promotedType;959 960 /// <summary>961 /// Gets the name of the predefined range.962 /// </summary>963 internal ValidateRangeKind? RangeKind { get => _rangeKind; }964 965 private readonly ValidateRangeKind? _rangeKind;966 967 /// <summary>968 /// Validates that each parameter argument falls in the range specified by <see cref="MinRange"/>969 /// and <see cref="MaxRange"/>.970 /// </summary>971 /// <param name="element">Object to validate.</param>972 /// <exception cref="ValidationMetadataException">973 /// Thrown if the object to be validated does not implement <see cref="IComparable"/>,974 /// if the element type is not the same as MinRange/MaxRange, or if the element is not between975 /// MinRange and MaxRange.976 /// </exception>977 protected override void ValidateElement(object element)978 {979 if (element == null)980 {981 throw new ValidationMetadataException(982 "ArgumentIsEmpty",983 null,984 Metadata.ValidateNotNullFailure);985 }986 987 var o = element as PSObject;988 if (o != null)989 {990 element = o.BaseObject;991 }992 993 if (_rangeKind.HasValue)994 {995 ValidateRange(element, (ValidateRangeKind)_rangeKind);996 }997 else998 {999 ValidateRange(element);1000 }1001 }1002 1003 /// <summary>1004 /// Initializes a new instance of the <see cref="ValidateRangeAttribute"/> class.1005 /// </summary>1006 /// <param name="minRange">Minimum value of the range allowed.</param>1007 /// <param name="maxRange">Maximum value of the range allowed.</param>1008 /// <exception cref="ArgumentNullException">For invalid arguments.</exception>1009 /// <exception cref="ValidationMetadataException">1010 /// if <paramref name="maxRange"/> has a different type than <paramref name="minRange"/>1011 /// if <paramref name="maxRange"/> is smaller than <paramref name="minRange"/>1012 /// if <paramref name="maxRange"/>, <paramref name="minRange"/> are not <see cref="IComparable"/>1013 /// </exception>1014 public ValidateRangeAttribute(object minRange, object maxRange) : base()1015 {1016 if (minRange == null)1017 {1018 throw PSTraceSource.NewArgumentNullException(nameof(minRange));1019 }1020 1021 if (maxRange == null)1022 {1023 throw PSTraceSource.NewArgumentNullException(nameof(maxRange));1024 }1025 1026 if (maxRange.GetType() != minRange.GetType())1027 {1028 bool failure = true;1029 _promotedType = GetCommonType(minRange.GetType(), maxRange.GetType());1030 if (_promotedType != null)1031 {1032 if (LanguagePrimitives.TryConvertTo(minRange, _promotedType, out object minResultValue)1033 && LanguagePrimitives.TryConvertTo(maxRange, _promotedType, out object maxResultValue))1034 {1035 minRange = minResultValue;1036 maxRange = maxResultValue;1037 failure = false;1038 }1039 }1040 1041 if (failure)1042 {1043 throw new ValidationMetadataException(1044 "MinRangeNotTheSameTypeOfMaxRange",1045 null,1046 Metadata.ValidateRangeMinRangeMaxRangeType,1047 minRange.GetType().Name, maxRange.GetType().Name);1048 }1049 }1050 else1051 {1052 _promotedType = minRange.GetType();1053 }1054 1055 // minRange and maxRange have the same type, so we just need to check one of them1056 _minComparable = minRange as IComparable;1057 if (_minComparable == null)1058 {1059 throw new ValidationMetadataException(1060 "MinRangeNotIComparable",1061 null,1062 Metadata.ValidateRangeNotIComparable);1063 }1064 1065 _maxComparable = maxRange as IComparable;1066 Diagnostics.Assert(_maxComparable != null, "maxComparable comes from a type that is IComparable");1067 1068 // Thanks to the IComparable test above this will not throw. They have the same type and are IComparable.1069 if (_minComparable.CompareTo(maxRange) > 0)1070 {1071 throw new ValidationMetadataException(1072 "MaxRangeSmallerThanMinRange",1073 null,1074 Metadata.ValidateRangeMaxRangeSmallerThanMinRange);1075 }1076 1077 MinRange = minRange;1078 MaxRange = maxRange;1079 }1080 1081 /// <summary>1082 /// Initializes a new instance of the <see cref="ValidateRangeAttribute"/> class.1083 /// This constructor uses a predefined <see cref="ValidateRangeKind"/>.1084 /// </summary>1085 public ValidateRangeAttribute(ValidateRangeKind kind) : base()1086 {1087 _rangeKind = kind;1088 }1089 1090 private static void ValidateRange(object element, ValidateRangeKind rangeKind)1091 {1092 if (element is TimeSpan ts)1093 {1094 ValidateTimeSpanRange(ts, rangeKind);1095 return;1096 }1097 1098 Type commonType = GetCommonType(typeof(int), element.GetType());1099 if (commonType == null)1100 {1101 throw new ValidationMetadataException(1102 "ValidationRangeElementType",1103 innerException: null,1104 Metadata.ValidateRangeElementType,1105 element.GetType().Name,1106 nameof(Int32));1107 }1108 1109 object resultValue;1110 IComparable dynamicZero = 0;1111 1112 if (LanguagePrimitives.TryConvertTo(element, commonType, out resultValue))1113 {1114 element = resultValue;1115 1116 if (LanguagePrimitives.TryConvertTo(0, commonType, out resultValue))1117 {1118 dynamicZero = (IComparable)resultValue;1119 }1120 }1121 else1122 {1123 throw new ValidationMetadataException(1124 "ValidationRangeElementType",1125 null,1126 Metadata.ValidateRangeElementType,1127 element.GetType().Name,1128 commonType.Name);1129 }1130 1131 switch (rangeKind)1132 {1133 case ValidateRangeKind.Positive:1134 if (dynamicZero.CompareTo(element) >= 0)1135 {1136 throw new ValidationMetadataException(1137 "ValidateRangePositiveFailure",1138 null,1139 Metadata.ValidateRangePositiveFailure,1140 element.ToString());1141 }1142 1143 break;1144 case ValidateRangeKind.NonNegative:1145 if (dynamicZero.CompareTo(element) > 0)1146 {1147 throw new ValidationMetadataException(1148 "ValidateRangeNonNegativeFailure",1149 null,1150 Metadata.ValidateRangeNonNegativeFailure,1151 element.ToString());1152 }1153 1154 break;1155 case ValidateRangeKind.Negative:1156 if (dynamicZero.CompareTo(element) <= 0)1157 {1158 throw new ValidationMetadataException(1159 "ValidateRangeNegativeFailure",1160 null,1161 Metadata.ValidateRangeNegativeFailure,1162 element.ToString());1163 }1164 1165 break;1166 case ValidateRangeKind.NonPositive:1167 if (dynamicZero.CompareTo(element) < 0)1168 {1169 throw new ValidationMetadataException(1170 "ValidateRangeNonPositiveFailure",1171 null,1172 Metadata.ValidateRangeNonPositiveFailure,1173 element.ToString());1174 }1175 1176 break;1177 }1178 }1179 1180 private void ValidateRange(object element)1181 {1182 // MinRange and MaxRange have the same type, so we just need to compare to one of them.1183 if (element.GetType() != _promotedType)1184 {1185 if (LanguagePrimitives.TryConvertTo(element, _promotedType, out object resultValue))1186 {1187 element = resultValue;1188 }1189 else1190 {1191 throw new ValidationMetadataException(1192 "ValidationRangeElementType",1193 null,1194 Metadata.ValidateRangeElementType,1195 element.GetType().Name,1196 MinRange.GetType().Name);1197 }1198 }1199 1200 // They are the same type and are all IComparable, so this should not throw