710 lines
26 KiB
C#

//----------------------------------------------------------------------------
//
// Copyright (C) Intel Corporation, 2006 - 2011 All Rights Reserved.
//
// File: CmdLineArguments.cs
//
// Contents: This file is an infrastructure for the entire WSMan sample.
// It contains a parser for the information inputted by the user
// via the command line arguments.
//
//----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
namespace Intel.Manageability.Utils
{
/// <summary>
/// This class is used to parse command line arguments.
/// Parameters can be given in the following format: [Parameter Value] pair
/// Parameter starting with - or / and Value separated from a Name with a space.
/// </summary>
public class CmdLineArguments
{
#region CONSTANTS
public const string OPT_HOST = "host";
public const string OPT_PASS = "pass";
public const string OPT_USER = "user";
public const string OPT_SECURE = "tls";
public const string OPT_KRB = "krb";
public const string OPT_CERT = "certname";
public const string OPT_VERBOSE = "verbose";
public const string OPT_PROXY = "proxy";
public const string OPT_PROXY_USER = "proxyuser";
public const string OPT_PROXY_PASSWORD = "proxypass";
public const string OPT_LOCAL = "local";
public const string OPT_ENUMERATE = "getallcontexts";
public const string OPT_SUBSCRIBE = "subscribe";
public const string OPT_UNSUBSCRIBE = "unsubscribe";
public const string OPT_IS_MACHINE_CONNECTED = "ismachineconnected";
private static List<string> PreDefinedFlags = new List<string>();
private static List<string> StandAloneArguments = new List<string>();
static CmdLineArguments()
{
InitStandAloneArguments();
}
private static void InitStandAloneArguments()
{
string[] tmpFlags = new string[] { OPT_HOST, OPT_PASS, OPT_USER, OPT_SECURE, OPT_KRB, OPT_CERT, OPT_VERBOSE, OPT_PROXY, OPT_PROXY_USER, OPT_PROXY_PASSWORD, OPT_LOCAL, OPT_ENUMERATE, OPT_SUBSCRIBE, OPT_UNSUBSCRIBE, OPT_IS_MACHINE_CONNECTED };
PreDefinedFlags.AddRange(tmpFlags);
StandAloneArguments.AddRange(tmpFlags);
}
/// <summary>
/// This enum will be used if the calling
/// application would like to disable specific conditions
/// </summary>
[Flags]
public enum ExclusionList
{
None = 0,
/// <summary>
/// The following value should disable the condition
/// of (username & pwd) | kerberos is needed
/// Notice the next enum values should be 2, 4, 8 ...
/// </summary>
DISABLE_AUTHENTICATION_CHECK = 1
};
#endregion CONSTANTS
#region DATA_MEMBERS
/// <summary>
/// This class represents a command line parameter (argument).
/// </summary>
public class Argument
{
/// <summary>Argument name identifer without the - , -- or / </summary>
private string _name = string.Empty;
/// <summary>The value of this argument.</summary>
private string _value = string.Empty;
/// <summary>Short description for this argument.</summary>
private string _description = string.Empty;
/// <summary>Indicates if this argument is mandatory.</summary>
private bool _mandatory; // Initializes by default to false
/// <summary>Indicates if this argument was found in the command line. </summary>
private bool _selected; // Initializes by default to false
/// <summary>Indicated whether this argument requires a value</summary>
private bool _hasValue; // Initializes by default to false
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">string, argument identifier</param>
/// <param name="hasValue">bool, value required</param>
/// <param name="mandatory">bool, is argument mandatory</param>
public Argument(string name, bool hasValue, bool mandatory, string description)
{
_name = name;
_hasValue = hasValue;
_mandatory = mandatory;
_description = description;
}
/// <summary>
/// Constructor (for old version support)
/// </summary>
/// <param name="name">string, argument identifier</param>
/// <param name="hasValue">bool, value required</param>
/// <param name="mandatory">bool, is argument mandatory</param>
public Argument(string name, bool hasValue, bool mandatory)
{
_name = name;
_hasValue = hasValue;
_mandatory = mandatory;
_description = "";
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">string, argument identifier</param>
/// <param name="hasValue">bool, value required</param>
public Argument(string name, bool hasValue)
{
_name = name;
_hasValue = hasValue;
}
/// <summary>
/// Get a string representation of this class
/// </summary>
/// <returns>string</returns>
public override string ToString()
{
return _value;
}
/// <summary>
/// Property: Argument description
/// </summary>
public string Description
{
get { return _description; }
set { _description = value; }
}
/// <summary>
/// Property: Argument identifer without the - , -- or /
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// Property: Indicates whether this argument requires a value
/// </summary>
public bool HasValue
{
get { return _hasValue; }
set { _hasValue = value; }
}
/// <summary>
/// Property: Indicates if this argument is mandatory
/// </summary>
public bool Mandatory
{
get { return _mandatory; }
set { _mandatory = value; }
}
/// <summary>
/// Property: The value of this argument.
/// </summary>
public string Value
{
get { return _value; }
set { _value = value; }
}
/// <summary>
/// Property: indicates if this argument was found in the command line
/// </summary>
public bool Selected
{
get { return _selected; }
set { _selected = value; }
}
}
/// <summary>
/// Thrown by the ApplicationCommandLine during processing
/// </summary>
[SerializableAttribute]
public class Exception : System.Exception
{
/// <summary>
/// Default constructor
/// </summary>
/// <param name="msg">string, Error message</param>
public Exception(string msg) : base(msg) { }
}
/// <summary>
/// Dictionary for arguments
/// </summary>
private Dictionary<string, Argument> _arguments;
/// <summary>
/// Indicate if more than one option can be specified - false by default
/// </summary>
private bool _hasMultipleOptions = false;
public bool HasMultipleOptions
{
get { return _hasMultipleOptions; }
set { _hasMultipleOptions = value; }
}
/// <summary>
/// the following variable will contain list of
/// conditions that the calling application would like to disable
/// </summary>
private ExclusionList _exclusionList;
/// <summary>
/// return the value of the argumet.
/// </summary>
/// <param name="name">argument name</param>
/// <returns>argument value</returns>
public string Value(string name)
{
if (_arguments.ContainsKey(name.ToLower()))
return _arguments[name.ToLower()].Value;
return null;
}
#endregion DATA_MEMBERS
#region CONSTRUCTORS
/// <summary>
/// Default Constructor
/// </summary>
public CmdLineArguments()
{
_arguments = new Dictionary<string, Argument>();
_exclusionList = ExclusionList.None;
}
#endregion CONSTRUCTORS
#region PUBLIC_FUNCTIONS
/// <summary>
/// Creates a usage explanation string
/// </summary>
/// <returns> string, the usage string</returns>
public string CreateUsage(string assemblyName, bool verbose)
{
string usage = CreateUsage(assemblyName, verbose, false);
return usage;
}
/// <summary>
/// Creates a usage explanation string
/// </summary>
/// <returns> string, the usage string</returns>
public string CreateUsage(string assemblyName, string additionalData, bool verbose)
{
string usageStr = CreateUsage(assemblyName, verbose);
usageStr += "\n" + additionalData + "\n";
return usageStr;
}
public void SetExclusionList(ExclusionList exclusionList)
{
_exclusionList = exclusionList;
}
/// <summary>
/// Creates a usage explanation string
/// </summary>
/// <returns> string, the usage string</returns>
public string CreateUsage(string assemblyName, bool verbose, bool hasLocalOption)
{
string usageStr = string.Empty;
StringBuilder optionsStr = new StringBuilder();
bool optionsExist = false;
string firstOption = string.Empty; // Holds first option, if exists, for usage example
// Go over the options (if any)
IDictionaryEnumerator e = _arguments.GetEnumerator();
int maxOptionNameLength = 0;
while (e.MoveNext())
{
Argument arg = _arguments[e.Key.ToString()];
if (IsCommonArg(arg.Name) == false)
{
if (arg.Name.Length > maxOptionNameLength)
{
maxOptionNameLength = arg.Name.Length;
}
}
}
e = _arguments.GetEnumerator();
while (e.MoveNext())
{
Argument arg = _arguments[e.Key.ToString()];
if (IsCommonArg(arg.Name) == false)
{
optionsExist = true;
optionsStr.Append("\t -" + arg.Name);
if (string.IsNullOrEmpty(firstOption)) // Gets the first option exists that doesn't have a value
if(!arg.HasValue)
firstOption = arg.Name;
if (arg.HasValue)
optionsStr.Append(" <value>");
for (int i = arg.Name.Length; i <= maxOptionNameLength; i++)
{
optionsStr.Append(" ");
}
optionsStr.Append(":\t" + arg.Description + "\n");
}
}
usageStr += "Usage:\n";
usageStr += "\t " + assemblyName;
if (optionsExist)
usageStr += " <opt>";
if (verbose)
usageStr += " [-verbose]";
usageStr += " -host <Hostname> [-user <user name> -pass <password>] [-krb] [-tls -certName <certName>]"
+ " [-proxy <host:port> [-proxyUser <proxy user> -proxyPass <proxy password>]]";
if (hasLocalOption)
{
usageStr += " [-local]";
}
usageStr += CreateUsageForStandAloneComponents();
usageStr += "\n\n";
if (optionsExist)
{
usageStr += "Where <opt> is :\n";
usageStr += optionsStr.ToString();
}
if (verbose)
usageStr += "\nIf -verbose is used the sample will display additional output information." + "\n";
usageStr +="\nIf -user <username> -pass <password> are defined and -krb isn't defined the Digest authentication scheme is used." + "\n\n"
+ "If -krb is used the Kerberos authentication scheme will be attempted." + "\n"
+ "\tIf specified, the kerberos user should be given in domain\\name format." + "\n\n"
+ "If -tls is used the sample application will perform server authentication. This option is required if the Intel AMT platform is configured for TLS." + "\n"
+ "Use -certName <name> to specify the client certificate's Common Name (CN)." + "\n\t"
+ "Used in TLS Mutual Authentication mode only." + "\n\t"
+ "If this option is not specified the sample application will search the" + "\n\t"
+ "certificate store for a client certificate matching Intel(R) AMT" + "\n\t" + "requirements." + "\n\t"
+ "The first one found will be used for authentication." + "\n\n"
+ "Use -proxy <host:port> when there is a proxy server between the sample application and Intel AMT." + "\n"
+ "Use -proxyUser <proxy user> -proxyPass <proxy password> when the proxy requires these parameters." + "\n";
if (hasLocalOption)
{
usageStr += "\nIf -local is used, the sample will use the local OsAdmin credentials.\n"+
"Please note that if -local is specified, the sample will ignore the other authentication \nproperties.\n\n";
}
usageStr += CreateDescriptionUsageForStandAloneComponents();
usageStr += "\nExamples:\n" + GetExamples(assemblyName, firstOption, verbose, hasLocalOption) + "\n";
return usageStr;
}
private string CreateDescriptionUsageForStandAloneComponents()
{
StringBuilder optionsStr = new StringBuilder();
foreach (string item in StandAloneArguments)
{
if (PreDefinedFlags.Contains(item))
continue;
Argument arg = _arguments[item];
optionsStr.Append(arg.Description + "\n");
}
return optionsStr.ToString();
}
private string CreateUsageForStandAloneComponents()
{
StringBuilder optionsStr = new StringBuilder();
foreach (string item in StandAloneArguments)
{
if (PreDefinedFlags.Contains(item))
continue;
optionsStr.Append(" ");
Argument arg = _arguments[item];
StringBuilder val = new StringBuilder();
if (arg.HasValue)
{
val.Append(" <value>");
}
if (arg.Mandatory)
{
optionsStr.Append("-" + item + val);
}
else
{
optionsStr.Append("[" + "-" + item + val + "]");
}
}
return optionsStr.ToString();
}
/// <summary>
/// Returns a IWebProxy according to the proxy parameters
/// </summary>
/// <returns> a IWebProxy or null if proxy parameter not define</returns>
public IWebProxy GetWebProxy()
{
string proxyAddress = this[OPT_PROXY];
if (proxyAddress != null)
{
if (!Regex.IsMatch(proxyAddress, @"\w\:\w"))
{
throw new ArgumentException("proxy argument is not according to usage");
}
string[] splitAddress = proxyAddress.Split(':');
int port = 0;
if (splitAddress.Length != 2 || !int.TryParse(splitAddress[1], out port))
{
throw new ArgumentException("proxy argument is not according to usage");
}
IWebProxy proxy = new WebProxy(splitAddress[0], port);
if (this[OPT_PROXY_USER] != null && this[OPT_PROXY_PASSWORD] != null)
{
proxy.Credentials = new NetworkCredential(this[OPT_PROXY_USER], this[OPT_PROXY_PASSWORD]);
}
return proxy;
}
return null;
}
/// <summary>
/// Parse the command line arguments.
/// </summary>
/// <param name="args">string array, typically the string[] received from Main</param>
public void Parse(string[] args)
{
int runOptions = 0;
// Iterate arguments
for (int i = 0; i < args.Length; i++)
{
// if the argument starts with an argument prefix
if (args[i].StartsWith("-") || args[i].StartsWith("/"))
{
string argName = args[i].Substring(1).ToLower();
// Check if argument is in our _arguments list.
if (_arguments.ContainsKey(argName))
{
if (!IsCommonArg(argName))
{
runOptions++;
}
// Process it
Argument arg = _arguments[argName.ToLower()];
// set it to selected
arg.Selected = true;
// Check if argument requires a value.
if (arg.HasValue)
{
if (++i >= args.Length)
throw new Exception("Could not find value for " + argName + ".");
if (args[i].StartsWith("-") || args[i].StartsWith("/"))
throw new Exception("Could not find value for " + argName + ".");
arg.Value = args[i];
}
}
else
{
// Invalid argument
throw new Exception("Invalid argument: " + argName + ".");
}
}
else
{
throw new Exception("Invalid argument: " + args[i] + ".");
}
}
if (runOptions > 1 && !_hasMultipleOptions)
{
throw new Exception("Specified more than one option");
}
// Make sure we received all mandatory arguments
for (IDictionaryEnumerator e = _arguments.GetEnumerator(); e.MoveNext(); )
{
Argument arg = (Argument)e.Value;
if (arg.Mandatory && !arg.Selected)
throw new Exception(arg.Name + " is not specified.");
}
if (_arguments.ContainsKey("user") && _arguments.ContainsKey("pass"))
{
// Checks appearance of both username and pass or none
if (_arguments["user"].Selected == !_arguments["pass"].Selected)
{
throw new Exception("user and pass must be both specified or both not specified.");
}
if (!((_exclusionList & ExclusionList.DISABLE_AUTHENTICATION_CHECK) == ExclusionList.DISABLE_AUTHENTICATION_CHECK))
{
// Checks authentication method
if (!_arguments["user"].Selected && !_arguments["pass"].Selected && !_arguments["krb"].Selected && !_arguments["local"].Selected)
{
throw new Exception("No authentication method available.");
}
}
}
if (_arguments.ContainsKey("proxyuser") && _arguments.ContainsKey("proxypass"))
{
if (_arguments["proxyuser"].Selected == !_arguments["proxypass"].Selected)
{
throw new Exception("proxyUser and proxyPass must be both specified or both not specified.");
}
}
}
/// <summary>
/// Add an argument to the valid argument list.
/// </summary>
/// <param name="arg">Argument, Add an expected argument</param>
public void AddArg(Argument arg)
{
_arguments.Add(arg.Name.ToLower(), arg);
}
/// <summary>
/// Add an argument to the valid argument list.
/// </summary>
/// <param name="name">string, argument name. </param>
/// <param name="hasValue">bool, is value required</param>
/// <param name="mandatory">bool, is mandatory argument</param>
public void AddArg(string name, bool hasValue, bool mandatory, string description)
{
AddArg(new Argument(name.ToLower(), hasValue, mandatory, description));
}
/// <summary>
/// Add an argument to the valid argument list.
/// </summary>
/// <param name="name">string, argument name. </param>
/// <param name="hasValue">bool, is value required</param>
/// <param name="mandatory">bool, is mandatory argument</param>
public void AddStandAloneArg(string name, bool hasValue, bool mandatory, string description)
{
AddArg(new Argument(name.ToLower(), hasValue, mandatory, description));
StandAloneArguments.Add(name.ToLower());
}
/// <summary>
/// Add an argument to the valid argument list.
/// </summary>
/// <param name="name">string, argument name. </param>
/// <param name="hasValue">bool, is value required</param>
/// <param name="mandatory">bool, is mandatory argument</param>
public void AddArg(string name, bool hasValue, bool mandatory)
{
AddArg(new Argument(name.ToLower(), hasValue, mandatory, ""));
}
/// <summary>
/// Check whether argument was given in the command line.
/// </summary>
/// <param name="name">argument name</param>
/// <returns>true if argument was selected</returns>
public bool Selected(string name)
{
if (_arguments.ContainsKey(name.ToLower()))
return _arguments[name.ToLower()].Selected;
return false;
}
/// <summary>
/// Indexer by argument name (only get)
/// </summary>
/// <param name="name">argument</param>
/// <returns></returns>
public string this[string name]
{
get
{
if (_arguments.ContainsKey(name.ToLower()))
{
Argument arg = _arguments[name.ToLower()];
if (arg.Selected)
{
if (arg.HasValue)
return arg.Value;
}
}
return null;
}
}
#endregion PUBLIC_FUNCTIONS
#region PRIVATE_FUNCTIONS
/// <summary>
/// Checks if the parameter name is a common argument that exists as a const.
/// </summary>
/// <param name="name">string, name to check</param>
/// <returns> bool, true if it's a common argument, false if not</returns>
private static bool IsCommonArg(string name)
{
return StandAloneArguments.Contains(name);
}
/// <summary>
/// Gets the 3 usage examples.
/// </summary>
/// <param name="assemblyName">string, the assembly name</param>
/// <param name="option">string, the first option, or an empty string if no option exists</param>
/// <param name="verbose">bool, true if verbose flag is on</param>
/// <returns> string, the 3 examples as a string</returns>
private static string GetExamples(string assemblyName, string option, bool verbose, bool hasLocalOption)
{
string examples = string.Empty;
// Creates first example
examples += assemblyName;
if (!string.IsNullOrEmpty(option))
examples += " -" + option;
if (verbose)
examples += " -" + OPT_VERBOSE;
examples += " -" + OPT_HOST + " 192.168.0.1 -" + OPT_USER + " admin -" + OPT_PASS + " Admin!98" + "\n";
// Creates second example
examples += assemblyName;
if (!string.IsNullOrEmpty(option))
examples += " -" + option;
if (verbose)
examples += " -" + OPT_VERBOSE;
examples += " -" + OPT_HOST + " hostname -" + OPT_KRB + "\n";
// Creates third example
examples += assemblyName;
if (!string.IsNullOrEmpty(option))
examples += " -" + option;
if (verbose)
examples += " -" + OPT_VERBOSE;
examples += " -" + OPT_HOST + " hostname -" + OPT_USER + " admin -" + OPT_PASS + " Admin!98 -"
+ OPT_SECURE + " -" + OPT_CERT + " certCommonName\n";
if (hasLocalOption)
{
examples += assemblyName;
if (!string.IsNullOrEmpty(option))
examples += " -" + option;
if (verbose)
examples += " -" + OPT_VERBOSE;
examples += " -" + OPT_HOST + " hostname -" + OPT_LOCAL;
}
return examples;
}
#endregion PRIVATE_FUNCTIONS
}
}