Search code examples
c#servicecontroller

C# Service Status On Remote Machine


I'm an expert programmer, so therefore, I don't have a clue as to WTH I'm doing :)

On a serious note; no, I'm not expert by any means. I do have a problem though, and don't know how to fix it. The good thing is, I (think I) know what the problem is, and I'm hoping someone here can help.

Here's the synopsis of the problem. I am creating a form in C# that will do some server and database administration task for me. I have a button that when clicked is supposed to return the service status of "x" service on "y" server. The status is printed on the screen to a textbox.

Here's my code:

     private void button2_Click(object sender, EventArgs e)
    {
        string fs = "Service X Status = ";
        string mr = "Service A Status = ";
        string qp = "Service B Status = ";
        string sp = "Spooler Service Status = ";
        ServiceController fssc = new ServiceController("xService", "yServer");
        ServiceController mrsc = new ServiceController("aService", "yServer");
        ServiceController qpsc = new ServiceController("bService", "yServer");
        ServiceController spsc = new ServiceController("Spooler", "yServer");

        try
        {
            txtGtwySts.AppendText(sp + spsc.Status.ToString());
            txtGtwySts.AppendText(Environment.NewLine);
            txtGtwySts.AppendText(fs + fssc.Status.ToString());
            txtGtwySts.AppendText(Environment.NewLine);
            txtGtwySts.AppendText(mr + mrsc.Status.ToString());
            txtGtwySts.AppendText(Environment.NewLine);
            txtGtwySts.AppendText(qp + qpsc.Status.ToString());
        }
        catch (Exception crap)
        {
            string msg = "";
            int i;
            for (i = 0; i < crap.Message.Count(); i++)
            {
                msg += "Error # " + i + " Message: " + crap.Message + "\n";

            }
            MessageBox.Show(msg);
            MessageBox.Show(i.ToString());
        }
    }

I get exceptions, basically saying: Cannot Open "Service" on "Server." Since this is a remote server, I'm assuming this is a credential/security problem. I do NOT, however, have any problems with the Spooler service.

My question is...How can I pass userID and password to this server so that it will authenticate or runas so I can check the status of these services, it that is the problem. If someone doesnt think its the problem, then please inform me where I've went wrong :)


Solution

  • Finally figured it out...

    Created a new class, and is shown below:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    
    public class ImpersonateUser
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(
        String lpszUsername,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
        private static IntPtr tokenHandle = new IntPtr(0);
        private static WindowsImpersonationContext impersonatedUser;
        // If you incorporate this code into a DLL, be sure to demand that it
        // runs with FullTrust.
        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public void Impersonate(string domainName, string userName, string password)
        {
            //try
            {
                // Use the unmanaged LogonUser function to get the user token for
                // the specified user, domain, and password.
                const int LOGON32_PROVIDER_DEFAULT = 0;
                // Passing this parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;
                tokenHandle = IntPtr.Zero;
                // ---- Step - 1
                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(
                userName,
                domainName,
                password,
                LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle); // tokenHandle - new security token
                if (false == returnValue)
                {
                    int ret = Marshal.GetLastWin32Error();
                    throw new System.ComponentModel.Win32Exception(ret);
                }
                // ---- Step - 2
                WindowsIdentity newId = new WindowsIdentity(tokenHandle);
                // ---- Step - 3
                {
                    impersonatedUser = newId.Impersonate();
                }
            }
        }
        // Stops impersonation
        public void Undo()
        {
            impersonatedUser.Undo();
            // Free the tokens.
            if (tokenHandle != IntPtr.Zero)
            {
                CloseHandle(tokenHandle);
            }            
        }        
    }    
    

    }

    and the original code that I posted is wrapped by:

    ImpersonateUser iu = new ImpersonateUser();
    iu.Impersonate("[domain]","[username]","[password]");
    // code you want to execute as impersonated user.....
    iu.Undo();