// 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;
}
}
}