/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Management.Automation.Language;
using Microsoft.Management.Infrastructure;
namespace System.Management.Automation.Runspaces
{
using System;
using System.Collections.ObjectModel;
using Debug = System.Management.Automation.Diagnostics;
///
/// Define a parameter for
///
public sealed class CommandParameter
{
#region Public constructors
///
/// Create a named parameter with a null value
///
/// parameter name
///
/// name is null.
///
///
/// Name length is zero after trimming whitespace.
///
public CommandParameter(string name)
: this(name, null)
{
if (name == null)
{
throw PSTraceSource.NewArgumentNullException("name");
}
}
///
/// Create a named parameter
///
/// parameter name
/// parameter value
///
/// Name is non null and name length is zero after trimming whitespace.
///
public CommandParameter(string name, object value)
{
if (name != null)
{
if (name.Trim().Length == 0)
{
throw PSTraceSource.NewArgumentException("name");
}
Name = name;
}
else
{
Name = null;
}
Value = value;
}
#endregion Public constructors
#region Public properties
///
/// gets the parameter name
///
public string Name { get; }
///
/// gets the value of the parameter
///
public object Value { get; }
#endregion Public properties
#region Private Fields
#endregion Private Fields
#region Conversion from and to CommandParameterInternal
internal static CommandParameter FromCommandParameterInternal(CommandParameterInternal internalParameter)
{
if (internalParameter == null)
{
throw PSTraceSource.NewArgumentNullException("internalParameter");
}
// we want the name to preserve 1) dashes, 2) colons, 3) followed-by-space information
string name = null;
if (internalParameter.ParameterNameSpecified)
{
name = internalParameter.ParameterText;
if (internalParameter.SpaceAfterParameter)
{
name = name + " ";
}
Diagnostics.Assert(name != null, "'name' variable should be initialized at this point");
Diagnostics.Assert(name[0].IsDash(), "first character in parameter name must be a dash");
Diagnostics.Assert(name.Trim().Length != 0, "Parameter name has to have some non-whitespace characters in it");
}
if (internalParameter.ParameterAndArgumentSpecified)
{
return new CommandParameter(name, internalParameter.ArgumentValue);
}
if (name != null) // either a switch parameter or first part of parameter+argument
{
return new CommandParameter(name);
}
// either a positional argument or second part of parameter+argument
return new CommandParameter(null, internalParameter.ArgumentValue);
}
internal static CommandParameterInternal ToCommandParameterInternal(CommandParameter publicParameter, bool forNativeCommand)
{
if (publicParameter == null)
{
throw PSTraceSource.NewArgumentNullException("publicParameter");
}
string name = publicParameter.Name;
object value = publicParameter.Value;
Debug.Assert((name == null) || (name.Trim().Length != 0), "Parameter name has to null or have some non-whitespace characters in it");
if (name == null)
{
return CommandParameterInternal.CreateArgument(PositionUtilities.EmptyExtent, value);
}
string parameterText;
if (!name[0].IsDash())
{
parameterText = forNativeCommand ? name : "-" + name;
return CommandParameterInternal.CreateParameterWithArgument(
PositionUtilities.EmptyExtent, name, parameterText,
PositionUtilities.EmptyExtent, value,
true);
}
// if first character of name is '-', then we try to fake the original token
// reconstructing dashes, colons and followed-by-space information
// find the last non-whitespace character
bool spaceAfterParameter = false;
int endPosition = name.Length;
while ((endPosition > 0) && char.IsWhiteSpace(name[endPosition - 1]))
{
spaceAfterParameter = true;
endPosition--;
}
Debug.Assert(endPosition > 0, "parameter name should have some non-whitespace characters in it");
// now make sure that parameterText doesn't have whitespace at the end,
parameterText = name.Substring(0, endPosition);
// parameterName should contain only the actual name of the parameter (no whitespace, colons, dashes)
bool hasColon = (name[endPosition - 1] == ':');
var parameterName = parameterText.Substring(1, parameterText.Length - (hasColon ? 2 : 1));
// At this point we have rebuilt the token. There are 3 strings that might be different:
// name = nameToken.Script = "-foo: " <- needed to fake FollowedBySpace=true (i.e. for "testecho.exe -a:b -c: d")
// tokenString = nameToken.TokenText = "-foo:" <- needed to preserve full token text (i.e. for write-output)
// nameToken.Data = "foo" <- needed to preserve name of parameter so parameter binding works
// Now we just need to use the token to build appropriate CommandParameterInternal object
// is this a name+value pair, or is it just a name (of a parameter)?
if (!hasColon && value == null)
{
// just a name
return CommandParameterInternal.CreateParameter(
PositionUtilities.EmptyExtent, parameterName, parameterText);
}
// name+value pair
return CommandParameterInternal.CreateParameterWithArgument(
PositionUtilities.EmptyExtent, parameterName, parameterText,
PositionUtilities.EmptyExtent, value,
spaceAfterParameter);
}
#endregion
#region Serialization / deserialization for remoting
///
/// Creates a CommandParameter object from a PSObject property bag.
/// PSObject has to be in the format returned by ToPSObjectForRemoting method.
///
/// PSObject to rehydrate
///
/// CommandParameter rehydrated from a PSObject property bag
///
///
/// Thrown if the PSObject is null.
///
///
/// Thrown when the PSObject is not in the expected format
///
internal static CommandParameter FromPSObjectForRemoting(PSObject parameterAsPSObject)
{
if (parameterAsPSObject == null)
{
throw PSTraceSource.NewArgumentNullException("parameterAsPSObject");
}
string name = RemotingDecoder.GetPropertyValue(parameterAsPSObject, RemoteDataNameStrings.ParameterName);
object value = RemotingDecoder.GetPropertyValue