/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Management.Automation.Internal;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation.Language;
using System.Runtime.CompilerServices;
namespace System.Management.Automation.Internal
{
///
/// Serves as the base class for Metadata attributes.
///
///
/// PSSnapins may not create custom attributes derived directly from
/// ,
/// since it has no public constructor. Only the public subclasses
/// and
///
/// are available.
///
///
///
[AttributeUsage(AttributeTargets.All)]
public abstract class CmdletMetadataAttribute : Attribute
{
///
/// Default constructor
///
internal CmdletMetadataAttribute()
{
}
}
///
/// Serves as the base class for Metadata attributes that serve as guidance to the parser and parameter binder.
///
///
/// PSSnapins may not create custom attributes derived
/// ,
/// since it has no public constructor. Only the sealed public subclasses
/// and
///
/// are available.
///
///
///
[AttributeUsage(AttributeTargets.All)]
public abstract class ParsingBaseAttribute : CmdletMetadataAttribute
{
///
/// Constructor with no parameters
///
internal ParsingBaseAttribute()
{
}
}
}
namespace System.Management.Automation
{
#region Base Metadata Classes
///
/// Serves as the base class for Validate attributes that validate parameter arguments.
///
///
/// Argument validation attributes can be attached to
/// and
/// parameters to ensure that the Cmdlet or CmdletProvider will not
/// be invoked with invalid values of the parameter. Existing
/// validation attributes include ,
/// ,
/// ,
/// ,
/// ,
/// ,
/// , and
/// .
///
/// PSSnapins wishing to create custom argument validation attributes
/// should derive from
///
/// and override the
///
/// abstract method, after which they can apply the
/// attribute to their parameters.
///
/// validates the argument
/// as a whole. If the argument value is potentially an enumeration,
/// you can derive from
/// which will take care of unrolling the enumeration
/// and validate each element individually.
///
/// It is also recommended to override
/// to return a readable string
/// similar to the attribute declaration, for example
/// "[ValidateRangeAttribute(5,10)]".
///
/// If this attribute is applied to a string parameter, the string command argument will be validated.
/// If this attribute is applied to a string[] parameter, the string[] command argument will be validated.
///
///
///
///
///
///
///
///
///
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public abstract class ValidateArgumentsAttribute : CmdletMetadataAttribute
{
///
/// Overridden by subclasses to implement the validation of the parameter arguments
///
/// argument value to validate
///
/// The engine APIs for the context under which the prerequisite is being
/// evaluated.
///
///
/// Validate that the value of is valid,
/// and throw
/// if it is invalid.
///
/// should be thrown for any validation failure
protected abstract void Validate(object arguments, EngineIntrinsics engineIntrinsics);
///
/// Method that the command processor calls for data validate processing
///
/// object to validate
///
/// The engine APIs for the context under which the prerequisite is being
/// evaluated.
///
///
/// bool true if the validate succeeded
///
/// Whenever any exception occurs during data validate.
/// All the system exceptions are wrapped in ValidationMetadataException
///
/// for invalid arguments
internal void InternalValidate(object o, EngineIntrinsics engineIntrinsics)
{
Validate(o, engineIntrinsics);
}
///
/// Initializes a new instance of a class derived from ValidateArgumentsAttribute
///
protected ValidateArgumentsAttribute()
{
}
}
///
/// A variant of which
/// unrolls enumeration values and validates each element
/// individually.
///
///
/// is like
/// , except that if
/// the argument value is an enumeration,
/// will unroll
/// the enumeration and validate each item individually.
///
/// Existing enumerated validation attributes include
/// ,
/// ,
/// , and
/// .
///
/// PSSnapins wishing to create custom enumerated argument validation attributes
/// should derive from
///
/// and override the
///
/// abstract method, after which they can apply the
/// attribute to their parameters.
///
/// It is also recommended to override
/// to return a readable string
/// similar to the attribute declaration, for example
/// "[ValidateRangeAttribute(5,10)]".
///
/// If this attribute is applied to a string parameter, the string command argument will be validated.
/// If this attribute is applied to a string[] parameter, each string command argument will be validated.
///
///
///
///
///
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public abstract class ValidateEnumeratedArgumentsAttribute : ValidateArgumentsAttribute
{
///
/// Initializes a new instance of a class derived from ValidateEnumeratedArgumentsAttribute
///
protected ValidateEnumeratedArgumentsAttribute() : base()
{
}
///
/// Overridden by subclasses to implement the validation of each parameter argument
///
///
/// Validate that the value of
/// is valid, and throw
///
/// if it is invalid.
///
/// one of the parameter arguments
/// should be thrown for any validation failure
protected abstract void ValidateElement(object element);
///
/// Calls ValidateElement in each element in the enumeration argument value.
///
/// object to validate
///
/// The engine APIs for the context under which the prerequisite is being
/// evaluated.
///
///
/// PSSnapins should override instead.
///
/// should be thrown for any validation failure
protected sealed override void Validate(object arguments, EngineIntrinsics engineIntrinsics)
{
if (arguments == null || arguments == AutomationNull.Value)
{
throw new ValidationMetadataException(
"ArgumentIsEmpty",
null,
Metadata.ValidateNotNullOrEmptyCollectionFailure);
}
var enumerator = _getEnumeratorSite.Target.Invoke(_getEnumeratorSite, arguments);
if (enumerator == null)
{
ValidateElement(arguments);
return;
}
// arguments is IEnumerator
while (enumerator.MoveNext())
{
ValidateElement(enumerator.Current);
}
enumerator.Reset();
}
private readonly CallSite> _getEnumeratorSite =
CallSite>.Create(PSEnumerableBinder.Get());
}
#endregion Base Metadata Classes
#region Misc Attributes
///
/// To specify RunAs behavior for the class
/// ///
public enum DSCResourceRunAsCredential
{
/// Default is same as optional.
Default,
///
/// PsDscRunAsCredential can not be used for this DSC Resource
///
NotSupported,
///
/// PsDscRunAsCredential is mandatory for resource
///
Mandatory,
///
/// PsDscRunAsCredential can or can not be specified
///
Optional = Default,
}
///
/// Indicates the class defines a DSC resource.
///
[AttributeUsage(AttributeTargets.Class)]
public class DscResourceAttribute : CmdletMetadataAttribute
{
///
/// To specify RunAs Behavior for the resource.
///
public DSCResourceRunAsCredential RunAsCredential { get; set; }
}
///
/// When specified on a property or field of a DSC Resource, the property
/// can or must be specified in a configuration, unless it is marked
/// , in which case it is
/// returned by the Get() method of the resource.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class DscPropertyAttribute : CmdletMetadataAttribute
{
///
/// Indicates the property is a required key property for a DSC resource.
///
public bool Key { get; set; }
///
/// Indicates the property is a required property for a DSC resource.
///
public bool Mandatory { get; set; }
///
/// Indicates the property is not a parameter to the DSC resource, but the
/// property will contain a value after the Get() method of the resource is called.
///
public bool NotConfigurable { get; set; }
}
///
/// Indication the configuration is for local configuration manager, also known as meta configuration.
///
[AttributeUsage(AttributeTargets.Class)]
public class DscLocalConfigurationManagerAttribute : CmdletMetadataAttribute
{
}
///
/// Contains information about a cmdlet's metadata.
///
[AttributeUsage(AttributeTargets.Class)]
public abstract class CmdletCommonMetadataAttribute : CmdletMetadataAttribute
{
///
/// Gets and sets the cmdlet default parameter set
///
public string DefaultParameterSetName { get; set; }
///
/// Gets and sets a Boolean value that indicates the Cmdlet supports ShouldProcess. By default
/// the value is false, meaning the cmdlet doesn't support ShouldProcess.
///
public bool SupportsShouldProcess { get; set; } = false;
///
/// Gets and sets a Boolean value that indicates the Cmdlet supports Paging. By default
/// the value is false, meaning the cmdlet doesn't support Paging.
///
public bool SupportsPaging { get; set; } = false;
///
/// Gets and sets a Boolean value that indicates the Cmdlet supports Transactions. By default
/// the value is false, meaning the cmdlet doesn't support Transactions.
///
public bool SupportsTransactions
{
get { return _supportsTransactions; }
set
{
#if !CORECLR
_supportsTransactions = value;
#else
// Disable 'SupportsTransactions' in CoreCLR
// No transaction supported on CSS due to the lack of System.Transactions namespace
_supportsTransactions = false;
#endif
}
}
private bool _supportsTransactions = false;
///
/// Gets and sets a ConfirmImpact value that indicates
/// the "destructiveness" of the operation and when it
/// should be confirmed. This should only be used when
/// SupportsShouldProcess is specified.
///
public ConfirmImpact ConfirmImpact { get; set; } = ConfirmImpact.Medium;
///
/// Gets and sets a HelpUri value that indicates
/// the location of online help. This is used by
/// Get-Help to retrieve help content when -Online
/// is specified.
///
[SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]
public string HelpUri { get; set; } = String.Empty;
///
/// Gets and sets the RemotingBehavior value that declares how this cmdlet should interact
/// with ambient remoting.
///
public RemotingCapability RemotingCapability { get; set; } = RemotingCapability.PowerShell;
}
///
/// Identifies a class as a cmdlet and specifies the verb and noun identifying this cmdlet.
///
[AttributeUsage(AttributeTargets.Class)]
public sealed class CmdletAttribute : CmdletCommonMetadataAttribute
{
///
/// Gets the cmdlet noun
///
public string NounName { get; }
///
/// Gets the cmdlet verb
///
public string VerbName { get; }
///
/// Initializes a new instance of the CmdletAttribute class
///
/// verb for the command
/// noun for the command
/// for invalid arguments
public CmdletAttribute(string verbName, string nounName)
{
//NounName,VerbName have to be Non-Null strings
if (string.IsNullOrEmpty(nounName))
{
throw PSTraceSource.NewArgumentException("nounName");
}
if (string.IsNullOrEmpty(verbName))
{
throw PSTraceSource.NewArgumentException("verbName");
}
NounName = nounName;
VerbName = verbName;
}
}
///
/// Identifies PowerShell script code as behaving like a cmdlet and hence uses
/// cmdlet parameter binding instead of script parameter binding.
///
[AttributeUsage(AttributeTargets.Class)]
public class CmdletBindingAttribute : CmdletCommonMetadataAttribute
{
///
/// When true, the script will auto-generate appropriate parameter metadata to support positional
/// parameters if the script hasn't already specified multiple parameter sets or specified positions
/// explicitly via the .
///
public bool PositionalBinding { get; set; } = true;
}
///
/// OutputTypeAttribute is used to specify the type of objects output by a cmdlet
/// or script.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
[SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments")]
public sealed class OutputTypeAttribute : CmdletMetadataAttribute
{
///
/// Construct the attribute from a System.Type
///
internal OutputTypeAttribute(Type type)
{
Type = new[] { new PSTypeName(type) };
}
///
/// Construct the attribute from a type name.
///
internal OutputTypeAttribute(string typeName)
{
Type = new[] { new PSTypeName(typeName) };
}
///
/// Construct the attribute from an array of System.Type
///
/// The types output by the cmdlet
public OutputTypeAttribute(params Type[] type)
{
if (type != null && type.Length > 0)
{
Type = new PSTypeName[type.Length];
for (int i = 0; i < type.Length; i++)
{
Type[i] = new PSTypeName(type[i]);
}
}
else
{
Type = Utils.EmptyArray();
}
}
///
/// Construct the attribute from an array of names of types.
///
/// The types output by the cmdlet
public OutputTypeAttribute(params string[] type)
{
if (type != null && type.Length > 0)
{
Type = new PSTypeName[type.Length];
for (int i = 0; i < type.Length; i++)
{
Type[i] = new PSTypeName(type[i]);
}
}
else
{
Type = Utils.EmptyArray();
}
}
///
/// The types specified by the attribute.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
public PSTypeName[] Type { get; private set; }
///
/// Attributes implemented by a provider can use:
///
/// [OutputType(ProviderCmdlet='cmdlet', typeof(...))]
///
/// To specify the provider specific objects returned for a given cmdlet.
///
public string ProviderCmdlet { get; set; }
///
/// The list of parameter sets this OutputType specifies.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public string[] ParameterSetName
{
get { return _parameterSetName ?? (_parameterSetName = new[] { ParameterAttribute.AllParameterSets }); }
set { _parameterSetName = value; }
}
private string[] _parameterSetName;
}
///
/// This attribute is used on a dynamic assembly to mark it as one that is used to implement
/// a set of classes defined in a PowerShell script.
///
[AttributeUsage(AttributeTargets.Assembly)]
public class DynamicClassImplementationAssemblyAttribute : Attribute
{
}
#endregion Misc Attributes
#region Parsing guidelines Attributes
///
/// Declares an alternative name for a parameter
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class AliasAttribute : ParsingBaseAttribute
{
internal string[] aliasNames;
///
/// Gets the alias names passed to the constructor
///
public IList AliasNames
{
get
{
return this.aliasNames;
}
}
///
/// Initializes a new instance of the AliasAttribute class
///
/// The name for this alias
/// for invalid arguments
public AliasAttribute(params string[] aliasNames)
{
if (aliasNames == null)
{
throw PSTraceSource.NewArgumentNullException("aliasNames");
}
this.aliasNames = aliasNames;
}
}
///
/// Identifies parameters to Cmdlets
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class ParameterAttribute : ParsingBaseAttribute
{
///
/// ParameterSetName referring to all ParameterSets
///
public const string AllParameterSets = "__AllParameterSets";
///
/// Initializes a new instance of the ParameterAttribute class
///
public ParameterAttribute()
{
}
private string _parameterSetName = ParameterAttribute.AllParameterSets;
private string _helpMessage;
private string _helpMessageBaseName;
private string _helpMessageResourceId;
///
/// Gets and sets the parameter position. If not set, the parameter is named.
///
public int Position { get; set; } = int.MinValue;
///
/// Gets and sets the name of the parameter set this parameter belongs to. When
/// it is not specified ParameterAttribute.AllParameterSets is assumed.
///
public string ParameterSetName
{
get { return _parameterSetName; }
set
{
_parameterSetName = value;
if (String.IsNullOrEmpty(_parameterSetName))
{
_parameterSetName = ParameterAttribute.AllParameterSets;
}
}
}
///
/// Gets and sets a flag specifying if this parameter is Mandatory. When
/// it is not specified, false is assumed and the parameter is considered optional.
///
public bool Mandatory { get; set; } = false;
///
/// Gets and sets a flag that specifies that this parameter can take values
/// from the incoming pipeline object. When it is not specified, false is assumed.
///
public bool ValueFromPipeline { get; set; }
///
/// Gets and sets a flag that specifies that this parameter can take values from a property
/// in the incoming pipeline object with the same name as the parameter. When it
/// is not specified, false is assumed.
///
public bool ValueFromPipelineByPropertyName { get; set; }
///
/// Gets and sets a flag that specifies that the remaining command line parameters
/// should be associated with this parameter in the form of an array. When it
/// is not specified, false is assumed.
///
public bool ValueFromRemainingArguments { get; set; } = false;
///
/// Gets and sets a short description for this parameter, suitable for presentation as a tool tip.
///
/// for a null or empty value when setting
public string HelpMessage
{
get
{
return _helpMessage;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw PSTraceSource.NewArgumentException("value");
}
_helpMessage = value;
}
}
///
/// Gets and sets the base name of the resource for a help message. When this field is specified,
/// HelpMessageResourceId must also be specified.
///
/// for a null or empty value when setting
public string HelpMessageBaseName
{
get
{
return _helpMessageBaseName;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw PSTraceSource.NewArgumentException("value");
}
_helpMessageBaseName = value;
}
}
///
/// Gets and sets the Id of the resource for a help message. When this field is specified,
/// HelpMessageBaseName must also be specified.
///
/// for a null or empty value when setting
public string HelpMessageResourceId
{
get
{
return _helpMessageResourceId;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw PSTraceSource.NewArgumentException("value");
}
_helpMessageResourceId = value;
}
}
///
/// Indicates that this parameter should not be shown to the user in this like intellisense
/// This is primarily to be used in functions that are implementing the logic for dynamic keywords.
///
public bool DontShow
{
get;
set;
}
}
///
/// Specifies PSTypeName of a cmdlet or function parameter.
///
///
/// This attribute is used to restrict the type name of the parameter, when the type goes beyond the .NET type system.
/// For example one could say: [PSTypeName("System.Management.ManagementObject#root\cimv2\Win32_Process")]
/// to only allow Win32_Process objects to be bound to the parameter.
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class PSTypeNameAttribute : Attribute
{
///
///
///
public string PSTypeName { get; private set; }
///
/// Creates a new PSTypeNameAttribute
///
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
public PSTypeNameAttribute(string psTypeName)
{
if (string.IsNullOrEmpty(psTypeName))
{
throw PSTraceSource.NewArgumentException("psTypeName");
}
this.PSTypeName = psTypeName;
}
}
///
/// Specifies that a parameter supports wildcards.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class SupportsWildcardsAttribute : ParsingBaseAttribute
{
}
///
/// Specify a default value and/or help comment for a command parameter. This attribute
/// does not have any semantic meaning, it is simply an aid to tools to make it simpler
/// to know the true default value of a command parameter (which may or may not have
/// any correlation with, e.g., the backing store of the Parameter's property or field.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class PSDefaultValueAttribute : ParsingBaseAttribute
{
///
/// Specify the default value of a command parameter. The PowerShell engine does not
/// use this value in any way, it exists for other tools that want to reflect on cmdlets.
///
public object Value { get; set; }
///
/// Specify the help string for the default value of a command parameter.
///
public string Help { get; set; }
}
///
/// Specify that the member is hidden for the purposes of cmdlets like Get-Member and
/// that the member is not displayed by default by Format-* cmdlets.
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Event)]
public sealed class HiddenAttribute : ParsingBaseAttribute
{
}
#endregion Parsing guidelines Attributes
#region Data validate Attributes
///
/// Validates that the length of each parameter argument's Length falls in the range
/// specified by MinLength and MaxLength
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ValidateLengthAttribute : ValidateEnumeratedArgumentsAttribute
{
///
/// Gets the attribute's minimum length
///
public int MinLength { get; }
///
/// Gets the attribute's maximum length
///
public int MaxLength { get; }
///
/// Validates that the length of each parameter argument's Length falls in the range
/// specified by MinLength and MaxLength
///
/// object to validate
/// if is not a string
/// with length between minLength and maxLength
/// for invalid arguments
protected override void ValidateElement(object element)
{
string objectString = element as string;
if (objectString == null)
{
throw new ValidationMetadataException("ValidateLengthNotString",
null, Metadata.ValidateLengthNotString);
}
int len = objectString.Length;
if (len < MinLength)
{
throw new ValidationMetadataException("ValidateLengthMinLengthFailure",
null, Metadata.ValidateLengthMinLengthFailure,
MinLength, len);
}
if (len > MaxLength)
{
throw new ValidationMetadataException("ValidateLengthMaxLengthFailure",
null, Metadata.ValidateLengthMaxLengthFailure,
MaxLength, len);
}
}
///
/// Initializes a new instance of the ValidateLengthAttribute class
///
/// Minimum required length
/// Maximum required length
/// for invalid arguments
/// if maxLength is less than minLength
public ValidateLengthAttribute(int minLength, int maxLength) : base()
{
if (minLength < 0)
{
throw PSTraceSource.NewArgumentOutOfRangeException("minLength", minLength);
}
if (maxLength <= 0)
{
throw PSTraceSource.NewArgumentOutOfRangeException("maxLength", maxLength);
}
if (maxLength < minLength)
{
throw new ValidationMetadataException("ValidateLengthMaxLengthSmallerThanMinLength",
null, Metadata.ValidateLengthMaxLengthSmallerThanMinLength);
}
MinLength = minLength;
MaxLength = maxLength;
}
}
///
/// Validates that each parameter argument falls in the range
/// specified by MinRange and MaxRange
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ValidateRangeAttribute : ValidateEnumeratedArgumentsAttribute
{
///
/// Gets the attribute's minimum range
///
public object MinRange { get; }
private IComparable _minComparable;
///
/// Gets the attribute's maximum range
///
public object MaxRange { get; }
private IComparable _maxComparable;
///
/// The range values and the value to validate will all be converted to the promoted type.
/// If minRange and maxRange are the same type,
///
private Type _promotedType;
///
/// Validates that each parameter argument falls in the range
/// specified by MinRange and MaxRange
///
/// object to validate
///
/// Thrown if the object to be validated does not implement IComparable,
/// if the element type is not the same of MinRange, MaxRange,
/// or if the element is not between MinRange and MaxRange.
///
protected override void ValidateElement(object element)
{
if (element == null)
{
throw new ValidationMetadataException(
"ArgumentIsEmpty",
null,
Metadata.ValidateNotNullFailure);
}
var o = element as PSObject;
if (o != null)
{
element = o.BaseObject;
}
// minRange and maxRange have the same type, so we just need
// to compare to one of them
if (element.GetType() != _promotedType)
{
object resultValue;
if (LanguagePrimitives.TryConvertTo(element, _promotedType, out resultValue))
{
element = resultValue;
}
else
{
throw new ValidationMetadataException("ValidationRangeElementType",
null, Metadata.ValidateRangeElementType,
element.GetType().Name, MinRange.GetType().Name);
}
}
// They are the same type and are all IComparable, so this should not throw
if (_minComparable.CompareTo(element) > 0)
{
throw new ValidationMetadataException("ValidateRangeTooSmall",
null, Metadata.ValidateRangeSmallerThanMinRangeFailure,
element.ToString(), MinRange.ToString());
}
if (_maxComparable.CompareTo(element) < 0)
{
throw new ValidationMetadataException("ValidateRangeTooBig",
null, Metadata.ValidateRangeGreaterThanMaxRangeFailure,
element.ToString(), MaxRange.ToString());
}
}
///
/// Initializes a new instance of the ValidateRangeAttribute class
///
/// Minimum value of the range allowed.
/// Maximum value of the range allowed.
/// for invalid arguments
///
/// if maxRange has a different type than minRange
/// if maxRange is smaller than minRange
/// if maxRange, minRange are not IComparable
///
public ValidateRangeAttribute(object minRange, object maxRange) : base()
{
if (minRange == null)
{
throw PSTraceSource.NewArgumentNullException("minRange");
}
if (maxRange == null)
{
throw PSTraceSource.NewArgumentNullException("maxRange");
}
if (maxRange.GetType() != minRange.GetType())
{
bool failure = true;
_promotedType = GetCommonType(minRange.GetType(), maxRange.GetType());
if (_promotedType != null)
{
object resultValue;
if (LanguagePrimitives.TryConvertTo(minRange, _promotedType, out resultValue))
{
minRange = resultValue;
if (LanguagePrimitives.TryConvertTo(maxRange, _promotedType, out resultValue))
{
maxRange = resultValue;
failure = false;
}
}
}
if (failure)
{
throw new ValidationMetadataException("MinRangeNotTheSameTypeOfMaxRange", null,
Metadata.ValidateRangeMinRangeMaxRangeType,
minRange.GetType().Name, maxRange.GetType().Name);
}
}
else
{
_promotedType = minRange.GetType();
}
_minComparable = minRange as IComparable;
// minRange and maxRange have the same type, so we just need
// to check one of them
if (_minComparable == null)
{
throw new ValidationMetadataException("MinRangeNotIComparable", null,
Metadata.ValidateRangeNotIComparable);
}
_maxComparable = maxRange as IComparable;
Diagnostics.Assert(_maxComparable != null, "maxComparable comes from a type that is IComparable");
// Thanks to the IComparable if above this will not throw. They have the same type
// and are IComparable
if (_minComparable.CompareTo(maxRange) > 0)
{
throw new ValidationMetadataException("MaxRangeSmallerThanMinRange",
null, Metadata.ValidateRangeMaxRangeSmallerThanMinRange);
}
MinRange = minRange;
MaxRange = maxRange;
}
private static Type GetCommonType(Type minType, Type maxType)
{
Type resultType = null;
TypeCode minTypeCode = LanguagePrimitives.GetTypeCode(minType);
TypeCode maxTypeCode = LanguagePrimitives.GetTypeCode(maxType);
TypeCode opTypeCode = (int)minTypeCode >= (int)maxTypeCode ? minTypeCode : maxTypeCode;
if ((int)opTypeCode <= (int)TypeCode.Int32)
{
resultType = typeof(int);
}
else if ((int)opTypeCode <= (int)TypeCode.UInt32)
{
// If one of the operands is signed, we need to promote to double if the value is negative. We aren't
// checking the value, so we unconditionally promote to double.
resultType = LanguagePrimitives.IsSignedInteger(minTypeCode) || LanguagePrimitives.IsSignedInteger(maxTypeCode)
? typeof(double) : typeof(uint);
}
else if ((int)opTypeCode <= (int)TypeCode.Int64)
{
resultType = typeof(long);
}
else if ((int)opTypeCode <= (int)TypeCode.UInt64)
{
// If one of the operands is signed, we need to promote to double if the value is negative. We aren't
// checking the value, so we unconditionally promote to double.
resultType = LanguagePrimitives.IsSignedInteger(minTypeCode) || LanguagePrimitives.IsSignedInteger(maxTypeCode)
? typeof(double) : typeof(ulong);
}
else if (opTypeCode == TypeCode.Decimal)
{
resultType = typeof(decimal);
}
else if (opTypeCode == TypeCode.Single || opTypeCode == TypeCode.Double)
{
resultType = typeof(double);
}
return resultType;
}
}
///
/// Validates that each parameter argument matches the RegexPattern
///
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class ValidatePatternAttribute : ValidateEnumeratedArgumentsAttribute
{
///
/// Gets the Regex pattern to be used in the validation
///
public string RegexPattern { get; }
///
/// Gets or sets the Regex options to be used in the validation
///
public RegexOptions Options { set; get; } = RegexOptions.IgnoreCase;
///
/// Validates that each parameter argument matches the RegexPattern
///
/// object to validate
/// if is not a string
/// that matches the pattern
/// and for invalid arguments
protected override void ValidateElement(object element)
{
if (element == null)
{
throw new ValidationMetadataException(
"ArgumentIsEmpty",
null,
Metadata.ValidateNotNullFailure);
}
string objectString = element.ToString();
Regex regex = null;
regex = new Regex(RegexPattern, Options);
Match match = regex.Match(objectString);
if (!match.Success)
{
throw new ValidationMetadataException("ValidatePatternFailure",
null, Metadata.ValidatePatternFailure,
objectString, RegexPattern);
}
}
///
/// Initializes a new instance of the ValidatePatternAttribute class
///
/// Pattern string to match
/// for invalid arguments
public ValidatePatternAttribute(string regexPattern)
{
if (String.IsNullOrEmpty(regexPattern))
{
throw PSTraceSource.NewArgumentException("regexPattern");
}
RegexPattern = regexPattern;
}
}
///
/// Class for validating against a script block.
///
public sealed class ValidateScriptAttribute : ValidateEnumeratedArgumentsAttribute
{
///
/// Gets the scriptblock to be used in the validation
///
public ScriptBlock ScriptBlock { get; }
///
/// Validates that each parameter argument matches the scriptblock
///
/// object to validate
/// if is invalid
protected override void ValidateElement(object element)
{
if (element == null)
{
throw new ValidationMetadataException(
"ArgumentIsEmpty",
null,
Metadata.ValidateNotNullFailure);
}
object result = ScriptBlock.DoInvokeReturnAsIs(
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,
dollarUnder: LanguagePrimitives.AsPSObjectOrNull(element),
input: AutomationNull.Value,
scriptThis: AutomationNull.Value,
args: Utils.EmptyArray