static void Main(string[] args) { string strURI = ""; string strAdminName = ""; string strPwd = ""; string strMailbox = ""; string strSubject = ""; string strGOID = ""; bool bUseSubject = true; bool bExact = false; DataSet dsMsgs = new DataSet("Messages"); Console.WriteLine(""); Console.WriteLine("================"); Console.WriteLine("Meeting Analyzer"); Console.WriteLine("================"); Console.WriteLine("Creates a timeline of a meeting and reports any problems found.\r\n"); Console.WriteLine("Enter a connection URI for remote powershell."); Console.WriteLine("You can leave this blank for Office 365 connections, or enter a"); Console.WriteLine("URI like \"https://outlook.office365.com/powershell-liveid\""); Console.Write("or \"https://yourdomain.onmicrosoft.com/powershell-liveid\" : "); strURI = Console.ReadLine(); if (string.IsNullOrEmpty(strURI)) { // >>> O365 - https://outlook.office365.com/powershell-liveid (from https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx) strURI = "https://outlook.office365.com/powershell-liveid"; } Console.WriteLine(""); // get the tenant admin Console.Write("Enter the tenant admin name (eg. [email protected]): "); strAdminName = Console.ReadLine(); // get the password Console.Write("Enter the password for {0}: ", strAdminName); // use below while loop to mask the password while reading it in bool bEnter = true; int iPwdChars = 0; while (bEnter) { ConsoleKeyInfo ckiKey = Console.ReadKey(true); if (ckiKey.Key == ConsoleKey.Enter) { bEnter = false; } else if (ckiKey.Key == ConsoleKey.Backspace) { if (strPwd.Length >= 1) { int oldLength = strPwd.Length; strPwd = strPwd.Substring(0, oldLength - 1); Console.Write("\b \b"); } } else { strPwd = strPwd + ckiKey.KeyChar.ToString(); iPwdChars++; Console.Write('*'); } } Console.WriteLine(""); // have to make the password secure for the connection SecureString secPwd = new SecureString(); foreach (char c in strPwd) { secPwd.AppendChar(c); } // get rid of the textual password as soon as we have the secure password. strPwd = ""; strPwd = null; // Now we have our username+password creds we can use for the connection PSCredential psCred = new PSCredential(strAdminName, secPwd); // Get rid of admin username now that the cred object is created strAdminName = ""; strAdminName = null; // Now make the connection object for the service Uri uriPS = new Uri(strURI); string strShellUri = "http://schemas.microsoft.com/powershell/Microsoft.Exchange"; WSManConnectionInfo connectionInfo = new WSManConnectionInfo(uriPS, strShellUri, psCred); connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic; connectionInfo.MaximumConnectionRedirectionCount = 5; Collection <PSObject> pshResults = new Collection <PSObject>(); // results collection object from running commands // Now do the connection and run PS commands using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo)) { PowerShell psh = PowerShell.Create(); Console.WriteLine("\r\nAttempting to connect to the service."); try { rs.Open(); psh.Runspace = rs; } catch (Exception ex) { Console.WriteLine("Could not open the remote powershell session."); Console.WriteLine("Error: " + ex.Message.ToString()); goto Exit; } Console.WriteLine("Successfully connected.\r\n"); //Get rid of the secure password, don't need it anymore. secPwd.Dispose(); secPwd = null; NextMtg: // Now get user and meeting info from the user Console.Write("Enter the SMTP address of the user for the meeting to analyze: "); strMailbox = Console.ReadLine(); Timeline.m_strMbx = strMailbox; // For printing out to screen later Utils.m_MBX = strMailbox; Console.Write("Enter the Subject of the meeting to analyze (leave blank to enter a Meeting ID instead): "); strSubject = Console.ReadLine(); if (string.IsNullOrEmpty(strSubject)) { Console.Write("Enter the Meeting ID (Global Object ID) of the problem meeting: "); strGOID = Console.ReadLine(); if (!(string.IsNullOrEmpty(strMailbox)) && !(string.IsNullOrEmpty(strGOID))) { Utils.CreateFile(strMailbox, strGOID); bUseSubject = false; } else { string strYN = "no"; Console.Write("\r\nSMTP address and Subject or Global Object ID must have values. Do you want to try again (yes/no)? "); strYN = Console.ReadLine().ToLower(); Console.WriteLine(); if (strYN.StartsWith("y")) { strMailbox = ""; Timeline.m_strMbx = ""; Utils.m_MBX = ""; strSubject = ""; strGOID = ""; goto NextMtg; } else { goto Exit; } } } else { strSubject = strSubject.Trim('"'); // remove quotes - they make things not work. Utils.m_Subject = strSubject; if (!(string.IsNullOrEmpty(strMailbox)) && !(string.IsNullOrEmpty(strSubject))) { Utils.CreateFile(strMailbox, strSubject); string strExact = "no"; Console.Write("Search for exact match on Subject? (yes/no): "); strExact = Console.ReadLine().ToLower(); if (strExact.StartsWith("y")) { bExact = true; } else { bExact = false; } } else { string strYN = "no"; Console.Write("\r\nSMTP address and Subject or Global Object ID must have values. Do you want to try again (yes/no)? "); strYN = Console.ReadLine().ToLower(); Console.WriteLine(); if (strYN.StartsWith("y")) { strMailbox = ""; Timeline.m_strMbx = ""; Utils.m_MBX = ""; strSubject = ""; strGOID = ""; goto NextMtg; } else { goto Exit; } } } Console.WriteLine("\r\nRunning command to retrieve the meeting data..."); // Run Get-CalendarDiagnosticObjects to get the version history data // Get-CalendarDiagnosticObjects -Identity <user smtp address> -Subject <meeting subject> -OutputProperties Custom -CustomPropertyNames ItemClass,NormalizedSubject... try { psh.AddCommand("Get-CalendarDiagnosticObjects"); psh.AddParameter("-Identity", strMailbox); if (bUseSubject) { psh.AddParameter("-Subject", strSubject); } else { psh.AddParameter("-MeetingId", strGOID); } if (bExact) { psh.AddParameter("-ExactMatch", 1); } //psh.AddParameter("-OutputProperties", "Custom"); psh.AddParameter("-CustomPropertyNames", Utils.rgstrPropsToGet); psh.AddParameter("-ShouldBindToItem", 1); pshResults = psh.Invoke(); } catch (Exception ex) { Console.WriteLine("\r\nUnable to process the Get-CalendarDiagnosticObjects command."); Console.WriteLine("Error: " + ex.Message.ToString()); goto Exit; } if (pshResults.Count > 0) { MsgData md = new MsgData(); Console.WriteLine("Successfully retrieved the meeting data.\r\n"); Timeline.m_iNumMsgs = pshResults.Count; Console.Write("Importing data from messages."); foreach (PSObject message in pshResults) { MsgData.PopulateDataSet(message); Console.Write("."); } Console.WriteLine("\r\nData import completed.\r\n"); } else { Console.WriteLine("No meeting data was retrieved. Check the user and meeting information and try again.\r\n"); psh.Commands.Clear(); pshResults.Clear(); Utils.Reset(); strGOID = ""; MsgData.m_GOID = ""; File.Delete(Utils.m_FilePath); goto NextMtg; } // we got the data imported - now we can sort by the Modified Time if (MsgData.m_bNoTime == false) { dsMsgs = MsgData.dsSort(MsgData.msgDataSet, "OrigModTime"); } // Create the timeline with the sorted messages Timeline.CreateTimeline(dsMsgs); Utils.CreateCSVFile(Utils.m_MBX, Utils.m_Subject); Utils.WriteMsgData(dsMsgs); Console.WriteLine("Timeline output written to: {0}", Utils.m_FilePath); Console.WriteLine("Calendar item property data written to: {0}", Utils.m_CSVPath); string strYesNo = "no"; //strYesNo = "no"; Console.Write("\r\nAnalyze data for another meeting (yes/no)? "); strYesNo = Console.ReadLine().ToLower(); Console.WriteLine(); if (strYesNo.StartsWith("y")) { dsMsgs.Clear(); psh.Commands.Clear(); pshResults.Clear(); Utils.Reset(); strGOID = ""; MsgData.m_GOID = ""; Console.WriteLine("=================================================="); Console.WriteLine(); goto NextMtg; } else { // clear out stuff dsMsgs.Clear(); psh.Commands.Clear(); pshResults.Clear(); Utils.Reset(); strGOID = ""; MsgData.m_GOID = ""; // close out the runspace since we're done. rs.Close(); rs.Dispose(); } } Exit: // Exit the app... Console.Write("\r\nExiting the program."); //Console.ReadLine(); }
} //PR_PARENT_DISPLAY // Get the value for a given property public string GetProp(string strName, string strProp = "PropVal") { return(MsgData.GetProp(m_dt, strName, strProp)); }