From 99d7440134d0f33683d1150a770a2bc594be41de Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 8 Mar 2021 16:06:01 -0600 Subject: Port dependency tests from old repo. --- src/TestExe/Program.cs | 74 +++++++ src/TestExe/Task.cs | 471 +++++++++++++++++++++++++++++++++++++++++++++ src/TestExe/TestExe.csproj | 17 ++ src/TestExe/app.config | 10 + 4 files changed, 572 insertions(+) create mode 100644 src/TestExe/Program.cs create mode 100644 src/TestExe/Task.cs create mode 100644 src/TestExe/TestExe.csproj create mode 100644 src/TestExe/app.config (limited to 'src/TestExe') diff --git a/src/TestExe/Program.cs b/src/TestExe/Program.cs new file mode 100644 index 00000000..e92c413b --- /dev/null +++ b/src/TestExe/Program.cs @@ -0,0 +1,74 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TestExe +{ + class Program + { + static List tasks; + static int exitCodeToReturn = 0; + + static int Main(string[] args) + { + Usage(); + tasks = TaskParser.ParseTasks(args); + + foreach (Task t in tasks) + { + // special case for the ExitCodeTask + if (t.GetType() == typeof(ExitCodeTask)) + { + exitCodeToReturn = int.Parse(t.data); + } + else + { + t.RunTask(); + } + } + + Console.WriteLine("Exiting with ExitCode = {0}", exitCodeToReturn); + return exitCodeToReturn; + } + + static void Usage() + { + Console.WriteLine(@"TestExe.exe"); + Console.WriteLine(@""); + Console.WriteLine(@"TestExe can be passed various switches to define how it will behave and what tasks it will perform."); + Console.WriteLine(@"All switches are optional."); + Console.WriteLine(@"Any # of switches can be combined in any order."); + Console.WriteLine(@"Switches can be specified multiple times."); + Console.WriteLine(@"The order of the switches listed is the order they will be processed."); + Console.WriteLine(@"Info is written to stdout to describe what tasks are being performed as they are executed."); + Console.WriteLine(@""); + Console.WriteLine(@"Usage: TestExe.exe [tasks...]"); + Console.WriteLine(@""); + Console.WriteLine(@""); + Console.WriteLine(@"/ec # Exit code to return. Can only be specified once. If not specified, 0 will be returned. Example: “/ec 3010” would return 3010"); + Console.WriteLine(@"/s # Milliseconds to sleep before continuing. Example: “/s 5000” would sleep 5 seconds."); + Console.WriteLine(@"/sr #-# Random range of Milliseconds to sleep before continuing. Example: “/sr 5000-10000” would sleep between 5-10 seconds."); + Console.WriteLine(@"/log filename Create a log file called filename. Contents of the log are static text. Example: “/log %temp%\test.log” would create a %temp%\test.log file."); + Console.WriteLine(@"/Pinfo filename Create an xml file containing information about the process: PID, start time, user running the process, etc."); + Console.WriteLine(@"/fe filename Wait for a file to exist before continuing. Example: “/fe %temp%\cache\file.msi” would wait until %temp%\cache\file.msi exists."); + Console.WriteLine(@"/regw regkey,name,type,value (Re)writes a registry key with the specified value"); + Console.WriteLine(@"/regd regkey,[name] Deletes registry key name or key and all of its children (subkeys and values)"); + Console.WriteLine(@""); + Console.WriteLine(@"Example: "); + Console.WriteLine(@""); + Console.WriteLine(@"TestExe.exe /ec 1603 /Pinfo %temp%\Pinfo1.xml /s 1000 /log %temp%\log1.log /sr 5000-10000 /log %temp%\log2.log"); + Console.WriteLine(@""); + Console.WriteLine(@"This would result in the following execution:"); + Console.WriteLine(@" - Create an xml file with the current process info in it."); + Console.WriteLine(@" - Sleep 1 seconds"); + Console.WriteLine(@" - Create log1.log"); + Console.WriteLine(@" - Sleep between 5-10 seconds"); + Console.WriteLine(@" - Create log2.log"); + Console.WriteLine(@" - Exit with 1603"); + Console.WriteLine(@""); + } + } +} diff --git a/src/TestExe/Task.cs b/src/TestExe/Task.cs new file mode 100644 index 00000000..577acbea --- /dev/null +++ b/src/TestExe/Task.cs @@ -0,0 +1,471 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Management; +using System.Text; +using Microsoft.Win32; + +namespace TestExe +{ + public abstract class Task + { + public string data; + + public Task(string Data) + { + data = Data; + } + + public abstract void RunTask(); + + } + + public class ExitCodeTask : Task + { + public ExitCodeTask(string Data) : base(Data) { } + + public override void RunTask() + { + // this task does nothing. Just stores data about what exit code to return. + } + } + + public class SleepTask : Task + { + public SleepTask(string Data) : base(Data) { } + + public override void RunTask() + { + int milliseconds = int.Parse(this.data); + Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); + System.Threading.Thread.Sleep(milliseconds); + } + } + + public class SleepRandomTask : Task + { + public SleepRandomTask(string Data) : base(Data) { } + + public override void RunTask() + { + int low = int.Parse(data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[0]); + int high = int.Parse(data.Split(new string[] { ":" }, 2, StringSplitOptions.None)[1]); + + Random r = new Random(); + int milliseconds = r.Next(high - low) + low; + Console.WriteLine("Starting to sleep for {0} milliseconds", milliseconds); + System.Threading.Thread.Sleep(milliseconds); + } + } + + public class LogTask : Task + { + string[] argsUsed; + public LogTask(string Data, string[] args) + : base(Data) + { + argsUsed = args; + } + + public override void RunTask() + { + string logFile = ""; + string argsUsedString = ""; + + foreach (string a in argsUsed) + { + argsUsedString += a + " "; + } + + try + { + logFile = System.Environment.ExpandEnvironmentVariables(data); + Console.WriteLine("creating log file: " + logFile); + StreamWriter textFile = File.CreateText(logFile); + textFile.WriteLine("This is a log file created by TestExe.exe"); + textFile.WriteLine("Args used: " + argsUsedString); + textFile.Close(); + } + catch + { + Console.WriteLine("creating a log file failed for: {0}", logFile); + } + + } + } + + public class ProcessInfoTask : Task + { + public ProcessInfoTask(string Data) : base(Data) { } + + public override void RunTask() + { + try + { + string processInfoXml = ""; + + // Get information about the process and who is running it + Process thisProc = Process.GetCurrentProcess(); + string username = thisProc.StartInfo.EnvironmentVariables["username"].ToString(); + + int parentProcId = GetParentProcess(thisProc.Id); + Process parentProc = Process.GetProcessById(parentProcId); + string parentUsername = parentProc.StartInfo.EnvironmentVariables["username"].ToString(); + + int grandparentProcId = GetParentProcess(parentProc.Id); + Process grandparentProc = Process.GetProcessById(grandparentProcId); + string grandparentUsername = grandparentProc.StartInfo.EnvironmentVariables["username"].ToString(); + + processInfoXml += ""; + processInfoXml += " " + thisProc.ProcessName + ""; + processInfoXml += " " + thisProc.Id.ToString() + ""; + processInfoXml += " " + thisProc.SessionId.ToString() + ""; + processInfoXml += " " + thisProc.MachineName + ""; + // this stuff isn't set since we didn't start the process and tell it what to use. So don't bother + //processInfoXml += " "; + //processInfoXml += " " + thisProc.StartInfo.FileName + ""; + //processInfoXml += " " + thisProc.StartInfo.UserName + ""; + //processInfoXml += " " + thisProc.StartInfo.WorkingDirectory + ""; + //processInfoXml += " " + thisProc.StartInfo.Arguments + ""; + //processInfoXml += " "; + processInfoXml += " " + thisProc.StartTime.ToString() + ""; + processInfoXml += " " + username + ""; + processInfoXml += " "; + processInfoXml += " " + parentProc.ProcessName + ""; + processInfoXml += " " + parentProc.Id.ToString() + ""; + processInfoXml += " " + parentProc.StartTime.ToString() + ""; + processInfoXml += " " + parentUsername + ""; + processInfoXml += " "; + processInfoXml += " "; + processInfoXml += " " + grandparentProc.ProcessName + ""; + processInfoXml += " " + grandparentProc.Id.ToString() + ""; + processInfoXml += " " + grandparentProc.StartTime.ToString() + ""; + processInfoXml += " " + grandparentUsername + ""; + processInfoXml += " "; + processInfoXml += ""; + + string logFile = System.Environment.ExpandEnvironmentVariables(data); + Console.WriteLine("Creating Process Info data file: " + logFile); + StreamWriter textFile = File.CreateText(logFile); + textFile.WriteLine(processInfoXml); + textFile.Close(); + } + catch (Exception eX) + { + Console.WriteLine("Creating Process Info data file failed"); + Console.WriteLine(eX.Message); + } + + + } + + private static int GetParentProcess(int Id) + { + int parentPid = 0; + using (ManagementObject mo = new ManagementObject("win32_process.handle='" + Id.ToString() + "'")) + { + mo.Get(); + parentPid = Convert.ToInt32(mo["ParentProcessId"]); + } + return parentPid; + } + } + + public class FileExistsTask : Task + { + public FileExistsTask(string Data) : base(Data) { } + + public override void RunTask() + { + string fileToExist = System.Environment.ExpandEnvironmentVariables(data); + + if (!String.IsNullOrEmpty(fileToExist)) + { + Console.WriteLine("Waiting for this file to exist: \"" + fileToExist + "\""); + while (!System.IO.File.Exists(fileToExist)) + { + System.Threading.Thread.Sleep(250); + } + Console.WriteLine("Found: \"" + fileToExist + "\""); + } + + } + } + + /// + /// Task class that will create a registry key and write a name and value in it + /// + public class RegistryWriterTask : Task + { + private string hive; + private string keyPath; + private string[] keyPathArray; + private string name; + private RegistryValueKind regValueKind; + private object value; + + public RegistryWriterTask(string Data) : base(Data) { } + + public override void RunTask() + { + if (parseRegKeyNameTypeValue(System.Environment.ExpandEnvironmentVariables(data))) + { + RegistryKey rk = Registry.LocalMachine; + + if (hive == "HKCU") rk = Microsoft.Win32.Registry.CurrentUser; + if (hive == "HKCC") rk = Microsoft.Win32.Registry.CurrentConfig; + if (hive == "HKLM") rk = Microsoft.Win32.Registry.LocalMachine; + + foreach (string key in keyPathArray) + { + rk = rk.CreateSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree); + } + + rk.SetValue(name, value, regValueKind); + Console.WriteLine("Created registry key: '{0}' name: '{1}' value: '{2}' of type: '{3}'", + hive + "\\" + keyPath, + name, + value.ToString(), + regValueKind.ToString()); + } + else + { + Console.WriteLine("Unable to write registry key."); + } + + } + + private bool parseRegKeyNameTypeValue(string delimittedData) + { + string[] splitString = delimittedData.Split(new string[] { "," }, StringSplitOptions.None); + if (splitString.Length != 4) + { + Console.WriteLine("Invalid regkey. Unable to parse key,name,type,value from: \"" + delimittedData + "\""); + return false; + } + else + { + keyPath = splitString[0]; + name = splitString[1]; + string datatype = splitString[2]; + if (datatype == "DWord") + { + value = UInt32.Parse(splitString[3]); + } + else if (datatype == "QWord") + { + value = UInt64.Parse(splitString[3]); + } + else + { + value = splitString[3]; + } + + if (keyPath.ToUpper().StartsWith("HKLM\\")) + { + hive = "HKLM"; + keyPath = keyPath.Replace("HKLM\\", ""); + } + else if (keyPath.ToUpper().StartsWith("HKCC\\")) + { + hive = "HKCC"; + keyPath = keyPath.Replace("HKCC\\", ""); + } + else if (keyPath.ToUpper().StartsWith("HKCU\\")) + { + hive = "HKCU"; + keyPath = keyPath.Replace("HKCU\\", ""); + } + else + { + Console.WriteLine("Invalid regkey. Unable to determin hive. regkey must start with either: [HKLM], [HKCU], or [HKCC]"); + return false; + } + keyPathArray = keyPath.Split(new string[] { "\\" }, StringSplitOptions.None); + + try + { + regValueKind = (RegistryValueKind)System.Enum.Parse(typeof(RegistryValueKind), datatype); + } + catch (Exception ex) + { + Console.WriteLine("Invalid datatype. It must be: String, DWord, or QWord (case sensitive)"); + Console.WriteLine(ex.Message); + return false; + } + } + return true; + } + } + + /// + /// Task class that will delete a registry key value or registry key and all of its children + /// + public class RegistryDeleterTask : Task + { + private string hive; + private string keyPath; + private string[] keyPathArray; + private string name; + + public RegistryDeleterTask(string Data) : base(Data) { } + + public override void RunTask() + { + if (parseRegKeyName(System.Environment.ExpandEnvironmentVariables(data))) + { + try + { + RegistryKey rk = Registry.LocalMachine; + + if (hive == "HKCU") rk = Microsoft.Win32.Registry.CurrentUser; + if (hive == "HKCC") rk = Microsoft.Win32.Registry.CurrentConfig; + if (hive == "HKLM") rk = Microsoft.Win32.Registry.LocalMachine; + + RegistryKey rkParent = null; + foreach (string key in keyPathArray) + { + rkParent = rk; + rk = rk.OpenSubKey(key, true); + } + + if (String.IsNullOrEmpty(name)) + { + // delete the key and all of its children + string subkeyToDelete = keyPathArray[keyPathArray.Length - 1]; + rkParent.DeleteSubKeyTree(subkeyToDelete); + Console.WriteLine("Deleted registry key: '{0}'", hive + "\\" + keyPath); + } + else + { + // just delete this value + rk.DeleteValue(name); + Console.WriteLine("Deleted registry key: '{0}' name: '{1}'", hive + "\\" + keyPath, name); + } + } + catch (Exception ex) + { + Console.WriteLine("Unable to delete registry key: '{0}'", hive + "\\" + keyPath); + Console.WriteLine(ex.Message); + } + } + else + { + Console.WriteLine("Unable to delete registry key."); + } + + } + + private bool parseRegKeyName(string delimittedData) + { + string[] splitString = delimittedData.Split(new string[] { "," }, StringSplitOptions.None); + + if (splitString.Length > 2) + { + Console.WriteLine("Unable to parse registry key and name."); + return false; + } + + keyPath = splitString[0]; + if (splitString.Length == 2) + { + name = splitString[1]; + } + + if (keyPath.ToUpper().StartsWith("HKLM\\")) + { + hive = "HKLM"; + keyPath = keyPath.Replace("HKLM\\", ""); + } + else if (keyPath.ToUpper().StartsWith("HKCC\\")) + { + hive = "HKCC"; + keyPath = keyPath.Replace("HKCC\\", ""); + } + else if (keyPath.ToUpper().StartsWith("HKCU\\")) + { + hive = "HKCU"; + keyPath = keyPath.Replace("HKCU\\", ""); + } + else + { + Console.WriteLine("Invalid regkey. Unable to determine hive. regkey must start with either: [HKLM], [HKCU], or [HKCC]"); + return false; + } + keyPathArray = keyPath.Split(new string[] { "\\" }, StringSplitOptions.None); + return true; + } + } + + public class TaskParser + { + + public static List ParseTasks(string[] args) + { + List tasks = new List(); + + try + { + // for invalid args. return empty list + if (args.Length % 2 == 0) + { + Task t; + + for (int i = 0; i < args.Length; i += 2) + { + switch (args[i].ToLower()) + { + case "/ec": + t = new ExitCodeTask(args[i + 1]); + tasks.Add(t); + break; + case "/s": + t = new SleepTask(args[i + 1]); + tasks.Add(t); + break; + case "/sr": + t = new SleepRandomTask(args[i + 1]); + tasks.Add(t); + break; + case "/log": + t = new LogTask(args[i + 1], args); + tasks.Add(t); + break; + case "/pinfo": + t = new ProcessInfoTask(args[i + 1]); + tasks.Add(t); + break; + case "/fe": + t = new FileExistsTask(args[i + 1]); + tasks.Add(t); + break; + case "/regw": + t = new RegistryWriterTask(args[i + 1]); + tasks.Add(t); + break; + case "/regd": + t = new RegistryDeleterTask(args[i + 1]); + tasks.Add(t); + break; + + default: + Console.WriteLine("Error: Invalid switch specified."); + return new List(); + } + } + } + } + catch + { + Console.WriteLine("Error: Invalid switch data specified. Couldn't parse the data."); + return new List(); + } + + return tasks; + } + } +} diff --git a/src/TestExe/TestExe.csproj b/src/TestExe/TestExe.csproj new file mode 100644 index 00000000..933fa932 --- /dev/null +++ b/src/TestExe/TestExe.csproj @@ -0,0 +1,17 @@ + + + + + + net35 + TestExe + TestExe + Exe + embedded + win-x86 + + + + + + \ No newline at end of file diff --git a/src/TestExe/app.config b/src/TestExe/app.config new file mode 100644 index 00000000..f9811b74 --- /dev/null +++ b/src/TestExe/app.config @@ -0,0 +1,10 @@ + + + + + + + + + + -- cgit v1.2.3-55-g6feb