To start off, this is an application I use almost daily. It's very simply titled Remote HealthCheck. As implied by the name, it remotely checks the "health" of computers in your environment. This uses WMI calls, Active Directory searches, UNC paths, etc to gather information about a computer and it's state. We will also create our own dll for storing commonly used functions. Of course, you'll need to modify based on your environment. When done, you'll also be able to search Active Directory and query an entire OU.

https://lh4.googleus.../s1152/rhc5.jpg
Part 1: Create your functions library
The reason I created a functions library is because most of these functions I use in many of my projects, so it's nice to just be able to reference this library and call the functions, without having to rewrite them.
Step 1: Create a new library project.
Mine is named THRFunctions... my company and Functions... unoriginal I know, but simple and to the point.
Step 2: Add your references
Add a reference to System.DirectoryServices. This allows us to work with Active Directory. Also, a reference to System.Management (can't remember if this is automatic or not.. but whatever)
Step 3: Code your library
Alright, here's the fun part. We need to create our functions that will be used for our projects.
When you copy / paste this into your IDE, you will find some errors. I placed these there on purpose because these are things YOU need to fill in based on your environment.
using System; using System.Collections.Generic; using System.Text; using System.DirectoryServices; using System.Threading; using System.Diagnostics; using System.Runtime.InteropServices; using Microsoft.Win32; using System.Windows.Forms; using System.Management; using System.Collections; using System.Net.NetworkInformation; namespace THRFunctions { public class clsMain { public enum objectClass { user, group, computer } public enum returnType { distinguishedName, ObjectGUID } /// <summary> /// Opens a directory entry connection for use with Active Directory /// </summary> /// <returns>Connection to Active Directory</returns> public DirectoryEntry createDirectoryEntry() { //Create our AD connection DirectoryEntry ldapConnection = new DirectoryEntry(<your_domain>); ldapConnection.Path = "LDAP://DC="<your_domain_LDAP_path>; ldapConnection.AuthenticationType = AuthenticationTypes.Secure; return ldapConnection; } /// <summary> /// Checks Active Directory for users admin status /// </summary> /// <returns>true / false</returns> public bool isAdmin() { string username = Environment.UserName; DirectoryEntry myLdapConnection = createDirectoryEntry(); DirectorySearcher search = new DirectorySearcher(myLdapConnection); search.SearchRoot = myLdapConnection; search.Filter = "(samaccountname=" + username + ")"; bool admin = false; try { SearchResult result = search.FindOne(); if (result != null) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { if (myCollection.ToString().Contains(<a group in AD that tells us the user is an admin>)) admin = true; } } } else { admin = false; } } catch { admin = false; } search.Dispose(); return admin; } /// <summary> /// Gets the short OU of a computer in Active Directory /// </summary> /// <param name="pcname">Name of the computer to lookup in Active Directory</param> /// <returns>Short OU of computer</returns> public string getOU(string pcname) { SearchResult result; string OU = ""; DirectoryEntry myLdapConnection = createDirectoryEntry(); DirectorySearcher search = new DirectorySearcher(myLdapConnection); search.SearchRoot = myLdapConnection; search.Filter = "(&(objectClass=computer)(Name=" + pcname + "))"; try { result = search.FindOne(); } catch { result = null; OU = "Standard"; } if (result != null) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { if (ldapField == "distinguishedname") { string DN = myCollection.ToString(); if (DN.Length > 1) { try { DN = (myCollection.ToString()).Substring((DN.IndexOf("OU=")) + 3); OU = DN.Remove((DN.IndexOf(",OU"))); if (OU.Contains("Standard")) OU = "None"; } catch { OU = "None"; } } else OU = "None"; } } } } search.Dispose(); return OU; } /// <summary> /// Gets the full distinguished name of a computer from Active Directory /// </summary> /// <param name="pcname">Name of the computer to lookup in Active Directory</param> /// <returns>DN of computer</returns> public string getDN(string pcname) { SearchResult result; string DN = ""; DirectoryEntry myLdapConnection = createDirectoryEntry(); DirectorySearcher search = new DirectorySearcher(myLdapConnection); search.SearchRoot = myLdapConnection; search.Filter = "(&(objectClass=computer)(Name=" + pcname + "))"; try { result = search.FindOne(); } catch { result = null; DN = "Not Found"; } if (result != null) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { if (ldapField == "distinguishedname") { DN = myCollection.ToString(); } } } } search.Dispose(); return DN; } /// <summary> /// Moves the computers OU in Active Directory /// </summary> /// <param name="type">What the computer is used for</param> /// <param name="entity">What site the computer is at</param> /// <param name="DN">The full DN of the computer</param> /// <returns>Success / Fail</returns> public bool moveOU(string type, string entity, string DN) { string strContainer; try { <MODIFY THIS SECTION TO FIT YOUR ENVIRONMENT> if (entity == "THPG" || entity == "THHV") strContainer = ("LDAP://OU=" + type + " " + entity + ",OU=Workstations,OU=" + entity + ",DC="<YOURDOMAIN>,DC=<YOURDOMAIN>"); else strContainer = ("LDAP://OU=" + type + " " + entity + ",OU=" + entity + ",OU=THR Workstations,DC="<YOURDOMAIN>"); DirectoryEntry eLocation = new DirectoryEntry("LDAP://" + DN); DirectoryEntry nLocation = new DirectoryEntry(strContainer); string newName = eLocation.Name; eLocation.MoveTo(nLocation, newName); nLocation.Close(); eLocation.Close(); MessageBox.Show(" Your Workstation is now in: " + strContainer); return true; } catch (Exception ex) { MessageBox.Show(ex.Message, "MoveOU"); return false; } } /// <summary> /// Moves the computers OU in Active Directory /// </summary> /// <param name="type">What the computer is used for</param> /// <param name="entity">What site the computer is at</param> /// <returns>Success / Fail</returns> public bool moveOU(string type, string entity) { string strContainer; try { <MODIFY THIS SECTION TO FIT YOUR ENVIRONMENT> if (entity == "THPG" || entity == "THHV") strContainer = ("LDAP://OU=" + type + " " + entity + ",OU=Workstations,OU=" + entity + ",DC="YOURDOMAIN"); else strContainer = ("LDAP://OU=" + type + " " + entity + ",OU=" + entity + ",OU=THR Workstations,DC="<YOURDOMAIN>"); DirectoryEntry eLocation = new DirectoryEntry("LDAP://" + getDN(Environment.MachineName)); MessageBox.Show(getDN(Environment.MachineName)); DirectoryEntry nLocation = new DirectoryEntry(strContainer); string newName = eLocation.Name; eLocation.MoveTo(nLocation, newName); nLocation.Close(); eLocation.Close(); MessageBox.Show(" Your Workstation is now in: " + strContainer); return true; } catch (Exception ex) { MessageBox.Show(ex.Message, "MoveOU"); return false; } } /// <summary> /// Returns the service tag of a computer /// </summary> /// <returns>service tag</returns> public string getCI() { string CI = ""; try { ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_BIOS"); foreach (ManagementObject queryObj in searcher.Get()) { CI = queryObj["SerialNumber"].ToString(); } } catch (ManagementException e) { MessageBox.Show("An error occurred while querying for WMI data: " + e.Message); } return CI; } /// <summary> /// Renames a computer /// </summary> /// <param name="PCName">New name for computer</param> /// <returns>Success / Fail</returns> public bool renamePC(string PCName) { string compPath = "Win32_ComputerSystem.Name='" + Environment.MachineName + "'"; using (ManagementObject dir = new ManagementObject(new ManagementPath(compPath))) { ManagementBaseObject inputArgs = dir.GetMethodParameters("Rename"); inputArgs["Name"] = PCName; ManagementBaseObject outParams = dir.InvokeMethod("Rename", inputArgs, null); uint ret = (uint)(outParams.Properties["ReturnValue"].Value); if (ret == 0) { //MessageBox.Show("Computer renamed correctly"); return true; } else { //MessageBox.Show("There was a problem"); return false; } } } /// <summary> /// Gets the DN of an object /// </summary> /// <param name="objectCls">objectClass: user, group, or computer</param> /// <param name="returnValue">returnType: distinguishedName or ObjectGUID</param> /// <param name="objectName">username, computername, groupname</param> /// <returns>string</returns> public string GetObjectDistinguishedName(objectClass objectCls, returnType returnValue, string objectName) { string LdapDomain = <YOURDOMAIN> e.g. someplace.com; string distinguishedName = string.Empty; string connectionPrefix = "LDAP://" + LdapDomain; DirectoryEntry entry = new DirectoryEntry(connectionPrefix); DirectorySearcher mySearcher = new DirectorySearcher(entry); switch (objectCls) { case objectClass.user: mySearcher.Filter = "(&(objectClass=user)(|(cn=" + objectName + ")(sAMAccountName=" + objectName + ")))"; break; case objectClass.group: mySearcher.Filter = "(&(objectClass=group)(|(cn=" + objectName + ")(dn=" + objectName + ")))"; break; case objectClass.computer: mySearcher.Filter = "(&(objectClass=computer)(|(cn=" + objectName + ")(dn=" + objectName + ")))"; break; } SearchResult result = mySearcher.FindOne(); if (result == null) { throw new NullReferenceException ("unable to locate the distinguishedName for the object " + objectName + " in the " + LdapDomain + " domain"); } DirectoryEntry directoryObject = result.GetDirectoryEntry(); if (returnValue.Equals(returnType.distinguishedName)) { distinguishedName = "LDAP://" + directoryObject.Properties ["distinguishedName"].Value; } if (returnValue.Equals(returnType.ObjectGUID)) { distinguishedName = directoryObject.Guid.ToString(); } entry.Close(); entry.Dispose(); mySearcher.Dispose(); return distinguishedName; } /// <summary> /// Adds a user to a group. Needs Distinguished names. Use with GetObjectDistinguishedName() /// </summary> /// <param name="userDn">User DN</param> /// <param name="groupDn">Group DN</param> public void AddToGroup(string userDn, string groupDn) { try { DirectoryEntry dirEntry = new DirectoryEntry(groupDn); dirEntry.Properties["member"].Add(userDn); dirEntry.CommitChanges(); dirEntry.Close(); } catch (System.DirectoryServices.DirectoryServicesCOMException e) { } } /// <summary> /// Removes a user from a group. Needs Distinguished names. Use with GetObjectDistinguishedName() /// </summary> /// <param name="userDn">User DN</param> /// <param name="groupDn">Group DN</param> public void RemoveFromGroup(string userDn, string groupDn) { try { DirectoryEntry dirEntry = new DirectoryEntry(groupDn); dirEntry.Properties["member"].Remove(userDn); dirEntry.CommitChanges(); dirEntry.Close(); } catch (System.DirectoryServices.DirectoryServicesCOMException e) { } } /// <summary> /// Gets a list of users in a group in Active Directory /// </summary> /// <param name="group">Name of the group</param> /// <returns>ArrayList</returns> public ArrayList GetUsersInGroup(string group) { ArrayList groupMembers = new ArrayList(); string sam = ""; //string fname = ""; //string lname = ""; string active = ""; <MODIFY THIS SECTION TO FIT YOUR ENVIRONMENT> DirectoryEntry de = new DirectoryEntry("LDAP://DC=someplace,DC=org"); DirectorySearcher ds = new DirectorySearcher(de, "(objectClass=person)"); ds.Filter = "(memberOf=CN=" + group + ",OU=Groups,OU=THR Users,DC=someplace,DC=org)"; ds.PageSize = 10000; //ds.PropertiesToLoad.Add("givenname"); ds.PropertiesToLoad.Add("samaccountname"); //ds.PropertiesToLoad.Add("sn"); //ds.PropertiesToLoad.Add("useraccountcontrol"); foreach (SearchResult sr in ds.FindAll()) { try { sam = sr.Properties["samaccountname"][0].ToString(); //fname = sr.Properties["givenname"][0].ToString(); //lname = sr.Properties["sn"][0].ToString(); //active = sr.Properties["useraccountcontrol"][0].ToString(); } catch (Exception e) { } // don't grab disabled users if (active.ToString() != "514") { groupMembers.Add(sam.ToString()); //, (fname.ToString() + " " + lname.ToString()) } } return groupMembers; } /// <summary> /// Checks to see if computer is online /// </summary> /// <param name="target">computer name or ip address</param> /// <returns>true or false</returns> public bool PCisOnline(string target) { using (Ping ping = new Ping()) { try { PingReply reply = ping.Send(target, 50); if (reply.Status == IPStatus.Success) { return true; } else { return false; } } catch (Exception ex) { return false; } } } /// <summary> /// LANDesk Remote Control to target PC /// </summary> /// <param name="target">Computer name or IP address</param> /// <returns>true: started, false: PC was offline</returns> public bool RemoteLandesk(string target) { if (PCisOnline(target)) { using (WebBrowser wb = new WebBrowser()) { wb.Navigate(@"http://landesk/RemoteSession.aspx?machine=" + target + @"&operation=rc"); } return true; } else { return false; } } /// <summary> /// Checks to see if the computer has a valid certificate /// </summary> /// <param name="target">Target Computer</param> /// <returns> /// missing /// valid /// expired /// old - will expire in less than 30 days /// </returns> public string CertStatus(string target) { //locate certificate in remote registry RegistryKey OurKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); OurKey = OurKey.OpenSubKey("SOFTWARE\\Microsoft\\SystemCertificates\\My\\Certificates"); int keys = OurKey.GetSubKeyNames().Length; int certValid = 0; string g_sString = ""; string g_rString = ""; #region check each cert on computer foreach (string key in OurKey.GetSubKeyNames()) { RegistryKey NewKey = OurKey.OpenSubKey(key); #region Convert binary certificate to readable string byte[] ans = (byte[])NewKey.GetValue("Blob"); g_sString = System.Text.Encoding.ASCII.GetString(ans); string[] sArray = g_sString.Split('\0'); g_rString = ""; g_sString = ""; foreach (string s in sArray) { g_rString += s; } #endregion #region extract date from cert, and compare to today if (g_rString.Contains("CA2")) g_sString = g_rString.Substring(g_rString.IndexOf("CA2") + 22, 6); else g_sString = g_rString.Substring(g_rString.IndexOf("CA1") + 22, 6); try { DateTime expire = new DateTime(2000 + Int32.Parse(g_sString.Substring(0, 2)), Int32.Parse(g_sString.Substring(2, 2)), Int32.Parse(g_sString.Substring(4, 2))); g_sString = expire.ToShortDateString(); if (expire > DateTime.Now && expire > DateTime.Now.AddDays(30)) return "valid"; if ((DateTime.Now < expire) && (expire <= DateTime.Now.AddDays(30))) { //Computer is within 30 days of expiration certValid = 2; } } catch { DateTime expire = new DateTime(2000, 01, 01); } #endregion } #endregion if (certValid == 1) return "valid"; else if (certValid == 0 && keys > 0) return "expired"; else if (certValid == 2) return "old"; else return "missing"; } } }
Ok, after you modify all of that, you can build it, and grab the dll.
Part 2: Writing the application
Now here's where we get down to the area where we can tell the application what to do.
Step 1: Create a new Windows Forms Project
Mine is simply name Remote HealthCheck, and is using .NET 3.5 framework.
Step 2: Add References
Add these references:
Microsoft.Office.Interop.Excel
System.Data.DataSetExtensions
System.DirectoryServices
System.Management
System.ServiceProcess
THRFunctions (whatever you named yours, reference it)
Step 3: Create File Structure
We have multiple forms, and a class that need to be added.
Root [INDENT]AddComputers[/INDENT] [INDENT][INDENT]frmAdd.cs - Windows Form[/INDENT][/INDENT] [INDENT][INDENT]frmADSearch.cs - Windows Form[/INDENT][/INDENT] [INDENT]clsGlobal.cs - Class[/INDENT] [INDENT]frmMain.cs - rename Form1.cs[/INDENT]
Leave everything else as is.
Step 4: Setup the clsGlobal class
Very simple:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Remote_HealthCheck { class clsGlobal { public static String g_targets; public static String g_sString; public static String g_rString; } }
Step 5: Design the frmAdd form
Open frmAdd [Design]
Change the FormBorderStyle to FixedToolWindow
Size = 319,336
SizeGripStyle = Hide
StartPosition = CenterParent
Text = Add Computers
TextBox: txtPCs
Location = 11,7
Multiline = True
ScrollBars = Vertical
Size = 291, 268
Button: btnADSearch
Location = 11,282
Size = 129,23
Text = Active Directory Search
Double click it to create a function for it, we'll come back to that later
Button: btnFormat
Location: 146,282
Size = 75,23
Text = Format
Double Click, come back to it later
Button: btnDone
Location = 227,282
Size = 75,23
Text = Done
Double Click, come back to it later
When finished, it should look like this:

Now for the code to this form:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Remote_HealthCheck.AddComputers { public partial class frmAdd : Form { public frmAdd() { InitializeComponent(); } private void btnFormat_Click(object sender, EventArgs e) { string tempPcs = ""; int i = 0; foreach (string computer in txtPCs.Text.Split(Environment.NewLine.ToCharArray())) { i++; if (i == 1) tempPcs = computer.Trim(); else { if (computer.Length > 2) tempPcs += Environment.NewLine + computer.Trim(); } } txtPCs.Text = tempPcs; } private void btnDone_Click(object sender, EventArgs e) { clsGlobal.g_targets = txtPCs.Text; this.Close(); } private void btnADSearch_Click(object sender, EventArgs e) { frmADSearch objfrmADSearch = new frmADSearch(); objfrmADSearch.ShowDialog(); txtPCs.Text = clsGlobal.g_targets; } } }
Step 6: Design the frmADSearch form
Form settings:
FormBorderStyle = FixedToolWindow
ShowIcon = False
Size = 382,105
SizeGripStyle = Hide
StartPosition = CenterParent
Text = Active Directory Search
TabControl tabControl1
Dock = Fill
TabPages = Collection (Open)
TabPages:
0 - tabName
Text = Name Search
1 - tabOU
Text = OU Search
Go to tabName
TextBox txtName:
Location = 6,6
Size = 196, 20
ComboBox cmbNameArg
DropDownStyle = DropDownList
Location = 217,6
Size = 121,21
Items = Collection:
Starts with Ends with Contains
Button btnNameSearch
Location = 8,32
Size = 75,23
Text = Find
Double Click, we can come back to it later.
tabOU:
ComboBox cmdOUList
Location = 8,6
Size = 236,21 (you can lengthen if you wish)
Button btnOUSearch:
Location = 8,33
Size = 75,23
Text = Search
Double Click


Code for this form:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Collections.Generic; using System.DirectoryServices; using THRFunctions; namespace Remote_HealthCheck.AddComputers { public partial class frmADSearch : Form { string[,] aryOU = new string[1, 2]; List<string> OUs = new List<string>(); THRFunctions.clsMain func = new clsMain(); public frmADSearch() { InitializeComponent(); } private void frmADSearch_Load(object sender, EventArgs e) { getOUList(); } public void getOUList() { DirectoryEntry de = func.createDirectoryEntry(); DirectorySearcher search = new DirectorySearcher(de); aryOU[0, 0] = "SimpleName"; aryOU[0, 1] = "FullPath"; search.Filter = "(objectClass=organizationalUnit)"; search.SearchScope = SearchScope.Subtree; search.PropertiesToLoad.Add("displayName"); SearchResultCollection results = search.FindAll(); //int x = 0; //int n = 0; foreach (SearchResult result in results) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { try { string ans = myCollection.ToString(); string OU = ans.Substring(ans.IndexOf("OU=") + 3, ans.IndexOf(",DC=") - ans.IndexOf("OU=") - 3); //string final = ""; if (!cmbOUList.Items.Contains(OU) && !OU.Contains("User")) { //try //{ //OUs.Add(OU); //int i = 0; //foreach (string split in OU.Split(',')) //{ // if (i == 0) // final = split; // else if (!split.Contains("THR Workstations")) // final += "\\" + split.Substring(3); // i++; //} cmbOUList.Items.Add(OU); //} //catch //{ // OUs.Add(OU); // final = OU; //} //n++; //x++; //ResizeArray(ref aryOU, 2,x+1); //aryOU[x,0] = final; //aryOU[x,1] = OU; //cmbOUList.Items.Add(final); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } cmbOUList.Sorted = true; } private void btnOUSearch_Click(object sender, EventArgs e) { DirectoryEntry ldapConnection = func.createDirectoryEntry(); if (cmbOUList.SelectedItem.ToString() == null) return; ldapConnection.Path = "LDAP://OU=" + cmbOUList.SelectedItem.ToString() + ",DC=someplace,DC=org"<FILLINYOURDOMAINHERE>; ldapConnection.AuthenticationType = AuthenticationTypes.Secure; clsGlobal.g_targets = ""; foreach (DirectoryEntry child in ldapConnection.Children) { DirectorySearcher search = new DirectorySearcher(child); search.Filter = String.Format("(&(objectCategory=computer))"); search.PropertiesToLoad.Add("displayName"); search.PageSize = 10000; SearchResultCollection results = search.FindAll(); foreach (SearchResult result in results) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { if (myCollection.ToString().Contains("$")) { clsGlobal.g_targets += myCollection.ToString().Substring(0, myCollection.ToString().IndexOf("$")) + Environment.NewLine; } else clsGlobal.g_targets += myCollection.ToString().Substring(myCollection.ToString().IndexOf("CN=") + 3, (myCollection.ToString().IndexOf(",OU")) - myCollection.ToString().IndexOf("CN=") - 3) + Environment.NewLine; } } } } this.Close(); } private void btnNameSearch_Click(object sender, EventArgs e) { string searchString = ""; switch (cmbNameArg.Text) { case "Starts with": searchString = txtName.Text + "*"; break; case "Ends with": searchString = "*" + txtName.Text; break; case "Contains": searchString = "*" + txtName.Text + "*"; break; case "": searchString = txtName.Text; break; } using (DirectoryEntry entry = func.createDirectoryEntry()) { DirectorySearcher ComputerSearch = new DirectorySearcher(entry); ComputerSearch.Filter = String.Format("(&(objectCategory=computer)(CN=" + searchString + "))"); ComputerSearch.PropertiesToLoad.Add("displayName"); SearchResultCollection matches = ComputerSearch.FindAll(); foreach (SearchResult result in matches) { ResultPropertyCollection fields = result.Properties; foreach (String ldapField in fields.PropertyNames) { foreach (Object myCollection in fields[ldapField]) { if (myCollection.ToString().Contains("$")) clsGlobal.g_targets += myCollection.ToString().Substring(0, myCollection.ToString().IndexOf("$")) + Environment.NewLine; } } } } this.Close(); } private void ResizeArray(ref string[,] original, int cols, int rows) { string[,] newArray = new string[rows, cols]; Array.Copy(original, newArray, original.Length); original = newArray; } } }
Fix the errors for your environment.
Step 7: The main form
Ok, so first off, we need to build the UI:
( I accidently name mine FrmMain, not frmMain as the actual name)
Size = 704, 518 (you can change this later if you wish)
Text = Remote HealthCheck
ToolStrip toolStrip1
Dock = Top
Collection:
ToolStripButton btnAdd DisplayStyle = Text Text = AddComputers Size = 85,22 ToolStripButton btnCheck: DisplayStyle = Text Text = Check Computers Size = 95,22 ToolStripButton btnClear: DisplayStyle = Text Text = Clear List Size = 55,22 ToolStripButton btnStop: DisplayStyle = Text Text = Stop Running Size = 75,22 Add a seperator ToolStripButton btnExport: DisplayStyle = Text Text = Export Size = 43,22 ToolStripDropDownButton DropDownSelect DisplayStyle = Text Text = Check For: Size = 72,22 Collection = Add these menu items, and change Checked = True and CheckState = Checked and CheckOnClick = True chkMenuCert - Text = Cert chkMenuSCCM - Text = SCCM chkMenuAppV - Text = AppV chkMenuNTR - Text = NTR chkMenuWMI - Text = WMI chkMenuGina - Text = Gina chkMenuAV - Text = AntiVirus chkMenuOU - Text = OU Add 2 more, without the Checked and CheckState and CheckOnClick(false and unchecked) checkAllToolStripMenuItem - text = Check All uncheckAllToolStripMenuItem - text = Uncheck All Double Click each button to create the links, including the 2 buttons at the bottom of Check For: (Check All and Uncheck All)
DataGridView gridResults
AllowUserToOrderColumns = True
ColumnHeadersHeightSizeMode = AutoSize
Dock = Fill
ReadOnly = True
StatusStrip statusStrip1:
Dock = Bottom
Collection:
ToolStripProgressBar progressBar1: Size = 200,16 ToolStripStatusLabel lblProgress: Text = Progress: 0 / 0 Size = 78,17
You should end up with this:

Code for this main form:
using System; using System.Collections; using System.Data; using System.Linq; using System.Windows.Forms; using Microsoft.Win32; using System.Net.NetworkInformation; using Remote_HealthCheck.Properties; using Excel = Microsoft.Office.Interop.Excel; using System.Reflection; using System.Diagnostics; using System.Management; using THRFunctions; using System.Data.SqlClient; using System.DirectoryServices; namespace Remote_HealthCheck { public partial class FrmMain : Form { readonly clsMain _func = new clsMain(); readonly DataTable _tableResults = new DataTable(); int _total; bool _cancelBtn; public FrmMain() { InitializeComponent(); _tableResults.Columns.Add("Computer Name", typeof(string)); var key = new DataColumn[1]; DataColumn column = _tableResults.Columns[0]; key[0] = column; _tableResults.PrimaryKey = key; _tableResults.Columns.Add("User", typeof (string)); _tableResults.Columns.Add("Cert Status", typeof(string)); _tableResults.Columns.Add("SCCM Installed", typeof(Boolean)); _tableResults.Columns.Add("AppV Installed", typeof(Boolean)); _tableResults.Columns.Add("NTR Installed", typeof(Boolean)); _tableResults.Columns.Add("WMI Good", typeof(Boolean)); _tableResults.Columns.Add("McAfee Installed", typeof(Boolean)); _tableResults.Columns.Add("Domain Admin", typeof(Boolean)); _tableResults.Columns.Add("Admin Workstation", typeof(Boolean)); _tableResults.Columns.Add("Current Gina", typeof(string)); _tableResults.Columns.Add("OU", typeof(string)); _tableResults.Columns.Add("Error Message", typeof(string)); } private void BtnAddClick(object sender, EventArgs e) { var gFrmAdd = new AddComputers.frmAdd(); gFrmAdd.ShowDialog(); var i = 0; new CheckBox {Checked = false}; foreach (var computer in clsGlobal.g_targets.Split(Environment.NewLine.ToCharArray())) { i++; if ((computer.Length > 2) && (_tableResults.Rows.Contains(computer) == false)) { _tableResults.Rows.Add(computer, "","", false, false, false, false, false, false, false, ""); } if (i >= 100) { gridResults.DataSource = _tableResults; lblProgress.Text = Resources.strProgressStatic + _tableResults.Rows.Count; Application.DoEvents(); i = 0; } } _total = _tableResults.Rows.Count; gridResults.DataSource = _tableResults; gridResults.Columns[0].Width = 150; gridResults.Columns[1].Width = 75; gridResults.Columns[2].Width = 75; gridResults.Columns[3].Width = 50; gridResults.Columns[4].Width = 50; gridResults.Columns[5].Width = 50; gridResults.Columns[6].Width = 50; gridResults.Columns[7].Width = 50; gridResults.Columns[8].Width = 50; gridResults.Columns[9].Width = 50; gridResults.Columns[10].Width = 100; gridResults.Columns[11].Width = 200; gridResults.Columns[12].Width = 400; gridResults.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[1].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[2].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[3].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[4].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[5].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[6].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[7].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[8].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[9].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[10].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[11].SortMode = DataGridViewColumnSortMode.Automatic; gridResults.Columns[12].SortMode = DataGridViewColumnSortMode.Automatic; } private void BtnCheckClick(object sender, EventArgs e) { #region disable buttons btnAdd.Enabled = false; //checkContinuousToolStripMenuItem.Enabled = false; //onceToolStripMenuItem.Enabled = false; btnCheck.Enabled = false; btnClear.Enabled = false; #endregion _cancelBtn = false; CheckComputers(); _cancelBtn = false; #region Load final counts and display message //string results = "Total Computers: " + lstComputers.Items.Count; //results += "\n----------------------------------"; //results += "\nCertificate Valid: " + validCount.ToString(); //results += "\nCertificate Expired: " + expiredCount.ToString(); //results += "\nCertificate Missing: " + missingCount.ToString(); //results += "\nComputer Offline: " + offlineCount.ToString(); //results += "\nComputer Invalid: " + invalidCount.ToString(); //results += "\nException Thrown: " + errorCount.ToString(); //MessageBox.Show(results, "Done Checking"); #endregion btnAdd.Enabled = true; btnClear.Enabled = true; btnCheck.Enabled = true; } private void CheckComputers() { if (gridResults.RowCount == 0) return; #region Initialize progress bar int i = gridResults.RowCount - 1; progressBar1.Minimum = 0; progressBar1.Maximum = i; progressBar1.Step = 1; progressBar1.Value = 0; lblProgress.Text = Resources.strProgressStatic + i; #endregion for (int x = 0; x < gridResults.Rows.Count - 1; x++) { var row = new DataGridViewRow(); row.CreateCells(gridResults); lblProgress.Text = @"Progress: " + (x+1) + @" / " + (gridResults.Rows.Count - 1); progressBar1.PerformStep(); if (_cancelBtn) { btnAdd.Enabled = true; btnClear.Enabled = true; btnCheck.Enabled = true; return; } string computer = gridResults[0, x].Value.ToString(); row.Cells[0].Value = computer; if (chkMenuOU.Checked) gridResults[11, x].Value = _func.getOU(computer); int online = PCisOnline(computer); #region Computer is offline if (online == 0) { gridResults[2, x].Value = "Offline"; } #endregion #region Computer is inactive else if (online == 2) { gridResults[2, x].Value = "Inactive"; } #endregion #region Computer is online else if (online == 1) { string error = ""; gridResults[1, x].Value = LastLoggedIn(computer); if (chkMenuCert.Checked) { string certstatus = CheckCert(computer); error = certstatus.Contains("Error") ? certstatus.Substring(5) : ""; gridResults[2, x].Value = certstatus.Contains("Error") ? "Error" : certstatus; } if (chkMenuSCCM.Checked) gridResults[3, x].Value = HasSccm(computer); if (chkMenuAppV.Checked) gridResults[4, x].Value = HasAppV(computer); if (chkMenuNTR.Checked) gridResults[5, x].Value = HasNtr(computer); if (chkMenuWMI.Checked) gridResults[6, x].Value = GoodWmi(computer); if (chkMenuAV.Checked) gridResults[7, x].Value = HasAv(computer); var admin = HasAdmin(computer); gridResults[8, x].Value = (admin == 1 || admin == 3) ? true : false; gridResults[9, x].Value = (admin == 2 || admin == 3) ? true : false; if (chkMenuGina.Checked) gridResults[10, x].Value = CurrentGina(computer); gridResults[12, x].Value = error; } #endregion //next row //Calculate percent complete, and display on Title Bar decimal percent = (decimal)((x) * 100) / i; Text = Resources.TitleBarText + Math.Round(percent) + @"%"; Application.DoEvents(); } } /// <summary> /// Checks to see if PC is active and online /// </summary> /// <param name="target">Target Computer</param> /// <returns> /// 0 = Offline /// 1 = Online /// 2 = Inactive /// </returns> public int PCisOnline(string target) { #region check to see if PC is online using (var ping = new Ping()) { try { var reply = ping.Send(target, 50); if (reply != null) return reply.Status == IPStatus.Success ? 1 : 0; } catch (Exception) { //Has no IP, cannot ping- inactive return 2; } } #endregion return 0; } /// <summary> /// Checks to see if the computer has a valid certificate /// </summary> /// <param name="target">Target Computer</param> /// <returns> /// 0 = missing /// 1 = valid /// 2 = expired /// 3 = will expire in less than 30 days /// </returns> public int HasCert(string target) { //locate certificate in remote registry RegistryKey ourKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); ourKey = ourKey.OpenSubKey("SOFTWARE\\Microsoft\\SystemCertificates\\My\\Certificates"); if (ourKey == null) { } else { var keys = ourKey.GetSubKeyNames().Count(); var certValid = 0; #region check each cert on computer foreach (byte[] ans in ourKey.GetSubKeyNames().Select(key => ourKey.OpenSubKey(key)).Select(newKey => (byte[]) newKey.GetValue("Blob"))) { clsGlobal.g_sString = System.Text.Encoding.ASCII.GetString(ans); var sArray = clsGlobal.g_sString.Split('\0'); clsGlobal.g_rString = ""; clsGlobal.g_sString = ""; foreach (var s in sArray) { clsGlobal.g_rString += s; } #endregion #region extract date from cert, and compare to today clsGlobal.g_sString = clsGlobal.g_rString.Contains("CA2") ? clsGlobal.g_rString.Substring(clsGlobal.g_rString.IndexOf("CA2") + 22, 6) : clsGlobal.g_rString.Substring(clsGlobal.g_rString.IndexOf("CA1") + 22, 6); try { var expire = new DateTime(2000 + Int32.Parse(clsGlobal.g_sString.Substring(0, 2)), Int32.Parse(clsGlobal.g_sString.Substring(2, 2)), Int32.Parse(clsGlobal.g_sString.Substring(4, 2))); clsGlobal.g_sString = expire.ToShortDateString(); if (expire > DateTime.Now && expire > DateTime.Now.AddDays(30)) return 1; if ((DateTime.Now < expire) && (expire <= DateTime.Now.AddDays(30))) { //Computer is within 30 days of expiration certValid = 2; } } catch { var dateTime = new DateTime(2000, 01, 01); certValid = 0; } } #endregion if (certValid == 1) return 1; if (certValid == 0 && keys > 0) return 2; return certValid == 2 ? 3 : 0; } return 0; } public bool HasSccm(string target) { try { RegistryKey OurKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); OurKey = OurKey.OpenSubKey("SOFTWARE\\Microsoft\\SMS\\Mobile Client"); if (OurKey.GetValue("AssignedSiteCode").ToString() == "TH1") return true; else return false; } catch (Exception ex) { return false; } } public bool HasAppV(string target) { try { RegistryKey OurKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); OurKey = OurKey.OpenSubKey("SOFTWARE\\Microsoft\\SoftGrid\\4.5\\SystemGuard"); if (OurKey.GetValue("Client").ToString() == "1") return true; else return false; } catch (Exception ex) { return false; } } public bool HasNtr(string target) { string remoteSystem = target; string procSearch = "installablerc"; try { Process[] proc = System.Diagnostics.Process.GetProcessesByName(procSearch, remoteSystem); if (proc.Length > 0) { return true; } else { return false; } } catch { return false; } //ServiceController sc = new ServiceController(); //sc.MachineName = target; //sc.ServiceName = "Server"; //try //{ // if (sc.Status.Equals(ServiceControllerStatus.Running)) // { return true; } // else // { return false; } //} //catch (Exception ex) //{ // MessageBox.Show(ex.Message); //return false; //} } public bool GoodWmi(string target) { try { using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + target + "\\root\\CIMV2", "SELECT * FROM Win32_ComputerSystem")) { foreach (ManagementObject queryObj in searcher.Get()) { if (queryObj["Manufacturer"].ToString().Length > 2) return true; else return false; } return true; } } catch (Exception ex) { return false; } } public bool HasAv(string target) { Version ver = new Version(); Version cver = new Version("8.5.0.0"); try { RegistryKey OurKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); OurKey = OurKey.OpenSubKey("SOFTWARE\\McAfee\\DesktopProtection"); if (OurKey.GetValue("Product").ToString() == "McAfee VirusScan Enterprise") { ver = new Version(OurKey.GetValue("szProductVer").ToString()); if (ver < cver) return false; } else return false; return true; } catch (Exception ex) { return false; } } public string CurrentGina(string target) { try { RegistryKey OurKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); OurKey = OurKey.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"); return (OurKey.GetValue("GinaDLL").ToString().Remove(0, OurKey.GetValue("GinaDLL").ToString().IndexOf(@"32\") + 3)); } catch (Exception ex) { return "None"; } } public string CheckCert(string target) { try { //does it have a valid cert? int valid = HasCert(target); #region Computer had valid Cert if (valid == 1) { return "Valid"; } #endregion #region Computer has expired Cert else if (valid == 2) { return "Expired"; } #endregion #region Cert will expire within a month else if (valid == 3) { return "Expires soon"; } #endregion #region Computer is missing Cert else { return "Missing"; } #endregion } catch (Exception ex) { #region Computer has a problem ////store error into array for later retrieval //errorList[ErrorNum] = computer; //errorList[ErrorNum + 1] = ex.Message; //ErrorNum++; //ErrorNum++; //errorCount++; //lvi.Group = lstComputers.Groups[4]; //lvi.BackColor = Color.Violet; return "Error " + ex.Message; #endregion } } private void BtnExportClick(object sender, EventArgs e) { Excel.Application xlApp; Excel.Workbook xlWorkbook; Excel.Worksheet xlWorksheetOnline; Excel.Worksheet xlWorksheetOffline; object misValue = Missing.Value; xlApp = new Excel.ApplicationClass(); xlWorkbook = xlApp.Workbooks.Add(misValue); xlWorksheetOnline = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(1); xlWorksheetOnline.Name = "Online"; xlWorksheetOnline.Cells[1, 1] = "Computer Name"; xlWorksheetOnline.Cells[1, 2] = "User"; xlWorksheetOnline.Cells[1, 3] = "Certificate Status"; xlWorksheetOnline.Cells[1, 4] = "SCCM Installed"; xlWorksheetOnline.Cells[1, 5] = "AppV Installed"; xlWorksheetOnline.Cells[1, 6] = "NTR Installed"; xlWorksheetOnline.Cells[1, 7] = "WMI Good"; xlWorksheetOnline.Cells[1, 8] = "McAfee Installed"; xlWorksheetOnline.Cells[1, 9] = "Domain Admin"; xlWorksheetOnline.Cells[1, 10] = "Admin Workstation"; xlWorksheetOnline.Cells[1, 11] = "Current Gina"; xlWorksheetOnline.Cells[1, 12] = "OU"; xlWorksheetOnline.Cells[1, 13] = "Errors"; xlWorksheetOffline = (Excel.Worksheet)xlWorkbook.Worksheets.get_Item(2); xlWorksheetOffline.Name = "Offline"; xlWorksheetOffline.Cells[1, 1] = "Computer Name"; xlWorksheetOffline.Cells[1, 2] = "User"; xlWorksheetOffline.Cells[1, 3] = "Certificate Status"; xlWorksheetOffline.Cells[1, 4] = "SCCM Installed"; xlWorksheetOffline.Cells[1, 5] = "AppV Installed"; xlWorksheetOffline.Cells[1, 6] = "NTR Installed"; xlWorksheetOffline.Cells[1, 7] = "WMI Good"; xlWorksheetOffline.Cells[1, 8] = "McAfee Installed"; xlWorksheetOffline.Cells[1, 9] = "Domain Admin"; xlWorksheetOffline.Cells[1, 10] = "Admin Workstation"; xlWorksheetOffline.Cells[1, 11] = "Current Gina"; xlWorksheetOffline.Cells[1, 12] = "OU"; xlWorksheetOffline.Cells[1, 13] = "Errors"; int offRow = 1, onRow = 1, x = 0; foreach (DataGridViewRow row in gridResults.Rows) { if (row.Cells[2].Value == null) break; switch (row.Cells[2].Value.ToString()) { case "Inactive": case "Offline": offRow++; xlWorksheetOffline.Cells[offRow, 1] = row.Cells[0].Value; xlWorksheetOffline.Cells[offRow, 2] = row.Cells[1].Value; xlWorksheetOffline.Cells[offRow, 3] = row.Cells[2].Value; xlWorksheetOffline.Cells[offRow, 4] = row.Cells[3].Value; xlWorksheetOffline.Cells[offRow, 5] = row.Cells[4].Value; xlWorksheetOffline.Cells[offRow, 6] = row.Cells[5].Value; xlWorksheetOffline.Cells[offRow, 7] = row.Cells[6].Value; xlWorksheetOffline.Cells[offRow, 8] = row.Cells[7].Value; xlWorksheetOffline.Cells[offRow, 9] = row.Cells[8].Value; xlWorksheetOffline.Cells[offRow, 10] = row.Cells[9].Value; xlWorksheetOffline.Cells[offRow, 11] = row.Cells[10].Value; xlWorksheetOffline.Cells[offRow, 12] = row.Cells[11].Value; xlWorksheetOffline.Cells[offRow, 13] = row.Cells[12].Value; break; default: onRow++; xlWorksheetOnline.Cells[onRow, 1] = row.Cells[0].Value; xlWorksheetOnline.Cells[onRow, 2] = row.Cells[1].Value; xlWorksheetOnline.Cells[onRow, 3] = row.Cells[2].Value; xlWorksheetOnline.Cells[onRow, 4] = row.Cells[3].Value; xlWorksheetOnline.Cells[onRow, 5] = row.Cells[4].Value; xlWorksheetOnline.Cells[onRow, 6] = row.Cells[5].Value; xlWorksheetOnline.Cells[onRow, 7] = row.Cells[6].Value; xlWorksheetOnline.Cells[onRow, 8] = row.Cells[7].Value; xlWorksheetOnline.Cells[onRow, 9] = row.Cells[8].Value; xlWorksheetOnline.Cells[onRow, 10] = row.Cells[9].Value; xlWorksheetOnline.Cells[onRow, 11] = row.Cells[10].Value; xlWorksheetOnline.Cells[onRow, 12] = row.Cells[11].Value; xlWorksheetOnline.Cells[onRow, 13] = row.Cells[12].Value; break; } } xlWorkbook.Close(true, misValue, misValue); xlApp.Quit(); ReleaseObject(xlWorksheetOnline); ReleaseObject(xlWorksheetOffline); ReleaseObject(xlWorkbook); ReleaseObject(xlApp); } private static void ReleaseObject(object obj) { try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch (Exception ex) { obj = null; MessageBox.Show(@"Exception Occured while releasing object " + ex.ToString()); } finally { GC.Collect(); } } private void BtnClearClick(object sender, EventArgs e) { gridResults.DataSource = null; _tableResults.Clear(); } private void BtnStopClick(object sender, EventArgs e) { _cancelBtn = true; } private void CheckAllToolStripMenuItemClick(object sender, EventArgs e) { chkMenuAppV.Checked = true; chkMenuCert.Checked = true; chkMenuGina.Checked = true; chkMenuNTR.Checked = true; chkMenuSCCM.Checked = true; chkMenuWMI.Checked = true; chkMenuOU.Checked = true; chkMenuAV.Checked = true; } private void UncheckAllToolStripMenuItemClick(object sender, EventArgs e) { chkMenuAppV.Checked = false; chkMenuCert.Checked = false; chkMenuGina.Checked = false; chkMenuNTR.Checked = false; chkMenuSCCM.Checked = false; chkMenuWMI.Checked = false; chkMenuOU.Checked = false; chkMenuAV.Checked = false; } public string LastLoggedIn(string target) { var conn = new SqlConnection(@"Data Source=FTWSCCMSQL01\INSTANCE1;Initial Catalog=SMS_TH1;Integrated Security=True"); conn.Open(); string strSqlCommand = @"SELECT User_Name0 FROM v_R_System WHERE (Name0 = '" + target + @"')"; var command = new SqlCommand(strSqlCommand, conn); var commreturn = command.ExecuteScalar(); var returnVal = commreturn != DBNull.Value && commreturn != null ? commreturn : "none"; conn.Close(); return returnVal.ToString(); } public int HasAdmin(string target) { var domain = false; var workstation = false; try { using (var groupEntry = new DirectoryEntry("WinNT://" + target + "/Administrators,group")) { foreach (var member in (IEnumerable)groupEntry.Invoke("Members")) { using (var memberEntry = new DirectoryEntry(member)) { if (memberEntry.Name == "Domain Admins") domain = true; if (memberEntry.Name == "Admin Workstation" || memberEntry.Name == "Admin Clinical Workstation") workstation = true; } } } if (domain && workstation) return 3; if (domain) return 1; return workstation ? 2 : 0; } catch (Exception) { return 0; } } } }
You'll notice there are some sections you may need to modify, such as public int HasAdmin(string target)
Change the memberEnrty.Name 's to match whatever the local admins for your computers should be.
Also, this section:
public string LastLoggedIn(string target) { var conn = new SqlConnection(@"Data Source=FTWSCCMSQL01\INSTANCE1;Initial Catalog=SMS_TH1;Integrated Security=True"); conn.Open(); string strSqlCommand = @"SELECT User_Name0 FROM v_R_System WHERE (Name0 = '" + target + @"')"; var command = new SqlCommand(strSqlCommand, conn); var commreturn = command.ExecuteScalar(); var returnVal = commreturn != DBNull.Value && commreturn != null ? commreturn : "none"; conn.Close(); return returnVal.ToString(); }Will need to be either reconfigured (if you have SCCM), or you can simply do a registry query against the target computer for this information:
public string LastLoggedIn(string target) { RegistryKey myKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, target); myKey = myKey.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"); try{UserName = myKey.GetValue("DefaultUserName").ToString();} catch { UserName = ""} return UserName; }
Now, we have also have some Resources:
Open your project properties:
Resources:
strProgressStatic = Progress: 0 / (I may not even have this in my code anymore.. if not, sorry)
TitleBarText = Remote HealthCheck:
Fix any errors you will have, and test run it.