//---------------------------------------------------------------------------- // // Copyright (C) Intel Corporation, 2011 - 2012. // // 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.Generic; using Intel.Management.Wsman; using System.Text.RegularExpressions; using System.Text; using Common.Utils; namespace Utils { /// /// This class 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. /// public class CmdLineArguments { #region CONSTANTS //command line Flags 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_WIRELESS = "wireless"; 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 NO_RESTORE_OPTION = "norestore"; // Setting this option will cause a skip of any certificate check in case the certificate is self-signed. public const string ACCEPT_SELF_SIGNED_CERTIFICATE = "acceptselfsignedcert"; 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"; //username and password boundaries public const int MAX_USER_LENGTH = 32; public const int MAX_PWD_LENGTH = 32; public const int MIN_PWD_LENGTH = 8; //private const string RESTORATION_DESCRIPTION = "No restoration flag. Indicates the sample not to restore the previous settings"; // Exit Codes Types private enum exitCodes { EXIT_SUCCESS = 0, EXIT_FAILURE, EXIT_USAGE, EXIT_COMMUNICATION_ERROR, EXIT_ARGUMENT_ERROR, } private static List PreDefinedFlags = new List(); private static List StandAloneArguments = new List(); static CmdLineArguments() { InitStandAloneArguments(); } private static void InitStandAloneArguments() { string[] tmpFlags = new[] { OPT_HOST, OPT_PASS, OPT_USER, OPT_SECURE, OPT_WIRELESS, 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, NO_RESTORE_OPTION, ACCEPT_SELF_SIGNED_CERTIFICATE }; PreDefinedFlags.AddRange(tmpFlags); StandAloneArguments.AddRange(tmpFlags); } /// /// This enum will be used if the calling /// application would like to disable specific conditions /// [Flags] public enum ExclusionList { None = 0, /// /// The following value should disable the condition /// of (username & pwd) | kerberos is needed /// Notice the next enum values should be 2, 4, 8 ... /// DISABLE_AUTHENTICATION_CHECK = 1 }; #endregion #region PUBLIC_FUNCTIONS /// /// Creates a usage explanation string /// /// string, the usage string public string CreateUsage(string assemblyName, bool verbose, bool hasLocalOption) { string usage = CreateUsage(assemblyName, verbose, hasLocalOption, false); return usage; } /// /// Creates a usage explanation string /// /// string, the usage string public string CreateUsage(string assemblyName, bool verbose) { string usage = CreateUsage(assemblyName, verbose, false); return usage; } /// /// Creates a usage explanation string /// /// string, the usage string public string CreateUsage(string assemblyName, string additionalData, bool verbose) { return CreateUsage(assemblyName, additionalData, verbose, false); } /// /// Creates a usage explanation string /// /// string, the usage string public string CreateUsage(string assemblyName, string additionalData, bool verbose, bool hasWirelessOption) { string usageStr = CreateUsage(assemblyName, verbose, false, hasWirelessOption); usageStr += "\n" + additionalData + "\n"; return usageStr; } public void SetExclusionList(ExclusionList exclusionList) { _exclusionList = exclusionList; } /// /// Creates a usage explanation string /// /// string, the usage string public string CreateUsage(string assemblyName, bool verbose, bool hasLocalOption, bool hasWirelessOption, bool hasRestoreOption = false) { string usageStr = string.Empty; StringBuilder optionsStr = new StringBuilder(); bool optionsExist = false; List firstOption = new List(); // 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; } } } usageStr += "Usage:\n"; usageStr += "\t " + assemblyName; usageStr += " "; if (verbose) usageStr += " [-verbose]"; if (hasWirelessOption) usageStr += " [-wireless]"; if (hasRestoreOption) usageStr += " [-norestore]"; usageStr += " -host [-user -pass ] [-krb] [-acceptselfsignedcert] [-tls -certName ]" + " [-proxy [-proxyUser -proxyPass ]]"; if (hasLocalOption) usageStr += " [-local]"; usageStr += createUsageForStandAloneComponents(); usageStr += "\n\n"; e = _arguments.GetEnumerator(); while (e.MoveNext()) { Argument arg = _arguments[e.Key.ToString()]; if (IsCommonArg(arg.Name) == false) { optionsExist = true; optionsStr.Append("\t -" + arg.Name); // Gets the option that doesn't have a if (!arg.HasValue) { firstOption.Add(arg.Name); } if (arg.HasValue) optionsStr.Append(" "); for (int i = arg.Name.Length; i <= maxOptionNameLength; i++) { optionsStr.Append(" "); } optionsStr.Append(":\t" + arg.Description + "\n"); } } if (optionsExist) { usageStr += "Where is :\n"; usageStr += optionsStr.ToString(); } if (verbose) usageStr += "\nIf –verbose is used the sample will display additional output information." + "\n"; usageStr += "\nIf -user -pass 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 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" + "The –acceptselfsignedcert option is used to accept self signed certificate. If set, in case the certificate is self-signed, the sample application will ignore any certificate errors." + "\n\n" + "Use -proxy when there is a proxy server between the sample application and Intel AMT." + "\n" + "Use -proxyUser -proxyPass 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"; if (hasWirelessOption) usageStr += "\nIf -wireless is used, the sample will use the wireless interface.\n" + "Please note that not in all the functions are available when using the wireless interface.\n\n"; if (hasRestoreOption) usageStr += "\n-norestore: This flag will indicate whether to restore the system's settings or not.\n" + "By default the sample will restore to the old settings. When choosing noRestore flag, the sample will not restore to the old settings.\n"+ "When -api option is chosen, the sample will ignore this flag.\n\n"; usageStr += createDescriptionUsageForStandAloneComponents(); usageStr += "\nExamples:\n" + GetExamples(assemblyName, firstOption.ToArray(), 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(" "); } if (arg.Mandatory) { optionsStr.Append("-" + item + val.ToString()); } else { optionsStr.Append("[" + "-" + item + val.ToString() + "]"); } } return optionsStr.ToString(); } #endregion #region PRIVATE_FUNCTIONS /// /// Checks if the parameter name is a common argument that exists as a const. /// /// string, name to check /// bool, true if it's a common argument, false if not private static bool IsCommonArg(string name) { return StandAloneArguments.Contains(name); } /// /// Gets the 3 usage examples. /// /// string, the assembly name /// string, the first option, or an empty string if no option exists /// bool, true if verbose flag is on /// bool, if local option is available /// string, the 3 examples as a string private static string GetExamples(string assemblyName, string[] options, bool verbose, bool hasLocalOption) { StringBuilder examples = new StringBuilder(); int count = 0; if (options.Length > 0) { foreach (string opt in options) { // Creates first example examples.Append(assemblyName); if (!string.IsNullOrEmpty(opt)) examples.Append(" -" + opt); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " 192.168.0.1 -" + OPT_USER + " admin -" + OPT_PASS + " P@ssw0rd" + "\n"); // Creates second example examples.Append(assemblyName); if (!string.IsNullOrEmpty(opt)) examples.Append(" -" + opt); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " hostname -" + OPT_KRB + "\n"); // Creates third example examples.Append(assemblyName); if (!string.IsNullOrEmpty(opt)) examples.Append(" -" + opt); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " hostname -" + OPT_USER + " admin -" + OPT_PASS + " P@ssw0rd -" + OPT_SECURE + " -" + OPT_CERT + " certCommonName\n\n"); //check for the "-local" option if (hasLocalOption) { examples.Append(assemblyName); if (!string.IsNullOrEmpty(opt)) examples.Append(" -" + opt); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " hostname -" + OPT_LOCAL); } count++; if (count > 1) //show 2 options only... If want to display all option this line can be eliminated. break; } } else { if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " 192.168.0.1 -" + OPT_USER + " admin -" + OPT_PASS + " P@ssw0rd" + "\n"); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " hostname -" + OPT_KRB + "\n"); if (verbose) examples.Append(" -" + OPT_VERBOSE); examples.Append(" -" + OPT_HOST + " hostname -" + OPT_USER + " admin -" + OPT_PASS + " P@ssw0rd -" + OPT_SECURE + " -" + OPT_CERT + " certCommonName\n\n"); } return examples.ToString(); } #endregion PRIVATE_FUNCTIONS /// /// This class represents a command line parameter (argument). /// public class Argument { /// Argument name identifier without the - , -- or / private string _name = string.Empty; /// The value of this argument. private string _value = string.Empty; /// Short description for this argument. private string _description = string.Empty; /// /// Constructor /// /// string, argument identifier /// bool, value required /// bool, is argument mandatory /// public Argument(string name, bool hasValue, bool mandatory, string description) { Selected = false; _name = name; HasValue = hasValue; Mandatory = mandatory; _description = description; } /// /// Constructor /// /// string, argument identifier /// bool, value required /// bool, is argument mandatory public Argument(string name, bool hasValue, bool mandatory) { Selected = false; _name = name; HasValue = hasValue; Mandatory = mandatory; _description = ""; } /// /// Constructor /// /// string, argument identifier /// bool, value required public Argument(string name, bool hasValue) { Selected = false; Mandatory = false; _name = name; HasValue = hasValue; } /// /// Get A string representation of this class /// /// string public override string ToString() { return _value; } /// /// Property: Argument description /// public string Description { get { return _description; } set { _description = value; } } /// /// Property: Argument identifier without the - , -- or / /// public string Name { get { return _name; } set { _name = value; } } /// /// Property: Indicated whether this argument requires a value /// public bool HasValue { get; set; } /// /// Property: Indicates if this argument is mandatory /// public bool Mandatory { get; set; } /// /// Property: The value of this argument. /// public string Value { get { return _value; } set { _value = value; } } /// /// Property: indicates if this argument was found in the command line /// public bool Selected { get; set; } } /// /// Thrown by the ApplicationCommandLine during processing /// public class Exception : System.Exception { /// /// Default constructor /// /// string, Error message public Exception(string msg) : base(msg) { } } /// /// Hashtable for arguments /// private Dictionary _arguments; /// /// the following variable will contain list of /// conditions that the calling application would like to disable /// private ExclusionList _exclusionList; /// /// Default Constructor /// public CmdLineArguments() { //_arguments = new Hashtable(); _arguments = new Dictionary(); _exclusionList = ExclusionList.None; } /// /// Parse the command line arguments. /// /// string array, typically the string[] received from Main public void Parse(string[] args) { // Iterate arguments for (int i = 0; i < args.Length; i++) { // if the argument start with an argument prefix if (args[i].StartsWith("-") || args[i].StartsWith("/")) { string argName = args[i].Substring(1); // Check if argument is in our _arguments list. if (_arguments.ContainsKey(argName)) { // Process it Argument arg = _arguments[argName]; // 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 found value for " + argName + "."); if (args[i].StartsWith("-") || args[i].StartsWith("/")) throw new Exception("Could not found value for " + argName + "."); //If this option is host name - validate value. if (argName.Equals(OPT_HOST)) ValidateHostName(args[i]); //If this option is user name - validate value. else if (argName.Equals(OPT_USER)) ValidateUserName(args[i]); //If this option is user password - validate value. else if (argName.Equals(OPT_PASS)) ValidatePassword(args[i]); //If this option is certificate name - validate value. else if (argName.Equals(OPT_CERT)) ValidateCertificateCn(args[i]); //If this option is proxy user name - validate value. else if (argName.Equals(OPT_PROXY_USER)) ValidateUserName(args[i]); //If this option is proxy password - validate value. else if (argName.Equals(OPT_PROXY_PASSWORD)) ValidatePassword(args[i]); arg.Value = args[i]; } } else { // Invalid argument throw new Exception("Invalid argument: " + argName + "."); } } else { throw new Exception("Invalid argument: " + args[i] + "."); } } // Make sure we received all mandatory argument. 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."); } } /// ///validates host name /// private static void ValidateHostName(string host) { if (Uri.CheckHostName(host) == UriHostNameType.Unknown) throw new Exception("Invalid argument: Invalid Host name"); } /// ///validates port number /// private static void ValidatePort(int port) { if (port < 0 || port > 65535) throw new ArgumentException("Argument error - Invalid port number"); } /// ///validates user name /// private static void ValidateUserName(string user) { if(user.Length > MAX_USER_LENGTH) throw new Exception("Invalid argument: Username can contain up to 32 characters."); } /// ///validates user password /// private static void ValidatePassword(string password) { if (!string.IsNullOrEmpty(password) && (password.Length < MIN_PWD_LENGTH || password.Length > MAX_PWD_LENGTH)) throw new Exception("Invalid argument: Password must contain between 8 to 32 characters."); } /// ///validates certificate common name /// private static void ValidateCertificateCn(string commonName) { // In the common name field of the DN of a X509 certificate, , the limit is up to 64 characters. if (commonName.Length > 64) throw new Exception("Invalid argument: Invalid certificate common name."); } /// /// Returns a IWebProxy according to the proxy parameters /// /// a IWebProxy or null if proxy parameter not define public MpsManager 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"); } //validating proxy host and proxy port ValidateHostName(splitAddress[0]); ValidatePort(port); MpsManager proxy = new MpsManager();//WebProxy(splitAddress[0], port); if (this[OPT_PROXY_USER] != null && this[OPT_PROXY_PASSWORD] != null) { proxy.HttpUser = this[OPT_PROXY_USER]; // WSMAN lib library supports passwords in SecureString format only. // Convert password to secure string to comply with wsman dll which supports passwords in SecureString // format only. proxy.HttpPassword = this[OPT_PROXY_PASSWORD].ConvertToSecureString(); // proxy.Credentials = new NetworkCredential(this[OPT_PROXY_USER], this[OPT_PROXY_PASSWORD]); } try { proxy.AddHost(this[OPT_HOST]); } catch { proxy.Dispose(); throw; } proxy.HttpProxy = proxyAddress; // proxy.Enabled = true; return proxy; } return null; } /// /// Add an argument to the valid argument list. /// /// Argument, Add an expected argument public void AddArg(Argument arg) { _arguments.Add(arg.Name.ToLower(), arg); } /// /// Add an argument to the valid argument list. /// /// string, argument name. /// bool, is value required /// bool, is mandatory argument /// public void AddArg(string name, bool hasValue, bool mandatory, string description = "") { _arguments.Add(name.ToLower(), new Argument(name.ToLower(), hasValue, mandatory, description)); } /// /// Add an argument to the valid argument list. /// /// string, argument name. /// bool, is value required /// bool, is mandatory argument /// public void AddStandAloneArg(string name, bool hasValue, bool mandatory, string description) { AddArg(new Argument(name.ToLower(), hasValue, mandatory, description)); StandAloneArguments.Add(name.ToLower()); } /// /// Check whether argument was given in the command line. /// /// argument name /// true if argument was selected public bool Selected(string name) { if (name != null && _arguments.ContainsKey(name.ToLower())) return _arguments[name.ToLower()].Selected; return false; } /// /// Indexer by argument name (only get) /// /// argument /// 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; } } #region GENERAL UTILS FUNCTIONS /// /// User input flags /// public enum YesNoFlag { YES, NO }; /// /// Perform y/n command (waiting for user input) /// /// The message to display /// The user choice public YesNoFlag AskYesNo(string message) { bool retry = false; // Indicates if the user input is correct YesNoFlag userFlag = YesNoFlag.NO; Console.Write("\n" + message + "[Y/N]? "); while (!retry) { string user_choice = Console.ReadLine(); if (string.Compare(user_choice, "y", true) == 0) { retry = true; userFlag = YesNoFlag.YES; } else if (string.Compare(user_choice, "n", true) == 0) { retry = true; userFlag = YesNoFlag.NO; } else Console.WriteLine("Invalid input, try again"); } return userFlag; } /// ///Change the Display Color for the User (waiting for user input) /// /// The message to display /// public void MessageDisplay_Color(string message, ConsoleColor color) { Console.ForegroundColor = color; Console.WriteLine("\n {0} ", message); Console.ForegroundColor = ConsoleColor.Gray; } #endregion #region INIT_FUNCTIONS /// ///Common INIT Functions for all samples /// public void init_functions() { AddArg(CmdLineArguments.OPT_HOST, true, true, string.Empty); // -host required AddArg(CmdLineArguments.OPT_PASS, true, false, string.Empty); // -pass optional AddArg(CmdLineArguments.OPT_USER, true, false, string.Empty); // -user optional AddArg(CmdLineArguments.OPT_SECURE, false, false, string.Empty); // -tls options AddArg(CmdLineArguments.OPT_WIRELESS, false, false, string.Empty); // -tls options AddArg(CmdLineArguments.OPT_KRB, false, false, string.Empty); // -kerberos options AddArg(CmdLineArguments.OPT_CERT, true, false, string.Empty); // -certificate options AddArg(CmdLineArguments.OPT_PROXY, true, false, string.Empty); // -proxy options AddArg(CmdLineArguments.OPT_VERBOSE, false, false, string.Empty); // -verbose options AddArg(CmdLineArguments.OPT_PROXY_USER, true, false, string.Empty); AddArg(CmdLineArguments.OPT_PROXY_PASSWORD, true, false, string.Empty); AddArg(CmdLineArguments.NO_RESTORE_OPTION, false, false, string.Empty); AddArg(CmdLineArguments.ACCEPT_SELF_SIGNED_CERTIFICATE, false, false, string.Empty); } #endregion #region CatchTypes public int catchType(System.Exception e, string usage) { exitCodes exitCode; if (e is Exception) { MessageDisplay_Color("\n--------------CmdLineArguments Exception--------------", ConsoleColor.Red); MessageDisplay_Color(e.Message, ConsoleColor.Red); MessageDisplay_Color(usage, ConsoleColor.Gray); exitCode = exitCodes.EXIT_USAGE; return (int)exitCode; } if (e is ArgumentException) { MessageDisplay_Color("\n--------------Argument Exception--------------", ConsoleColor.Red); MessageDisplay_Color(e.Message, ConsoleColor.Red); exitCode = exitCodes.EXIT_ARGUMENT_ERROR; return (int)exitCode; } if (e is FormatException) { Console.WriteLine("\n--------------DateTimeFormat Exception--------------"); Console.WriteLine(e.Message); exitCode = exitCodes.EXIT_FAILURE; return (int)exitCode; } if (e is WsmanConnectionException) { MessageDisplay_Color("\n ---------- WSMan Exception------------", ConsoleColor.Red); MessageDisplay_Color(e.Message, ConsoleColor.Red); exitCode = exitCodes.EXIT_FAILURE; return (int)exitCode; } if (e is WsmanUnreachableException) { MessageDisplay_Color("\n ---------- WSMan Exception------------", ConsoleColor.Red); MessageDisplay_Color(e.Message, ConsoleColor.Red); exitCode = exitCodes.EXIT_FAILURE; return (int)exitCode; } //General Exception - in case non of the above work. MessageDisplay_Color("\n--------------General Exception--------------", ConsoleColor.Red); MessageDisplay_Color(e.Message, ConsoleColor.Red); exitCode = exitCodes.EXIT_FAILURE; return (int)exitCode; } //end func #endregion } }