using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Configuration; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Media; using System.Net; using System.Net.Mail; using System.Reflection; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Text; using System.Timers; using System.Windows.Forms; using CustomMessageBox; namespace AutomationMonitor { public partial class AutomationMonitorMain : Form { string application = ""; string applicationPath = @"" + ConfigurationManager.AppSettings["appPath"]; string logFile = ""; string logFilePath = @"" + ConfigurationManager.AppSettings["logFilePath"]; // for testing string sandBoxPath = @"" + ConfigurationManager.AppSettings["sandBoxPath"]; string localAppPath = @"" + ConfigurationManager.AppSettings["localAppPath"]; string emergencyPath = @"" + ConfigurationManager.AppSettings["emergencyPath"]; string fbProdPath = @"" + ConfigurationManager.AppSettings["fbProdPath"]; double delayTime = Convert.ToDouble(ConfigurationManager.AppSettings["delayTime"]); double fbFedExpireDay = Convert.ToDouble(ConfigurationManager.AppSettings["fbFedExpireDay"]); string downApp = ""; //string labelSubtitle = ""; List appsList = new List(); //Populated with apps List processList = new List(); bool driveScanFail = false; //boolean to show whether or not network drives were available during scan int failCount = 0; int runCount = 0; bool emergencyFlag = false; //boolean to check if auto mode detected drive(s) down/unavailable //if this is on, GemaltoNET will try to process again in 10 minutes //Var to hold on to regular time. Used in regular auto mode processing. DateTime autoTime; //Var to hold on to time. Used in emergency mode. DateTime emergencyTime; //Email timers (using these to control how many times Boomerang error emails are sent out) DateTime driveScanFailTimeStamp = new DateTime(); DateTime folderScanFailTimeStamp = new DateTime(); DateTime last_driveScanFailTimeStamp = DateTime.MinValue; DateTime last_folderScanFailTimeStamp = DateTime.MinValue; WMPLib.WindowsMediaPlayer player = new WMPLib.WindowsMediaPlayer(); public AutomationMonitorMain() { InitializeComponent(); //load known apps string[] appsPaths = ConfigurationManager.AppSettings.AllKeys; foreach (string key in appsPaths) { if (key.StartsWith("appMon")) { appsList.Add(ConfigurationManager.AppSettings[key]); } } } private void AutomationMonitorMain_Load(object sender, EventArgs e) { dennisNedryCode(); this.Text = Application.ProductName + " v. " + Application.ProductVersion; statusStripStatusLabel.Text = Application.ProductName + " v. " + Application.ProductVersion + " loaded."; AddMsg(statusStripStatusLabel.Text); statusStripStatusLabel.Text = "Authored by J. Edwards, 2015. Rights applicable."; AddMsg(statusStripStatusLabel.Text); writeToLog("AutomationMonitor started."); // --- Sets Auto mode by default, to coincide with the checked state on the form timerAutoMode.Enabled = true; autoTime = DateTime.Now.AddMinutes(1D);// 1 minute startAutoMonitor(); } //-------------------------------------------------------------------------------------------------// private void AutomationMonitorMain_Resize(object sender, EventArgs e) { if (FormWindowState.Minimized == this.WindowState) { notifyIconAutomationMonitor.Visible = true; this.Hide(); } } private void notifyIconAutomationMonitor_MouseClick(object sender, MouseEventArgs e) { this.Show(); notifyIconAutomationMonitor.Visible = false; this.WindowState = FormWindowState.Normal; } //-------------------------------------------------------------------------------------------------// /// /// Start Automonitor /// Function to run the app in auto mode. /// private void startAutoMonitor() { /************************************************************************************** * Current autoprocessing checks to see if the program is busy when running normally; * * it will not check to see if the program is busy when running emergency mode * * (maybe check to see if emergency mode is busy, OR lock everything else to prevent * * any other programs from running in emergency mode?) * **************************************************************************************/ if (emergencyFlag == false) //If auto mode has not detected any critical errors... { if (((autoTime.Hour == DateTime.Now.Hour) && (autoTime.Minute == DateTime.Now.Minute) && (autoTime.Second == DateTime.Now.Second))) //We've waited and now the auto-run process begins... { statusStripStatusLabel.Text = "AutomationMonitor is checking applications, please stand by..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); runningCode(); if (driveScanFail == false) //Run successful! Drives, folders, files 100% analyzed, checked, and iterated) { autoTime = DateTime.Now.AddMinutes(delayTime); //i.e. - Next run will be in 10 minutes } } else { labelAutoTime.Text = "Next autorun is at " + autoTime.Hour.ToString("00") + ":" + autoTime.Minute.ToString("00") + ":" + autoTime.Second.ToString("00") + "; Currently " + DateTime.Now.Hour.ToString("00") + ":" + DateTime.Now.Minute.ToString("00") + ":" + DateTime.Now.Second.ToString("00"); } } else // autoprocess detected down/unavailable drive(s); time will be given to restart process... { if (emergencyTime == DateTime.Now) //If the emergency timeframe has passed, it's time to re-run again... { statusStripStatusLabel.Text = "Auto Mode emergency restart activated..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); emailEmergency(statusStripStatusLabel.Text, ""); runningCode(); if (driveScanFail == false) //Run successful! //(Drives, folders, and files were 100% analyzed, checked, and iterated; we can exit emergency mode...) { emergencyFlag = false; //Turn off emergency mode... autoTime = DateTime.Now.AddMinutes(delayTime); //i.e. - Next run will be in 10 minutes statusStripStatusLabel.Text = "Auto Mode emergency restart successful, now deactivating Emergency Mode..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } } else { labelAutoTime.Text = "Emergency run at: " + emergencyTime.ToString("HH:mm:ss") + " Time now: " + DateTime.Now.ToString("HH:mm:ss"); } } } /// /// Main method /// runningCode() /// private void runningCode() { ////////////////////////////////////////////////////////////// //STEP 1: Check to make sure the network location are there // ////////////////////////////////////////////////////////////// checkDrives(); ////////////////////////////////////////////////////// //STEP 2: Check to see the applications are running // ////////////////////////////////////////////////////// checkApps(); //////////////////////////////////////////////////// //STEP 3: Check for stale FedEx firebirds file(s) // //////////////////////////////////////////////////// checkFirebirds(); //////////////////////////////////////////// //STEP 4: Clean up and reset for next run // //////////////////////////////////////////// endMonitorRun(); } /// /// Check Drives /// Function to check the network status of mapped drives. /// private void checkDrives() { statusStripStatusLabel.Text = "AutomationMonitor is checking drive locations, please stand by..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); foreach (string app in appsList) { // Check app if (!Directory.Exists(sandBoxPath + "\\" + app)) { statusStripStatusLabel.Text = app + " application path cannot be reached."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); //driveScanFail = true; failCount++; if (failCount > 1) { downApp += app + ","; } else { downApp = app; } } } if (failCount > 0) { driveScanFail = true; } if (driveScanFail == true) //If checkDrives() produced a bad scan because a location was down/unavailable... { statusStripStatusLabel.Text = downApp + "'s network location is unavailable."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); if ((last_driveScanFailTimeStamp == DateTime.MinValue) || (last_driveScanFailTimeStamp.AddMinutes(60) > DateTime.Now)) { emailEmergency("WARNING!!!\n\n" + "AutomationMonitor has detected that " + downApp + " is " + "unavailable, or has encountered a system error while checking drives at " + DateTime.Now + ".\n\n" + "Please check network drives and/or the log file as soon as possible.\n\n" + "AutomationMonitor is now in Emergency Mode, running automation apps locally.\n\n", downApp); last_driveScanFailTimeStamp = driveScanFailTimeStamp; } emergencyFlag = true; //Emergency mode activated and will continue until problem is solved 2012-11-23 emergencyTime = DateTime.Now.AddMinutes(10D); //Exit the function return; } else { statusStripStatusLabel.Text = "Network folders are currently available."; AddMsg(statusStripStatusLabel.Text); //writeToLog(statusStripStatusLabel.Text); } } /// /// Check Apps /// Function to check if apps are running. /// private void checkApps() { //load a list with running processes foreach (Process runningProcesses in Process.GetProcesses()) { processList.Add(runningProcesses.ProcessName); } //compare processes to what should be running foreach (string app in appsList) { //if an app isn't running if (!processList.Contains(app)) { try { // if network locales are up if (driveScanFail == false) { //run the app from the network ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.WorkingDirectory = sandBoxPath + "\\" + app; startInfo.CreateNoWindow = false; startInfo.UseShellExecute = false; startInfo.FileName = startInfo.WorkingDirectory + "\\" + app + ".exe"; startInfo.WindowStyle = ProcessWindowStyle.Minimized; if (app == "Boomerang" || app == "LabelMonitor")//added since the lock file feature was added to Boomerang. (2017-05-08) { startInfo.Arguments = "/auto"; } Process.Start(startInfo); statusStripStatusLabel.Text = app + " was not running. AutomationMonitor has restarted it."; } // if network locales are down else if (driveScanFail == true || emergencyFlag == true) { //run the app from the local drive //appStartLocal(app); //this feature has been disabled at this time (2017-05-18, jae) //statusStripStatusLabel.Text = app + " was not running and the network is down! AutomationMonitor has restarted it locally."; statusStripStatusLabel.Text = app + " was not running and the network is down! AutomationMonitor cannot restart it locally."; } //statusStripStatusLabel.Text = app + " was not running. AutomationMonitor has restarted it."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } catch (Exception strt) { statusStripStatusLabel.Text = app + " was not running and could not be started!"; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + strt.ToString()); //emailEmergency(""); try { //then start a local copy of the app //appStartLocal(app); //this feature has been disabled at this time (2017-05-18, jae) //statusStripStatusLabel.Text = app + " was not running from the network, but was started locally."; statusStripStatusLabel.Text = app + " was not running from the network and was NOT started locally."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } catch { statusStripStatusLabel.Text = "WARNING! - " + app + " was not running from the network and could not be started locally either!"; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + strt.ToString()); } } } //what if a network app is running and the network goes down? else if (driveScanFail == true || emergencyFlag == true) { //check for 'stale' apps running from memory foreach (Process staleProcess in Process.GetProcessesByName(app)) { try { //kill all 'stale' apps staleProcess.Kill(); statusStripStatusLabel.Text = "A 'stale' copy of " + app + " was running from the network and had to be killed."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } catch (Exception spk) { statusStripStatusLabel.Text = "A 'stale' copy of " + app + " was running and could not be restarted locally."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + spk.ToString()); } } try { //then restart a local copy of the app //appStartLocal(app); //this feature has been disabled at this time (2017-05-18, jae) //statusStripStatusLabel.Text = "A local copy of " + app + " was successfully restarted."; statusStripStatusLabel.Text = "A local copy of " + app + " was NOT restarted."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } catch (Exception lrst) { statusStripStatusLabel.Text = "A local copy of " + app + " could not be started!"; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + lrst.ToString()); } } else //app is already running { statusStripStatusLabel.Text = app + " is running."; AddMsg(statusStripStatusLabel.Text); } } } /// /// Check Firebirds /// Function to check the ftp Production folder for /// FedEx files to update tracking info if older than three days /// private void checkFirebirds() { if (checkBoxAutoMode.Checked == true && runCount == 0) { try { statusStripStatusLabel.Text = "AutomationMonitor's Firebirds FedEx file scan starting."; AddMsg(statusStripStatusLabel.Text); string[] fedExFiles = Directory.GetFiles(fbProdPath); List expiredFiles = new List(); ; foreach (string file in fedExFiles) { FileInfo fi = new FileInfo(file); if ((fi.LastWriteTime < DateTime.Now.AddDays(fbFedExpireDay * -1)) && (fi.Name.ToUpper().Contains("FEDEX"))) { expiredFiles.Add(file); } } if (expiredFiles.Count > 1) { string oldFiles = ""; for (int i = 0; expiredFiles.Count > i; i++) { if (i != (expiredFiles.Count - 1)) { oldFiles += expiredFiles[i] + ", "; } else { oldFiles += expiredFiles[i] + "."; } } emailEmergency("Firebirds fedex files " + oldFiles + " are older than " + fbFedExpireDay + " days.\r\n" + "Request an update from shipping and/or CSRs.", "Firebirds FedEx Tracking"); } else if (expiredFiles.Count == 1) { emailEmergency("Firebirds fedex file " + expiredFiles[0] + " is older than " + fbFedExpireDay + " days.\r\n" + "Request an update from shipping and/or CSRs.", "Firebirds FedEx Tracking"); } else if (expiredFiles.Count == 0) { statusStripStatusLabel.Text = "No Firebirds FedEx files found."; AddMsg(statusStripStatusLabel.Text); } } catch (Exception ex) { statusStripStatusLabel.Text = "AutomationMonitor's Firebirds FedEx file scan failed."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + "\r\n" + ex.ToString()); } } if (runCount == 5)// each run is 10 min, making this an hourly check { runCount = 0; //AddMsg("Firebirds FedEx check run count reset to " + runCount.ToString()); } else { runCount++; //AddMsg("Firebirds FedEx check run count - " + runCount.ToString()); } } private void appStartLocal(string app) { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.WorkingDirectory = localAppPath + "\\" + app + "\\" + app; startInfo.CreateNoWindow = false; startInfo.UseShellExecute = false; startInfo.FileName = startInfo.WorkingDirectory + "\\bin\\Debug\\" + app + ".exe"; startInfo.WindowStyle = ProcessWindowStyle.Normal; Process.Start(startInfo); } /// /// Checkbox Automode /// Function to toggle the auto mode. /// private void checkBoxAutoMode_CheckedChanged(object sender, EventArgs e) { if (timerAutoMode.Enabled == false) { timerAutoMode.Enabled = true; autoTime = DateTime.Now.AddMinutes(1D); //startAutoMonitor(); buttonRun.Enabled = false; statusStripStatusLabel.Text = "Auto mode: online."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } else { timerAutoMode.Enabled = false; labelAutoTime.Text = "Auto mode: offline!"; buttonRun.Enabled = true; statusStripStatusLabel.Text = "Auto mode: offline!"; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } } private void timerAutoMode_Tick(object sender, EventArgs e) { if (emergencyFlag == false) //If auto mode has not detected any down/unavailable drives after just running... { startAutoMonitor(); } else //RepOrder's autoprocess detected down/unavailable drive(s); time will be given to restart process { if (emergencyTime == DateTime.Now) //If the emergency timeframe has passed, it's time to re-run again... { statusStripStatusLabel.Text = "Auto mode emergency restart activated..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); startAutoMonitor(); if (driveScanFail == false) //This run was successful, we can exit emergency mode { emergencyFlag = false; //Turn off emergency mode statusStripStatusLabel.Text = "Auto mode emergency restart successful, emergency mode off..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); } } else { labelAutoTime.Text = "Emergency run at: " + emergencyTime.ToString("HH:mm:ss") + " Time now: " + DateTime.Now.ToString("HH:mm:ss"); } } } /// /// Add Message /// Function to update the status box with information or program progress. /// /// Message to be displayed in status box private void AddMsg(string msgData) { listBoxStatus.Items.Add(msgData/* + " (" + DateTime.Now.ToLongTimeString() + ")"*/); listBoxStatus.SetSelected(listBoxStatus.Items.Count - 1, true); //auto-scroll listbox //auto clean up... if more than 500 lines of text exist in the status box, remove them starting with the oldest record if (listBoxStatus.Items.Count > 500) { listBoxStatus.Items.RemoveAt(0); } } /// /// Write To Log /// Function which creates and appends to a log file showing status updates over time. /// /// Status box message to be added to log file private void writeToLog(string information) { logFile = logFilePath + "\\" + DateTime.Today.ToString("yyyyMMdd") + "_logfile.txt"; try { using (StreamWriter w = File.AppendText(logFile)) { w.WriteLine(" {0}: {1}", DateTime.Now, information); } } catch { statusStripStatusLabel.Text = "Unable to write to log! Please check log file..."; AddMsg(statusStripStatusLabel.Text); } } /// /// Dennis Nedry programmed the "Magic Word" lockdown code for Jurassic Park. It was essentially unbreakable without a reboot. /// This code is even stronger! Reboots have no effect. It is so named in the honor of his untimely death, due to natural causes. /// Add a reference to CustomMessageBox.dll in this program as well as /// add these "using" decalarations to the head of this code page - using System.Reflection; using CustomMessageBox; /// Call this code first, in the Load() or Show() of this program. /// Make sure the custom message icon you use is 64x64 and that it and the sound file jurass01.mp3 are in the root output folder. /// private void dennisNedryCode() { //check to see if this program is already open //block all other attempts to load another instance of itself //if (Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)).Length > 1) { player.URL = "jurass01.mp3"; player.controls.play(); player.settings.playCount = 3; CustomMessageBox.CustomMessageBox.Show(Application.ProductName + " is already running. This instance will not load." + Environment.NewLine + "YOU DIDN'T SAY THE MAGIC WORD!" + Environment.NewLine + "YOU DIDN'T SAY THE MAGIC WORD!" + Environment.NewLine + "YOU DIDN'T SAY THE MAGIC WORD!" + Environment.NewLine + "YOU DIDN'T SAY THE MAGIC WORD!" + Environment.NewLine + "YOU DIDN'T SAY THE MAGIC WORD!", "Ahh, Ahh, Ahhhh...! " + Application.ProductName + " is already running!", CustomMessageBox.CustomMessageBox.eDialogButtons.OK, Image.FromFile("dNedry2.gif")); Application.Exit(); } } /// /// Log File Trim /// Trim the log file before closing /// /// Keep the log file at 10000 lines. private void logFileTrim() { string[] lines = File.ReadAllLines(logFile); Array.Reverse(lines); //flip the contents ArrayList remStrings = new ArrayList(); remStrings.AddRange(lines); //load the flipped array into an array list for line removal remStrings.RemoveRange(10000, /*logLineCount*/remStrings.Count - 10000); //retains a line count of 10000 string[] newLines = remStrings.ToArray(typeof(string)) as string[]; Array.Reverse(newLines); //flip contents for rewriting File.WriteAllLines(logFile, newLines); //removes the first lines of the log } /// /// Email Emergency /// Method to send emergency emails to MIS. /// /// String which holds message body to be emailed to MIS. private void emailEmergency(string message, string batch) { bool emailSentOK = false; //just to make sure emergency email was sent 2013-10-22 bool emailBackupPlanDidNotWork = false; //if there is a problem sending email, so we don't infinitely loop 2013-10-22 int numberOfTries = 1; //how many times we tried to send email 2013-10-22 while ((emailSentOK == false) && (emailBackupPlanDidNotWork == false)) { try { MailMessage oMsg = new MailMessage(); oMsg.From = new MailAddress("mis@cpscards.com"); //oMsg.To.Add("mis@cpscards.com"); //Send email to MIS 2012-11-23 //oMsg.To.Add("schamlee@cpscards.com"); //Send email to MIS 2013-10-31 //oMsg.To.Add("jedwards@cpscards.com"); //Send email to MIS 2013-10-31 //oMsg.To.Add("6107517747@tmomail.net"); //send text msg to Jay string[] appSettings = ConfigurationManager.AppSettings.AllKeys; foreach (string key in appSettings) { if (key.ToLower().StartsWith("alertmailto")) { oMsg.To.Add(ConfigurationManager.AppSettings[key]); } } if (string.IsNullOrEmpty(batch)) { oMsg.Subject = "CPS AutomationMonitor - Emergency MIS Notice"; } else { oMsg.Subject = "CPS AutomationMonitor - Emergency MIS Notice - App: " + batch; } //Body of email (passed in to emailNetworkDrivesError method) oMsg.Body = message + "\r\n\n Origin: " + Environment.MachineName + " (" + Environment.UserName + ")" + "\n\nFor more details, follow this link to the log: " + logFile; oMsg.Priority = MailPriority.High; SmtpClient mySMTP = new SmtpClient(ConfigurationManager.AppSettings["smtp"]); mySMTP.Credentials = new NetworkCredential("gemaltonet@cpscards.com", "sonsverb1"); mySMTP.Send(oMsg); oMsg = null; emailSentOK = true; //email was sent ok, we can break out of while loop 2013-10-22 } catch (Exception e) { statusStripStatusLabel.Text = "Error occurred when sending emergency email, attempt " + numberOfTries.ToString() + "..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text + e.ToString()); System.Threading.Thread.Sleep(3000); //wait three seconds before trying again numberOfTries++; if (numberOfTries > 21) //if we tried to send emergency email for 60 seconds solid and failed... { emailBackupPlanDidNotWork = true; } } } if (emailBackupPlanDidNotWork == true) //Email failed to send after a period of time { statusStripStatusLabel.Text = "Emergency email backup loop failed (email was not sent)..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); numberOfTries = 0; } } private void buttonExit_Click(object sender, EventArgs e) { writeToLog("AutomationMonitor closing.\n\n----------------------------------------\n"); Application.Exit(); } private void buttonRun_Click(object sender, EventArgs e) { statusStripStatusLabel.Text = "Manual restart commencing..."; AddMsg(statusStripStatusLabel.Text); writeToLog(statusStripStatusLabel.Text); runningCode(); } private void endMonitorRun() { processList.Clear(); driveScanFail = false; failCount = 0; statusStripStatusLabel.Text = "Ready."; AddMsg("Monitor run complete."); } #region ToolStrip Menu Items private void runToolStripMenuItem1_Click(object sender, EventArgs e) { buttonRun_Click(sender, e); } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { buttonExit_Click(sender, e); } private void usingAutoMonToolStripMenuItem_Click(object sender, EventArgs e) { Process.Start(@"" + ConfigurationManager.AppSettings["manualFile"]); } private void aboutAutoMonToolStripMenuItem_Click(object sender, EventArgs e) { aboutAutoMon about = new aboutAutoMon(); about.ShowDialog(this); } #endregion } }