Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Manage Processes on Remote Machine

0.00/5 (No votes)
8 Mar 2007 1  
The article describes how to manage processes on a remote machine using WMI
Screenshot - RemoteProcessController.png

Introduction

This article is a very small code snippet that help users to log on to a remote machine and if they have admin rights, then helps to manage the processes.

I have tried to keep the source code as simple as possible and also try to explain it here.

Application Flow

The application flow is very simple:

  1. Get the machine from domain (using active directory)
  2. Select the machine
  3. Give user name and password (either domain or machine specific)
  4. Login to remote machine
  5. On log on, list of all running processes with some details are loaded into datagridview
  6. Select any process to terminate. You can use either button or context menu
  7. If you want to start a new process, then type the name of the process and press Start

Code Walkthrough

Variable Declaration: This is the list of variables used in the program to manage the flow, WMI operations and active directory searching.

// List of domains that will be loaded in a combobox
private string []domains = {"india"};
// User name and password required to login to the selected machine
private string userName;
private string password;
private string machineName;
private string myDomain;
       
// I am using a datatable which contains 7 columns with these column names 
private string[] columnNames = { "Caption", "ComputerName", 
"Description", "Name", "Priority", "ProcessID", "SessionId" };        
// Hashtable to maintain list of machines and related users
private Hashtable hs = new Hashtable();
// Scope of the WMI operations
private ManagementScope myScope;
// Connection options to set user credentials
private ConnectionOptions connOptions;
// Retrieve list of management object based upon specific query
private ManagementObjectSearcher objSearcher;
// Handled management events
private ManagementOperationObserver opsObserver;
// Used to create new process on remote machine
private ManagementClass manageClass;
// Following are active directory objects to search users and computers
private DirectoryEntry entry;
private DirectorySearcher searcher;
private DirectorySearcher userSearcher;
private DataTable dt;
private DataColumn []dc = new DataColumn[7];

Important Functions

This method is used to get all machines available on the domain:

private void btnGetMachines_Click(object sender, EventArgs e)
{
    Cursor.Current = Cursors.WaitCursor;
            
    int index = 0;
    // Create an entry for domain
    entry = new DirectoryEntry("LDAP://" + cmbDomainList.Text);
    // Create a user searcher by using filter
    userSearcher = new DirectorySearcher(entry);
    userSearcher.Filter = ("(objectclass=user)");
    SearchResultCollection src = userSearcher.FindAll();            
    
    // Get all computers
    searcher = new DirectorySearcher(entry);
    searcher.Filter = ("(objectclass=computer)");
            
    try
    {
        // Get the result collection
        SearchResultCollection results = searcher.FindAll();
        foreach (SearchResult sr in results)
        {
            DirectoryEntry de = sr.GetDirectoryEntry();
            // Remove preceding "CN=" character string
            cmdMachinesInDomain.Items.Add(de.Name.Remove(0,3));
            // Also get the users
            DirectoryEntry de1 = src[index++].GetDirectoryEntry();
            cmbUsers.Items.Add(de1.Properties["cn"].Value.ToString());
            if (!hs.ContainsKey(de.Name))
            {
                hs.Add(de.Name.Remove(0, 3), 
                de1.Properties["cn"].Value.ToString());
            }
        }
        cmdMachinesInDomain.SelectedIndex = 0;                
        cmbUsers.SelectedIndex = 0;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        this.Cursor = Cursors.Default;
    }
}

This is a very important function as it actually connects to a remote machine and calls a WMI specific query.

private void ConnectToRemoteMachine()
{            
    int width = dataGridView1.Width;
    int singleColWidth;          
    // Make width of all columns same
    singleColWidth = width / dt.Columns.Count;
    
    userName = txtUserName.Text.Trim();
    password = txtPassword.Text.Trim();
    if (cmdMachinesInDomain.SelectedItem != null)
    {
        machineName = cmdMachinesInDomain.SelectedItem.ToString();
    }
    else if (cmdMachinesInDomain.SelectedText != string.Empty)
    {
        machineName = cmdMachinesInDomain.SelectedText;
    }
    else
    {
        machineName = cmdMachinesInDomain.Text;
    }

    myDomain = cmbDomainList.Text;

    try
    {
        connOptions = new ConnectionOptions();
        connOptions.Impersonation = ImpersonationLevel.Impersonate;
        connOptions.EnablePrivileges = true;
        // Here we can connect to machine by using domain credentials or by using 
        // machine specific credentials
        if (machineName.ToUpper() == Environment.MachineName.ToUpper())
        {
            // Create the management scope with given credentials
            myScope = new ManagementScope(@"\ROOT\CIMV2", connOptions);
        }
        else
        {
            if (chkUseDomain.Checked)
            {
                connOptions.Username = myDomain + "\\" + userName;
            }
            else
            {
                connOptions.Username = machineName + "\\" + userName;
            }
            connOptions.Password = password;
            myScope = new ManagementScope(@"\\" + machineName + 
                @"\ROOT\CIMV2", connOptions);
        }

        myScope.Connect();
        // Query on win32 process
        objSearcher = new ManagementObjectSearcher
        ("SELECT * FROM Win32_Process");
        opsObserver = new ManagementOperationObserver();
        objSearcher.Scope = myScope;
        string[] sep = { "\n", "\t" };
        toolStripStatusLabel1.Text = string.Empty;
        toolStripStatusLabel1.Text = 
        "Authentication successful. Getting processes..";
        dt.Rows.Clear();
        // Get all processes from the machine                
        foreach (ManagementObject obj in objSearcher.Get())
        {
            string caption = obj.GetText(TextFormat.Mof);
            string[] split = caption.Split
            (sep, StringSplitOptions.RemoveEmptyEntries);
            DataRow dr = dt.NewRow();
            // Iterate through the splitter
            for (int i = 0; i < split.Length; i++)
            {
                if (split[i].Split('=').Length > 1)
                {
                    // Extract the right name of the process
                    string []procDetails = split[i].Split('=');
                    procDetails[1] = procDetails[1].Replace(@"""", "");
                    procDetails[1] = procDetails[1].Replace(';', ' ');
                    switch (procDetails[0].Trim().ToLower())
                    {
                        case "caption":
                            dr[dc[0]] = procDetails[1];
                            break;
                        case "csname":
                            dr[dc[1]] = procDetails[1];
                            break;
                        case "description":
                            dr[dc[2]] = procDetails[1];
                            break;
                        case "name":
                            dr[dc[3]] = procDetails[1];
                            break;
                        case "priority":
                            dr[dc[4]] = procDetails[1];
                            break;
                        case "processid":
                            dr[dc[5]] = procDetails[1];
                            break;
                        case "sessionid":
                            dr[dc[6]] = procDetails[1];
                            break;
                    }
                }
            }
            dt.Rows.Add(dr);
        }
        bindingSource1.DataSource = dt.DefaultView;
        foreach (DataColumn col in dt.Columns)
        {
            DataGridViewTextBoxColumn dvc = new DataGridViewTextBoxColumn();
            dvc.ToolTipText = col.ColumnName;
            dvc.Name = col.ColumnName;
            dvc.HeaderText = col.ColumnName;
            dvc.DataPropertyName = col.ColumnName;
            dvc.Width = singleColWidth;
            dataGridView1.Columns.Add(dvc);
        }
        grpStartNewProcess.Enabled = true;
        btnEndProcess.Enabled = true;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        this.Cursor = Cursors.Default;
    }
}

This code snippet starts a new process on the remote machine.

private void btnStartNew_Click(object sender, EventArgs e)
{
    object[] arrParams = {txtNewProcess.Text.Trim()};
    try
    {
        manageClass =
            new ManagementClass(myScope,
        new ManagementPath("Win32_Process"), new ObjectGetOptions());
        manageClass.InvokeMethod("Create", arrParams);
        btnConnect_Click(sender, e);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

Conclusion

This way, we can have WMI used efficiently to manage processes on remote machines.

History

  • 8th March, 2007: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here