MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Globalization;7using System.Linq;8using System.Management.Automation.Language;9using System.Reflection;10 11using Microsoft.PowerShell;12 13using Dbg = System.Diagnostics.Debug;14 15namespace System.Management.Automation16{17 /// <summary>18 /// This class represents the compiled metadata for a parameter set.19 /// </summary>20 public sealed class ParameterSetMetadata21 {22 #region Private Data23 24 private bool _isMandatory;25 private int _position;26 private bool _valueFromPipeline;27 private bool _valueFromPipelineByPropertyName;28 private bool _valueFromRemainingArguments;29 private string _helpMessage;30 private string _helpMessageBaseName;31 private string _helpMessageResourceId;32 33 #endregion34 35 #region Constructor36 37 /// <summary>38 /// </summary>39 /// <param name="psMD"></param>40 internal ParameterSetMetadata(ParameterSetSpecificMetadata psMD)41 {42 Dbg.Assert(psMD != null, "ParameterSetSpecificMetadata cannot be null");43 Initialize(psMD);44 }45 46 /// <summary>47 /// A copy constructor that creates a deep copy of the <paramref name="other"/> ParameterSetMetadata object.48 /// </summary>49 /// <param name="other">Object to copy.</param>50 internal ParameterSetMetadata(ParameterSetMetadata other)51 {52 if (other == null)53 {54 throw PSTraceSource.NewArgumentNullException(nameof(other));55 }56 57 _helpMessage = other._helpMessage;58 _helpMessageBaseName = other._helpMessageBaseName;59 _helpMessageResourceId = other._helpMessageResourceId;60 _isMandatory = other._isMandatory;61 _position = other._position;62 _valueFromPipeline = other._valueFromPipeline;63 _valueFromPipelineByPropertyName = other._valueFromPipelineByPropertyName;64 _valueFromRemainingArguments = other._valueFromRemainingArguments;65 }66 67 #endregion68 69 #region Public Properties70 71 /// <summary>72 /// Returns true if the parameter is mandatory for this parameterset, false otherwise.73 /// </summary>74 /// <value></value>75 public bool IsMandatory76 {77 get78 {79 return _isMandatory;80 }81 82 set83 {84 _isMandatory = value;85 }86 }87 88 /// <summary>89 /// If the parameter is allowed to be positional for this parameter set, this returns90 /// the position it is allowed to be in. If it is not positional, this returns int.MinValue.91 /// </summary>92 /// <value></value>93 public int Position94 {95 get96 {97 return _position;98 }99 100 set101 {102 _position = value;103 }104 }105 106 /// <summary>107 /// Specifies that this parameter can take values from the incoming pipeline object.108 /// </summary>109 public bool ValueFromPipeline110 {111 get112 {113 return _valueFromPipeline;114 }115 116 set117 {118 _valueFromPipeline = value;119 }120 }121 122 /// <summary>123 /// Specifies that this parameter can take values from a property from the incoming124 /// pipeline object with the same name as the parameter.125 /// </summary>126 public bool ValueFromPipelineByPropertyName127 {128 get129 {130 return _valueFromPipelineByPropertyName;131 }132 133 set134 {135 _valueFromPipelineByPropertyName = value;136 }137 }138 139 /// <summary>140 /// Specifies if this parameter takes all the remaining unbound141 /// arguments that were specified.142 /// </summary>143 /// <value></value>144 public bool ValueFromRemainingArguments145 {146 get147 {148 return _valueFromRemainingArguments;149 }150 151 set152 {153 _valueFromRemainingArguments = value;154 }155 }156 157 /// <summary>158 /// A short description for this parameter, suitable for presentation as a tool tip.159 /// </summary>160 public string HelpMessage161 {162 get163 {164 return _helpMessage;165 }166 167 set168 {169 _helpMessage = value;170 }171 }172 173 /// <summary>174 /// The base name of the resource for a help message.175 /// </summary>176 public string HelpMessageBaseName177 {178 get179 {180 return _helpMessageBaseName;181 }182 183 set184 {185 _helpMessageBaseName = value;186 }187 }188 189 /// <summary>190 /// The Id of the resource for a help message.191 /// </summary>192 public string HelpMessageResourceId193 {194 get195 {196 return _helpMessageResourceId;197 }198 199 set200 {201 _helpMessageResourceId = value;202 }203 }204 205 #endregion206 207 #region Private / Internal Methods & Properties208 209 /// <summary>210 /// </summary>211 /// <param name="psMD"></param>212 internal void Initialize(ParameterSetSpecificMetadata psMD)213 {214 _isMandatory = psMD.IsMandatory;215 _position = psMD.Position;216 _valueFromPipeline = psMD.ValueFromPipeline;217 _valueFromPipelineByPropertyName = psMD.ValueFromPipelineByPropertyName;218 _valueFromRemainingArguments = psMD.ValueFromRemainingArguments;219 _helpMessage = psMD.HelpMessage;220 _helpMessageBaseName = psMD.HelpMessageBaseName;221 _helpMessageResourceId = psMD.HelpMessageResourceId;222 }223 224 /// <summary>225 /// Compares this instance with the supplied <paramref name="second"/>.226 /// </summary>227 /// <param name="second">228 /// An object to compare this instance with229 /// </param>230 /// <returns>231 /// true if the metadata is same. false otherwise.232 /// </returns>233 internal bool Equals(ParameterSetMetadata second)234 {235 if ((_isMandatory != second._isMandatory) ||236 (_position != second._position) ||237 (_valueFromPipeline != second._valueFromPipeline) ||238 (_valueFromPipelineByPropertyName != second._valueFromPipelineByPropertyName) ||239 (_valueFromRemainingArguments != second._valueFromRemainingArguments) ||240 (_helpMessage != second._helpMessage) ||241 (_helpMessageBaseName != second._helpMessageBaseName) ||242 (_helpMessageResourceId != second._helpMessageResourceId))243 {244 return false;245 }246 247 return true;248 }249 250 #endregion251 252 #region Efficient serialization + rehydration logic253 254 [Flags]255 internal enum ParameterFlags : uint256 {257 Mandatory = 0x01,258 ValueFromPipeline = 0x02,259 ValueFromPipelineByPropertyName = 0x04,260 ValueFromRemainingArguments = 0x08,261 }262 263 internal ParameterFlags Flags264 {265 get266 {267 ParameterFlags flags = 0;268 if (IsMandatory) { flags |= ParameterFlags.Mandatory; }269 270 if (ValueFromPipeline) { flags |= ParameterFlags.ValueFromPipeline; }271 272 if (ValueFromPipelineByPropertyName) { flags |= ParameterFlags.ValueFromPipelineByPropertyName; }273 274 if (ValueFromRemainingArguments) { flags |= ParameterFlags.ValueFromRemainingArguments; }275 276 return flags;277 }278 279 set280 {281 this.IsMandatory = ((value & ParameterFlags.Mandatory) == ParameterFlags.Mandatory);282 this.ValueFromPipeline = ((value & ParameterFlags.ValueFromPipeline) == ParameterFlags.ValueFromPipeline);283 this.ValueFromPipelineByPropertyName = ((value & ParameterFlags.ValueFromPipelineByPropertyName) == ParameterFlags.ValueFromPipelineByPropertyName);284 this.ValueFromRemainingArguments = ((value & ParameterFlags.ValueFromRemainingArguments) == ParameterFlags.ValueFromRemainingArguments);285 }286 }287 288 /// <summary>289 /// Constructor used by rehydration.290 /// </summary>291 internal ParameterSetMetadata(292 int position,293 ParameterFlags flags,294 string helpMessage)295 {296 this.Position = position;297 this.Flags = flags;298 this.HelpMessage = helpMessage;299 }300 301 #endregion302 303 #region Proxy Parameter Generation304 305 private const string MandatoryFormat = @"{0}Mandatory=$true";306 private const string PositionFormat = @"{0}Position={1}";307 private const string ValueFromPipelineFormat = @"{0}ValueFromPipeline=$true";308 private const string ValueFromPipelineByPropertyNameFormat = @"{0}ValueFromPipelineByPropertyName=$true";309 private const string ValueFromRemainingArgumentsFormat = @"{0}ValueFromRemainingArguments=$true";310 private const string HelpMessageFormat = @"{0}HelpMessage='{1}'";311 312 /// <summary>313 /// </summary>314 /// <returns></returns>315 internal string GetProxyParameterData()316 {317 Text.StringBuilder result = new System.Text.StringBuilder();318 string prefix = string.Empty;319 320 if (_isMandatory)321 {322 result.AppendFormat(CultureInfo.InvariantCulture, MandatoryFormat, prefix);323 prefix = ", ";324 }325 326 if (_position != Int32.MinValue)327 {328 result.AppendFormat(CultureInfo.InvariantCulture, PositionFormat, prefix, _position);329 prefix = ", ";330 }331 332 if (_valueFromPipeline)333 {334 result.AppendFormat(CultureInfo.InvariantCulture, ValueFromPipelineFormat, prefix);335 prefix = ", ";336 }337 338 if (_valueFromPipelineByPropertyName)339 {340 result.AppendFormat(CultureInfo.InvariantCulture, ValueFromPipelineByPropertyNameFormat, prefix);341 prefix = ", ";342 }343 344 if (_valueFromRemainingArguments)345 {346 result.AppendFormat(CultureInfo.InvariantCulture, ValueFromRemainingArgumentsFormat, prefix);347 prefix = ", ";348 }349 350 if (!string.IsNullOrEmpty(_helpMessage))351 {352 result.AppendFormat(353 CultureInfo.InvariantCulture,354 HelpMessageFormat,355 prefix,356 CodeGeneration.EscapeSingleQuotedStringContent(_helpMessage));357 prefix = ", ";358 }359 360 return result.ToString();361 }362 363 #endregion364 }365 366 /// <summary>367 /// This class represents the compiled metadata for a parameter.368 /// </summary>369 public sealed class ParameterMetadata370 {371 #region Private Data372 373 private string _name;374 private Type _parameterType;375 private bool _isDynamic;376 private Dictionary<string, ParameterSetMetadata> _parameterSets;377 private Collection<string> _aliases;378 private Collection<Attribute> _attributes;379 380 #endregion381 382 #region Constructor383 384 /// <summary>385 /// Constructs a ParameterMetadata instance.386 /// </summary>387 /// <param name="name">388 /// Name of the parameter.389 /// </param>390 /// <exception cref="ArgumentNullException">391 /// name is null.392 /// </exception>393 public ParameterMetadata(string name)394 : this(name, null)395 {396 }397 398 /// <summary>399 /// Constructs a ParameterMetadata instance.400 /// </summary>401 /// <param name="name">402 /// Name of the parameter.403 /// </param>404 /// <param name="parameterType">405 /// Type of the parameter.406 /// </param>407 /// <exception cref="ArgumentNullException">408 /// name is null.409 /// </exception>410 public ParameterMetadata(string name, Type parameterType)411 {412 if (string.IsNullOrEmpty(name))413 {414 throw PSTraceSource.NewArgumentNullException(nameof(name));415 }416 417 _name = name;418 _parameterType = parameterType;419 420 _attributes = new Collection<Attribute>();421 _aliases = new Collection<string>();422 _parameterSets = new Dictionary<string, ParameterSetMetadata>();423 }424 425 /// <summary>426 /// A copy constructor that creates a deep copy of the <paramref name="other"/> ParameterMetadata object.427 /// Instances of Attribute and Type classes are copied by reference.428 /// </summary>429 /// <param name="other">Object to copy.</param>430 public ParameterMetadata(ParameterMetadata other)431 {432 if (other == null)433 {434 throw PSTraceSource.NewArgumentNullException(nameof(other));435 }436 437 _isDynamic = other._isDynamic;438 _name = other._name;439 _parameterType = other._parameterType;440 441 // deep copy442 _aliases = new Collection<string>(new List<string>(other._aliases.Count));443 foreach (string alias in other._aliases)444 {445 _aliases.Add(alias);446 }447 448 // deep copy of the collection, collection items (Attributes) copied by reference449 if (other._attributes == null)450 {451 _attributes = null;452 }453 else454 {455 _attributes = new Collection<Attribute>(new List<Attribute>(other._attributes.Count));456 foreach (Attribute attribute in other._attributes)457 {458 _attributes.Add(attribute);459 }460 }461 462 // deep copy463 _parameterSets = null;464 if (other._parameterSets == null)465 {466 _parameterSets = null;467 }468 else469 {470 _parameterSets = new Dictionary<string, ParameterSetMetadata>(other._parameterSets.Count);471 foreach (KeyValuePair<string, ParameterSetMetadata> entry in other._parameterSets)472 {473 _parameterSets.Add(entry.Key, new ParameterSetMetadata(entry.Value));474 }475 }476 }477 478 /// <summary>479 /// An internal constructor which constructs a ParameterMetadata object480 /// from compiled command parameter metadata. ParameterMetadata481 /// is a proxy written on top of CompiledCommandParameter.482 /// </summary>483 /// <param name="cmdParameterMD">484 /// Internal CompiledCommandParameter metadata485 /// </param>486 internal ParameterMetadata(CompiledCommandParameter cmdParameterMD)487 {488 Dbg.Assert(cmdParameterMD != null,489 "CompiledCommandParameter cannot be null");490 491 Initialize(cmdParameterMD);492 }493 494 /// <summary>495 /// Constructor used by implicit remoting.496 /// </summary>497 internal ParameterMetadata(498 Collection<string> aliases,499 bool isDynamic,500 string name,501 Dictionary<string, ParameterSetMetadata> parameterSets,502 Type parameterType)503 {504 _aliases = aliases;505 _isDynamic = isDynamic;506 _name = name;507 _parameterSets = parameterSets;508 _parameterType = parameterType;509 _attributes = new Collection<Attribute>();510 }511 512 #endregion513 514 #region Public Methods/Properties515 516 /// <summary>517 /// Gets the name of the parameter.518 /// </summary>519 public string Name520 {521 get522 {523 return _name;524 }525 526 set527 {528 if (string.IsNullOrEmpty(value))529 {530 throw PSTraceSource.NewArgumentNullException("Name");531 }532 533 _name = value;534 }535 }536 537 /// <summary>538 /// Gets the Type information of the Parameter.539 /// </summary>540 public Type ParameterType541 {542 get543 {544 return _parameterType;545 }546 547 set548 {549 _parameterType = value;550 }551 }552 553 /// <summary>554 /// Gets the ParameterSets metadata that this parameter belongs to.555 /// </summary>556 public Dictionary<string, ParameterSetMetadata> ParameterSets557 {558 get559 {560 return _parameterSets;561 }562 }563 564 /// <summary>565 /// Specifies if the parameter is Dynamic.566 /// </summary>567 public bool IsDynamic568 {569 get { return _isDynamic; }570 571 set { _isDynamic = value; }572 }573 /// <summary>574 /// Specifies the alias names for this parameter.575 /// </summary>576 public Collection<string> Aliases577 {578 get579 {580 return _aliases;581 }582 }583 584 /// <summary>585 /// A collection of the attributes found on the member.586 /// </summary>587 public Collection<Attribute> Attributes588 {589 get590 {591 return _attributes;592 }593 }594 595 /// <summary>596 /// Specifies if the parameter is a SwitchParameter.597 /// </summary>598 public bool SwitchParameter599 {600 get601 {602 if (_parameterType != null)603 {604 return _parameterType.Equals(typeof(SwitchParameter));605 }606 607 return false;608 }609 }610 611 /// <summary>612 /// Gets a dictionary of parameter metadata for the supplied <paramref name="type"/>.613 /// </summary>614 /// <param name="type">615 /// CLR Type for which the parameter metadata is constructed.616 /// </param>617 /// <returns>618 /// A Dictionary of ParameterMetadata keyed by parameter name.619 /// null if no parameter metadata is found.620 /// </returns>621 /// <exception cref="ArgumentNullException">622 /// type is null.623 /// </exception>624 public static Dictionary<string, ParameterMetadata> GetParameterMetadata(Type type)625 {626 if (type == null)627 {628 throw PSTraceSource.NewArgumentNullException(nameof(type));629 }630 631 CommandMetadata cmdMetaData = new CommandMetadata(type);632 Dictionary<string, ParameterMetadata> result = cmdMetaData.Parameters;633 // early GC.634 cmdMetaData = null;635 return result;636 }637 638 #endregion639 640 #region Internal Methods/Properties641 642 /// <summary>643 /// </summary>644 /// <param name="compiledParameterMD"></param>645 internal void Initialize(CompiledCommandParameter compiledParameterMD)646 {647 _name = compiledParameterMD.Name;648 _parameterType = compiledParameterMD.Type;649 _isDynamic = compiledParameterMD.IsDynamic;650 651 // Create parameter set metadata652 _parameterSets = new Dictionary<string, ParameterSetMetadata>(StringComparer.OrdinalIgnoreCase);653 foreach (string key in compiledParameterMD.ParameterSetData.Keys)654 {655 ParameterSetSpecificMetadata pMD = compiledParameterMD.ParameterSetData[key];656 _parameterSets.Add(key, new ParameterSetMetadata(pMD));657 }658 659 // Create aliases for this parameter660 _aliases = new Collection<string>();661 foreach (string alias in compiledParameterMD.Aliases)662 {663 _aliases.Add(alias);664 }665 666 // Create attributes for this parameter667 _attributes = new Collection<Attribute>();668 foreach (var attrib in compiledParameterMD.CompiledAttributes)669 {670 _attributes.Add(attrib);671 }672 }673 674 /// <summary>675 /// </summary>676 /// <param name="cmdParameterMetadata"></param>677 /// <returns></returns>678 internal static Dictionary<string, ParameterMetadata> GetParameterMetadata(MergedCommandParameterMetadata679 cmdParameterMetadata)680 {681 Dbg.Assert(cmdParameterMetadata != null, "cmdParameterMetadata cannot be null");682 683 Dictionary<string, ParameterMetadata> result = new Dictionary<string, ParameterMetadata>(StringComparer.OrdinalIgnoreCase);684 685 foreach (var keyValuePair in cmdParameterMetadata.BindableParameters)686 {687 var key = keyValuePair.Key;688 var mergedCompiledPMD = keyValuePair.Value;689 ParameterMetadata parameterMetaData = new ParameterMetadata(mergedCompiledPMD.Parameter);690 result.Add(key, parameterMetaData);691 }692 693 return result;694 }695 696 internal bool IsMatchingType(PSTypeName psTypeName)697 {698 Type dotNetType = psTypeName.Type;699 if (dotNetType != null)700 {701 // ConstrainedLanguage note - This conversion is analyzed, but actually invoked via regular conversion.702 bool parameterAcceptsObjects =703 ((int)(LanguagePrimitives.FigureConversion(typeof(object), this.ParameterType).Rank)) >=704 (int)(ConversionRank.AssignableS2A);705 if (dotNetType.Equals(typeof(object)))706 {707 return parameterAcceptsObjects;708 }709 710 if (parameterAcceptsObjects)711 {712 return (psTypeName.Type != null) && (psTypeName.Type.Equals(typeof(object)));713 }714 715 // ConstrainedLanguage note - This conversion is analyzed, but actually invoked via regular conversion.716 var conversionData = LanguagePrimitives.FigureConversion(dotNetType, this.ParameterType);717 if (conversionData != null)718 {719 if ((int)(conversionData.Rank) >= (int)(ConversionRank.NumericImplicitS2A))720 {721 return true;722 }723 }724 725 return false;726 }727 728 var wildcardPattern = WildcardPattern.Get(729 "*" + (psTypeName.Name ?? string.Empty),730 WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant);731 if (wildcardPattern.IsMatch(this.ParameterType.FullName))732 {733 return true;734 }735 736 if (this.ParameterType.IsArray && wildcardPattern.IsMatch((this.ParameterType.GetElementType().FullName)))737 {738 return true;739 }740 741 if (this.Attributes != null)742 {743 PSTypeNameAttribute typeNameAttribute = this.Attributes.OfType<PSTypeNameAttribute>().FirstOrDefault();744 if (typeNameAttribute != null && wildcardPattern.IsMatch(typeNameAttribute.PSTypeName))745 {746 return true;747 }748 }749 750 return false;751 }752 753 #endregion754 755 #region Proxy Parameter generation756 757 // The formats are prefixed with {0} to enable easy formatting.758 private const string ParameterNameFormat = @"{0}${{{1}}}";759 private const string ParameterTypeFormat = @"{0}[{1}]";760 private const string ParameterSetNameFormat = "ParameterSetName='{0}'";761 private const string AliasesFormat = @"{0}[Alias({1})]";762 private const string ValidateLengthFormat = @"{0}[ValidateLength({1}, {2})]";763 private const string ValidateRangeRangeKindFormat = @"{0}[ValidateRange([System.Management.Automation.ValidateRangeKind]::{1})]";764 private const string ValidateRangeEnumFormat = @"{0}[ValidateRange([{3}]::{1}, [{3}]::{2})]";765 private const string ValidateRangeFloatFormat = @"{0}[ValidateRange({1:R}, {2:R})]";766 private const string ValidateRangeFormat = @"{0}[ValidateRange({1}, {2})]";767 private const string ValidatePatternFormat = "{0}[ValidatePattern('{1}')]";768 private const string ValidateScriptFormat = @"{0}[ValidateScript({{ {1} }})]";769 private const string ValidateCountFormat = @"{0}[ValidateCount({1}, {2})]";770 private const string ValidateSetFormat = @"{0}[ValidateSet({1})]";771 private const string ValidateNotNullFormat = @"{0}[ValidateNotNull()]";772 private const string ValidateNotNullOrEmptyFormat = @"{0}[ValidateNotNullOrEmpty()]";773 private const string ValidateNotNullOrWhiteSpaceFormat = @"{0}[ValidateNotNullOrWhiteSpace()]";774 private const string AllowNullFormat = @"{0}[AllowNull()]";775 private const string AllowEmptyStringFormat = @"{0}[AllowEmptyString()]";776 private const string AllowEmptyCollectionFormat = @"{0}[AllowEmptyCollection()]";777 private const string PSTypeNameFormat = @"{0}[PSTypeName('{1}')]";778 private const string ObsoleteFormat = @"{0}[Obsolete({1})]";779 private const string CredentialAttributeFormat = @"{0}[System.Management.Automation.CredentialAttribute()]";780 781 /// <summary>782 /// </summary>783 /// <param name="prefix">784 /// prefix that is added to every new-line. Used for tabbing content.785 /// </param>786 /// <param name="paramNameOverride">787 /// The paramNameOverride is used as the parameter name if it is not null or empty.788 /// </param>789 /// <param name="isProxyForCmdlet">790 /// The parameter is for a cmdlet and requires a Parameter attribute.791 /// </param>792 /// <returns></returns>793 internal string GetProxyParameterData(string prefix, string paramNameOverride, bool isProxyForCmdlet)794 {795 Text.StringBuilder result = new System.Text.StringBuilder();796 797 if (_parameterSets != null && isProxyForCmdlet)798 {799 foreach (var pair in _parameterSets)800 {801 string parameterSetName = pair.Key;802 ParameterSetMetadata parameterSet = pair.Value;803 string paramSetData = parameterSet.GetProxyParameterData();804 if (!string.IsNullOrEmpty(paramSetData) || !parameterSetName.Equals(ParameterAttribute.AllParameterSets))805 {806 string separator = string.Empty;807 result.Append(prefix);808 result.Append("[Parameter(");809 if (!parameterSetName.Equals(ParameterAttribute.AllParameterSets))810 {811 result.AppendFormat(812 CultureInfo.InvariantCulture,813 ParameterSetNameFormat,814 CodeGeneration.EscapeSingleQuotedStringContent(parameterSetName));815 separator = ", ";816 }817 818 if (!string.IsNullOrEmpty(paramSetData))819 {820 result.Append(separator);821 result.Append(paramSetData);822 }823 824 result.Append(")]");825 }826 }827 }828 829 if ((_aliases != null) && (_aliases.Count > 0))830 {831 Text.StringBuilder aliasesData = new System.Text.StringBuilder();832 string comma = string.Empty; // comma is not need for the first element833 834 foreach (string alias in _aliases)835 {836 aliasesData.AppendFormat(837 CultureInfo.InvariantCulture,838 "{0}'{1}'",839 comma,840 CodeGeneration.EscapeSingleQuotedStringContent(alias));841 comma = ",";842 }843 844 result.AppendFormat(CultureInfo.InvariantCulture, AliasesFormat, prefix, aliasesData.ToString());845 }846 847 if ((_attributes != null) && (_attributes.Count > 0))848 {849 foreach (Attribute attrib in _attributes)850 {851 string attribData = GetProxyAttributeData(attrib, prefix);852 if (!string.IsNullOrEmpty(attribData))853 {854 result.Append(attribData);855 }856 }857 }858 859 if (SwitchParameter)860 {861 result.AppendFormat(CultureInfo.InvariantCulture, ParameterTypeFormat, prefix, "switch");862 }863 else if (_parameterType != null)864 {865 result.AppendFormat(CultureInfo.InvariantCulture, ParameterTypeFormat, prefix, ToStringCodeMethods.Type(_parameterType));866 }867 868 /* 1. CredentialAttribute needs to go after the type869 * 2. To avoid risk, I don't want to move other attributes to go here / after the type */870 CredentialAttribute credentialAttrib = _attributes.OfType<CredentialAttribute>().FirstOrDefault();871 if (credentialAttrib != null)872 {873 string attribData = string.Format(CultureInfo.InvariantCulture, CredentialAttributeFormat, prefix);874 if (!string.IsNullOrEmpty(attribData))875 {876 result.Append(attribData);877 }878 }879 880 result.AppendFormat(881 CultureInfo.InvariantCulture,882 ParameterNameFormat,883 prefix,884 CodeGeneration.EscapeVariableName(string.IsNullOrEmpty(paramNameOverride) ? _name : paramNameOverride));885 return result.ToString();886 }887 888 /// <summary>889 /// Generates proxy data for attributes like ValidateLength, ValidateRange etc.890 /// </summary>891 /// <param name="attrib">892 /// Attribute to process.893 /// </param>894 /// <param name="prefix">895 /// Prefix string to add.896 /// </param>897 /// <returns>898 /// Attribute's proxy string.899 /// </returns>900 private static string GetProxyAttributeData(Attribute attrib, string prefix)901 {902 string result;903 904 ValidateLengthAttribute validLengthAttrib = attrib as ValidateLengthAttribute;905 if (validLengthAttrib != null)906 {907 result = string.Format(908 CultureInfo.InvariantCulture,909 ValidateLengthFormat, prefix,910 validLengthAttrib.MinLength,911 validLengthAttrib.MaxLength);912 return result;913 }914 915 ValidateRangeAttribute validRangeAttrib = attrib as ValidateRangeAttribute;916 if (validRangeAttrib != null)917 {918 if (validRangeAttrib.RangeKind.HasValue)919 {920 result = string.Format(921 CultureInfo.InvariantCulture,922 ValidateRangeRangeKindFormat,923 prefix,924 validRangeAttrib.RangeKind.ToString());925 return result;926 }927 else928 {929 Type rangeType = validRangeAttrib.MinRange.GetType();930 string format;931 932 if (rangeType == typeof(float) || rangeType == typeof(double))933 {934 format = ValidateRangeFloatFormat;935 }936 else if (rangeType.IsEnum)937 {938 format = ValidateRangeEnumFormat;939 }940 else941 {942 format = ValidateRangeFormat;943 }944 945 result = string.Format(946 CultureInfo.InvariantCulture,947 format,948 prefix,949 validRangeAttrib.MinRange,950 validRangeAttrib.MaxRange,951 rangeType.FullName);952 return result;953 }954 }955 956 AllowNullAttribute allowNullAttrib = attrib as AllowNullAttribute;957 if (allowNullAttrib != null)958 {959 result = string.Format(CultureInfo.InvariantCulture,960 AllowNullFormat, prefix);961 return result;962 }963 964 AllowEmptyStringAttribute allowEmptyStringAttrib = attrib as AllowEmptyStringAttribute;965 if (allowEmptyStringAttrib != null)966 {967 result = string.Format(CultureInfo.InvariantCulture,968 AllowEmptyStringFormat, prefix);969 return result;970 }971 972 AllowEmptyCollectionAttribute allowEmptyColAttrib = attrib as AllowEmptyCollectionAttribute;973 if (allowEmptyColAttrib != null)974 {975 result = string.Format(CultureInfo.InvariantCulture,976 AllowEmptyCollectionFormat, prefix);977 return result;978 }979 980 ValidatePatternAttribute patternAttrib = attrib as ValidatePatternAttribute;981 if (patternAttrib != null)982 {983 /* TODO: Validate Pattern dont support Options in ScriptCmdletText.984 StringBuilder regexOps = new System.Text.StringBuilder();985 string or = string.Empty;986 string[] regexOptionEnumValues = Enum.GetNames<System.Text.RegularExpressions.RegexOptions>();987 988 foreach (string regexOption in regexOptionEnumValues)989 {990 System.Text.RegularExpressions.RegexOptions option = (System.Text.RegularExpressions.RegexOptions) Enum.Parse(991 typeof(System.Text.RegularExpressions.RegexOptions),992 regexOption, true);993 if ((option & patternAttrib.Options) == option)994 {995 tracer.WriteLine("Regex option {0} found", regexOption);996 regexOps.AppendFormat(CultureInfo.InvariantCulture,997 "{0}[System.Text.RegularExpressions.RegexOptions]::{1}", or,998 option.ToString()999 );1000 or = "|";1001 }1002 }*/1003 1004 result = string.Format(CultureInfo.InvariantCulture,1005 ValidatePatternFormat, prefix,1006 CodeGeneration.EscapeSingleQuotedStringContent(patternAttrib.RegexPattern)1007 /*,regexOps.ToString()*/);1008 return result;1009 }1010 1011 ValidateCountAttribute countAttrib = attrib as ValidateCountAttribute;1012 if (countAttrib != null)1013 {1014 result = string.Format(CultureInfo.InvariantCulture,1015 ValidateCountFormat, prefix, countAttrib.MinLength, countAttrib.MaxLength);1016 return result;1017 }1018 1019 ValidateNotNullAttribute notNullAttrib = attrib as ValidateNotNullAttribute;1020 if (notNullAttrib != null)1021 {1022 result = string.Format(CultureInfo.InvariantCulture,1023 ValidateNotNullFormat, prefix);1024 return result;1025 }1026 1027 ValidateNotNullOrEmptyAttribute notNullEmptyAttrib = attrib as ValidateNotNullOrEmptyAttribute;1028 if (notNullEmptyAttrib != null)1029 {1030 result = string.Format(CultureInfo.InvariantCulture,1031 ValidateNotNullOrEmptyFormat, prefix);1032 return result;1033 }1034 1035 ValidateNotNullOrWhiteSpaceAttribute notNullWhiteSpaceAttrib = attrib as ValidateNotNullOrWhiteSpaceAttribute;1036 if (notNullWhiteSpaceAttrib != null)1037 {1038 result = string.Format(CultureInfo.InvariantCulture,1039 ValidateNotNullOrWhiteSpaceFormat, prefix);1040 return result;1041 }1042 1043 ValidateSetAttribute setAttrib = attrib as ValidateSetAttribute;1044 if (setAttrib != null)1045 {1046 Text.StringBuilder values = new System.Text.StringBuilder();1047 string comma = string.Empty;1048 foreach (string validValue in setAttrib.ValidValues)1049 {1050 values.AppendFormat(1051 CultureInfo.InvariantCulture,1052 "{0}'{1}'",1053 comma,1054 CodeGeneration.EscapeSingleQuotedStringContent(validValue));1055 comma = ",";1056 }1057 1058 result = string.Format(CultureInfo.InvariantCulture,1059 ValidateSetFormat, prefix, values.ToString()/*, setAttrib.IgnoreCase*/);1060 return result;1061 }1062 1063 ValidateScriptAttribute scriptAttrib = attrib as ValidateScriptAttribute;1064 if (scriptAttrib != null)1065 {1066 // Talked with others and I think it is okay to use *unescaped* value from sb.ToString()1067 // 1. implicit remoting is not bringing validation scripts across1068 // 2. other places in code also assume that contents of a script block can be parsed1069 // without escaping1070 result = string.Format(CultureInfo.InvariantCulture,1071 ValidateScriptFormat, prefix, scriptAttrib.ScriptBlock.ToString());1072 return result;1073 }1074 1075 PSTypeNameAttribute psTypeNameAttrib = attrib as PSTypeNameAttribute;1076 if (psTypeNameAttrib != null)1077 {1078 result = string.Format(1079 CultureInfo.InvariantCulture,1080 PSTypeNameFormat,1081 prefix,1082 CodeGeneration.EscapeSingleQuotedStringContent(psTypeNameAttrib.PSTypeName));1083 return result;1084 }1085 1086 ObsoleteAttribute obsoleteAttrib = attrib as ObsoleteAttribute;1087 if (obsoleteAttrib != null)1088 {1089 string parameters = string.Empty;1090 if (obsoleteAttrib.IsError)1091 {1092 string message = "'" + CodeGeneration.EscapeSingleQuotedStringContent(obsoleteAttrib.Message) + "'";1093 parameters = message + ", $true";1094 }1095 else if (obsoleteAttrib.Message != null)1096 {1097 parameters = "'" + CodeGeneration.EscapeSingleQuotedStringContent(obsoleteAttrib.Message) + "'";1098 }1099 1100 result = string.Format(1101 CultureInfo.InvariantCulture,1102 ObsoleteFormat,1103 prefix,1104 parameters);1105 return result;1106 }1107 1108 return null;1109 }1110 1111 #endregion1112 }1113 1114 /// <summary>1115 /// The metadata associated with a bindable type.1116 /// </summary>1117 internal class InternalParameterMetadata1118 {1119 #region ctor1120 1121 /// <summary>1122 /// Gets or constructs an instance of the InternalParameterMetadata for the specified runtime-defined parameters.1123 /// </summary>1124 /// <param name="runtimeDefinedParameters">1125 /// The runtime-defined parameter collection that describes the parameters and their metadata.1126 /// </param>1127 /// <param name="processingDynamicParameters">1128 /// True if dynamic parameters are being processed, or false otherwise.1129 /// </param>1130 /// <param name="checkNames">1131 /// Check for reserved parameter names.1132 /// </param>1133 /// <returns>1134 /// An instance of the TypeMetadata for the specified runtime-defined parameters. The metadata1135 /// is always constructed on demand and never cached.1136 /// </returns>1137 /// <exception cref="ArgumentNullException">1138 /// If <paramref name="runtimeDefinedParameters"/> is null.1139 /// </exception>1140 /// <exception cref="MetadataException">1141 /// If a parameter defines the same parameter-set name multiple times.1142 /// If the attributes could not be read from a property or field.1143 /// </exception>1144 internal static InternalParameterMetadata Get(RuntimeDefinedParameterDictionary runtimeDefinedParameters,1145 bool processingDynamicParameters,1146 bool checkNames)1147 {1148 if (runtimeDefinedParameters == null)1149 {1150 throw PSTraceSource.NewArgumentNullException("runtimeDefinedParameter");1151 }1152 1153 return new InternalParameterMetadata(runtimeDefinedParameters, processingDynamicParameters, checkNames);1154 }1155 1156 /// <summary>1157 /// Gets or constructs an instance of the InternalParameterMetadata for the specified type.1158 /// </summary>1159 /// <param name="type">1160 /// The type to get the metadata for.1161 /// </param>1162 /// <param name="context">1163 /// The current engine context.1164 /// </param>1165 /// <param name="processingDynamicParameters">1166 /// True if dynamic parameters are being processed, or false otherwise.1167 /// </param>1168 /// <returns>1169 /// An instance of the TypeMetadata for the specified type. The metadata may get1170 /// constructed on-demand or may be retrieved from the cache.1171 /// </returns>1172 /// <exception cref="ArgumentNullException">1173 /// If <paramref name="type"/> is null.1174 /// </exception>1175 /// <exception cref="MetadataException">1176 /// If a parameter defines the same parameter-set name multiple times.1177 /// If the attributes could not be read from a property or field.1178 /// </exception>1179 internal static InternalParameterMetadata Get(Type type, ExecutionContext context, bool processingDynamicParameters)1180 {1181 if (type == null)1182 {1183 throw PSTraceSource.NewArgumentNullException(nameof(type));1184 }1185 1186 InternalParameterMetadata result;1187 if (context == null || !s_parameterMetadataCache.TryGetValue(type.AssemblyQualifiedName, out result))1188 {1189 result = new InternalParameterMetadata(type, processingDynamicParameters);1190 1191 if (context != null)1192 {1193 s_parameterMetadataCache.TryAdd(type.AssemblyQualifiedName, result);1194 }1195 }1196 1197 return result;1198 }1199 1200 //