diff --git a/NTFSSecurity/ParameterConversion.cs b/NTFSSecurity/ParameterConversion.cs
index 738bf21..11ee2fa 100644
--- a/NTFSSecurity/ParameterConversion.cs
+++ b/NTFSSecurity/ParameterConversion.cs
@@ -17,10 +17,10 @@ namespace NTFSSecurity
///
/// Converts the raw value of a parameter to T, the way the PowerShell binder converts an argument for a
/// parameter of that type: names in any case, a comma-separated list for a flags enumeration, a number, or
- /// an enumeration instance. An enumeration that is not a flags enumeration takes one value: PowerShell would
- /// add up the numbers of a list for it, so that one of the values wins silently or a value that the caller
- /// did not name is chosen, so a list is rejected for it, in whatever kind of collection it comes. A
- /// collection of one element converts as that element.
+ /// an enumeration instance. An enumeration that is not a flags enumeration takes one value: PowerShell
+ /// combines the numbers of a list for it bit by bit, so that one of the values wins silently or a value that
+ /// the caller did not name is chosen, so a list is rejected for it, in whatever kind of collection it comes.
+ /// A collection of one element converts as that element.
///
///
/// The raw value of the parameter. Not null: the caller keeps the default of the parameter for null instead
@@ -40,13 +40,13 @@ namespace NTFSSecurity
if (!typeof(T).IsDefined(typeof(FlagsAttribute), false))
{
- string list;
- convertible = TakeOneValue(value, out list);
- if (list != null)
+ bool isList;
+ convertible = TakeOneValue(value, out isList);
+ if (isList)
{
throw new ArgumentException(string.Format(
"The value '{0}' for parameter -{1} is not valid: the parameter takes one value, not a list. {2}",
- list, parameterName, DescribeValidValues(typeof(T))));
+ Describe(value), parameterName, DescribeValidValues(typeof(T))));
}
}
@@ -64,7 +64,7 @@ namespace NTFSSecurity
catch (Exception ex)
{
throw new ArgumentException(
- string.Format("The value '{0}' for parameter -{1} is not valid. {2}", value, parameterName, DescribeValidValues(typeof(T))),
+ string.Format("The value '{0}' for parameter -{1} is not valid. {2}", Describe(value), parameterName, DescribeValidValues(typeof(T))),
ex);
}
}
@@ -82,30 +82,31 @@ namespace NTFSSecurity
return string.Format("The value for parameter -{0} is null. {1}", parameterName, DescribeValidValues(typeof(T)));
}
+ // How many collections that hold one collection each are opened before the argument counts as a list: enough
+ // for any real argument, and a stop for a collection that holds itself.
+ private const int MaxNesting = 32;
+
// The one value that the conversion takes from the argument of an enumeration that is not a flags enumeration:
// the argument itself, or the only element of a collection of any kind (a wrapped PSObject counts as what it
- // wraps, and a collection that holds a collection is opened too). When the argument holds more than one
- // value, list is its text for the message: a string that holds a comma, a collection of several elements, or
- // a collection of one element that holds such a list; the returned value is then not used. A dictionary, an
- // empty collection, or a collection that cannot be enumerated is returned as it is, for the conversion to
- // reject or convert with its own error.
- private static object TakeOneValue(object value, out string list)
+ // wraps, and a collection that holds a collection is opened too). isList is true when the argument holds more
+ // than one value: a string that holds a comma, a collection of several elements (two are enough to know, so
+ // a long or endless sequence is not read to its end), a collection of one element that holds such a list, or
+ // collections nested deeper than MaxNesting; the returned value is then not used. A dictionary, an empty
+ // collection, or a collection that cannot be enumerated is returned as it is, for the conversion to reject or
+ // convert with its own error.
+ private static object TakeOneValue(object value, out bool isList)
{
- list = null;
+ isList = false;
var current = value;
- while (true)
+ for (var depth = 0; depth < MaxNesting; depth++)
{
var unwrapped = current is PSObject ? ((PSObject)current).BaseObject : current;
var text = unwrapped as string;
if (text != null)
{
- if (text.IndexOf(',') >= 0)
- {
- list = text;
- }
-
+ isList = text.IndexOf(',') >= 0;
return unwrapped;
}
@@ -115,12 +116,19 @@ namespace NTFSSecurity
return unwrapped;
}
- var items = new System.Collections.Generic.List