diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs
index d0ae9f601..189fc6032 100644
--- a/src/System.Management.Automation/engine/Attributes.cs
+++ b/src/System.Management.Automation/engine/Attributes.cs
@@ -1113,6 +1113,17 @@ namespace System.Management.Automation
///
public RegexOptions Options { set; get; } = RegexOptions.IgnoreCase;
+ ///
+ /// Gets or sets the custom error message pattern that is displayed to the user.
+ ///
+ /// The text representation of the object being validated and the validating regex is passed as
+ /// the first and second formatting parameters to the ErrorMessage formatting pattern.
+ ///
+ /// [ValidatePattern("\s+", ErrorMessage="The text '{0}' did not pass validation of regex '{1}'")]
+ ///
+ ///
+ public string ErrorMessage { get; set; }
+
///
/// Validates that each parameter argument matches the RegexPattern
///
@@ -1136,8 +1147,9 @@ namespace System.Management.Automation
Match match = regex.Match(objectString);
if (!match.Success)
{
+ var errorMessageFormat = String.IsNullOrEmpty(ErrorMessage) ? Metadata.ValidatePatternFailure : ErrorMessage;
throw new ValidationMetadataException("ValidatePatternFailure",
- null, Metadata.ValidatePatternFailure,
+ null, errorMessageFormat,
objectString, RegexPattern);
}
}
@@ -1163,6 +1175,18 @@ namespace System.Management.Automation
///
public sealed class ValidateScriptAttribute : ValidateEnumeratedArgumentsAttribute
{
+ ///
+ /// Gets or sets the custom error message that is displayed to the user.
+ ///
+ /// The item being validated and the validating scriptblock is passed as the first and second
+ /// formatting argument.
+ ///
+ ///
+ /// [ValidateScript("$_ % 2", ErrorMessage = "The item '{0}' did not pass validation of script '{1}'")]
+ ///
+ ///
+ public string ErrorMessage { get; set; }
+
///
/// Gets the scriptblock to be used in the validation
///
@@ -1193,8 +1217,9 @@ namespace System.Management.Automation
if (!LanguagePrimitives.IsTrue(result))
{
+ var errorMessageFormat = String.IsNullOrEmpty(ErrorMessage) ? Metadata.ValidateScriptFailure : ErrorMessage;
throw new ValidationMetadataException("ValidateScriptFailure",
- null, Metadata.ValidateScriptFailure,
+ null, errorMessageFormat,
element, ScriptBlock);
}
}
@@ -1336,6 +1361,18 @@ namespace System.Management.Automation
{
private string[] _validValues;
+ ///
+ /// Gets or sets the custom error message that is displayed to the user
+ ///
+ /// The item being validated and a text representation of the validation set
+ /// is passed as the first and second formatting argument to the ErrorMessage formatting pattern.
+ ///
+ ///
+ /// [ValidateSet("A","B","C", ErrorMessage="The item '{0}' is not part of the set '{1}'.")
+ ///
+ ///
+ public string ErrorMessage { get; set; }
+
///
/// Gets a flag specifying if we should ignore the case when performing string comparison. The
/// default is true.
@@ -1386,8 +1423,10 @@ namespace System.Management.Automation
return;
}
}
+
+ var errorMessageFormat = String.IsNullOrEmpty(ErrorMessage) ? Metadata.ValidateSetFailure : ErrorMessage;
throw new ValidationMetadataException("ValidateSetFailure", null,
- Metadata.ValidateSetFailure,
+ errorMessageFormat,
element.ToString(), SetAsString());
}
diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs
index 91244543e..d24520080 100644
--- a/src/System.Management.Automation/engine/parser/Compiler.cs
+++ b/src/System.Management.Automation/engine/parser/Compiler.cs
@@ -1313,6 +1313,10 @@ namespace System.Management.Automation.Language
{
result.IgnoreCase = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue);
}
+ else if (argumentName.Equals("ErrorMessage", StringComparison.OrdinalIgnoreCase))
+ {
+ result.ErrorMessage = argValue.ToString();
+ }
else
{
throw InterpreterError.NewInterpreterException(namedArg, typeof(RuntimeException), namedArg.Extent,
diff --git a/test/powershell/Language/Scripting/ParameterBinding.Tests.ps1 b/test/powershell/Language/Scripting/ParameterBinding.Tests.ps1
index 4f3d2dbf2..6f3795211 100644
--- a/test/powershell/Language/Scripting/ParameterBinding.Tests.ps1
+++ b/test/powershell/Language/Scripting/ParameterBinding.Tests.ps1
@@ -412,6 +412,62 @@
{ get-fooh } | Should not throw
}
+
+ It "ValidateScript can use custom ErrorMessage" {
+ function get-fooi {
+ [CmdletBinding()]
+ param([ValidateScript({$_ -gt 2}, ErrorMessage = "Item '{0}' failed '{1}' validation")] $p)
+ $p
+ }
+ $errMsg = ''
+ try
+ {
+ get-fooi -p 2
+ }
+ catch
+ {
+ $errMsg = $_.Exception.Message
+ }
+ $errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' failed '`$_ -gt 2' validation"
+ }
+
+ It "ValidatePattern can use custom ErrorMessage" {
+ function get-fooj
+ {
+ [CmdletBinding()]
+ param([ValidatePattern("\s+", ErrorMessage = "Item '{0}' failed '{1}' regex")] $p)
+ $p
+ }
+ $errMsg = ''
+ try
+ {
+ get-fooj -p 2
+ }
+ catch
+ {
+ $errMsg = $_.Exception.Message
+ }
+ $errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' failed '\s+' regex"
+ }
+
+ It "ValidateSet can use custom ErrorMessage" {
+ function get-fook
+ {
+ param([ValidateSet('A', 'B', 'C', IgnoreCase=$false, ErrorMessage="Item '{0}' is not in '{1}'")] $p)
+ }
+ $errMsg = ''
+ try
+ {
+ get-fook -p 2
+ }
+ catch
+ {
+ $errMsg = $_.Exception.Message
+ }
+ $set = 'A','B','C' -join [Globalization.CultureInfo]::CurrentUICulture.TextInfo.ListSeparator
+ $errMsg | Should Be "Cannot validate argument on parameter 'p'. Item '2' is not in '$set'"
+ }
+
}
#known issue 2069