使用 C# 检查在远程计算机上运行的服务的状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1335065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:17:03  来源:igfitidea点击:

Check status of services that run in a remote computer using C#

c#windowswindows-servicesremote-access

提问by

I'm using the following code.

我正在使用以下代码。

ServiceController MyController = new ServiceController();
MyController.MachineName = server_txt.Text.Trim();
MyController.ServiceName = "Service1";

string msg = MyController.Status.ToString();
Label1.Text = msg;

This code works fine for network computers where I have access. How to change this so it works for the systems in different domains using credentials?

此代码适用于我可以访问的网络计算机。如何更改它以使其适用于使用凭据的不同域中的系统?

回答by user797717

If you use WMI, you can set the credentials in 'ConnectionOptions'.

如果您使用 WMI,则可以在“ConnectionOptions”中设置凭据。

ConnectionOptions op = new ConnectionOptions();
op.Username = "Domain\Domainuser";
op.Password = "password";
ManagementScope scope = new ManagementScope(@"\Servername.Domain\root\cimv2", op);
scope.Connect();
ManagementPath path = new ManagementPath("Win32_Service");
ManagementClass services;
services = new ManagementClass(scope, path, null);

foreach (ManagementObject service in services.GetInstances())
{

if (service.GetPropertyValue("State").ToString().ToLower().Equals("running"))
{ // Do something }

}

回答by vapcguy

MSDN is your friend.:)

MSDN 是你的朋友。:)

If you DO have admin privileges on that machine, this code will work perfectly fine:

如果您确实在该机器上拥有管理员权限,则此代码将正常运行:

using System.ServiceProcess;

ServiceController sc = new ServiceController("YourService", "MachineName");
if (sc.Status.Equals(ServiceControllerStatus.Stopped) || 
    sc.Status.Equals(ServiceControllerStatus.StopPending))
{
    // it is stopped
}

Otherwise, as it has been mentioned in another comment, you would likely have to set this up with impersonation if the account you are running under does not have admin privileges on that machine, like so:

否则,正如在另一条评论中提到的那样,如果您运行的帐户在该计算机上没有管理员权限,您可能必须通过模拟进行设置,如下所示:

string userName = "domain\user"; // there's really just one slash, 
//but you have to escape it if hard-coding.. 
//if brought in by a text box, it would be just domain\user

string password = "whatever";

WindowsImpersonationContext adminContext = Impersonation.getWic(userName, password);
if (adminContext != null)
{
   try
   {
        ServiceController sc = new ServiceController("YourService", "MachineName");
        if (sc.Status.Equals(ServiceControllerStatus.Stopped) || 
            sc.Status.Equals(ServiceControllerStatus.StopPending))
        {
            // it is stopped
        }
    }
    catch (Exception ex)
    {
        Console.Out.WriteLine("\nUnable to set profile to Mandatory:\n\t" + ex.Message);
        Impersonation.endImpersonation();
        adminContext.Undo();
    }
    finally
    {
        Impersonation.endImpersonation();
        // The above line just basically does this on the tokens --            
        //if (tokenHandle != IntPtr.Zero) CloseHandle(tokenHandle);
        adminContext.Undo();
    }
}

This is my separate Impersonation class. It has 2 main entry points, getWic()and doImpersonation()-- getWic()will take a username that looks like domain\useror machinename\userand split them up into their component parts before handing it off to doImpersonation(), while doImpersonation()accepts the parts already split, if you have it like that and don't need the code in getWic(). Both return a WindowsImpersonationContext.

这是我单独的 Impersonation 类。它有 2 个主要入口点,getWic()并且doImpersonation()--getWic()将使用一个看起来像domain\user或的用户名,machinename\user然后将它们拆分为它们的组成部分,然后再将其交给doImpersonation(),同时doImpersonation()接受已经拆分的部分,如果您有这样的并且不需要中的代码getWic()。两者都返回 a WindowsImpersonationContext

using System;
using System.Data;
using System.Configuration;
using System.Security.Permissions;
using System.Security.Principal;
using System.Runtime.InteropServices;

[assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode = true)]
[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")]
public class Impersonation
{
    [DllImport("advapi32.dll", EntryPoint = "LogonUser")]
    public static extern bool LogonUser(
        string lpszUsername,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
        int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    // Declare the Logon Types as constants
    const int LOGON32_LOGON_INTERACTIVE = 2;
    const int LOGON32_LOGON_NETWORK = 3;
    const int LOGON32_LOGON_BATCH = 4;
    const int LOGON32_LOGON_SERVICE = 5;
    const int LOGON32_LOGON_UNLOCK = 7;
    const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8; // Win2K or higher   
    const int LOGON32_LOGON_NEW_CREDENTIALS = 9; // Win2K or higher

    // Declare the Logon Providers as constants
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_PROVIDER_WINNT50 = 3;
    const int LOGON32_PROVIDER_WINNT40 = 2;
    const int LOGON32_PROVIDER_WINNT35 = 1;

    // Declare the Impersonation Levels as constants
    const int SecurityAnonymous = 0;
    const int SecurityIdentification = 1;
    const int SecurityImpersonation = 2;
    const int SecurityDelegation = 3;

    private static WindowsIdentity newId;
    private static IntPtr tokenHandle = new IntPtr(0);
    private static IntPtr dupeTokenHandle = new IntPtr(0);

    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public static WindowsImpersonationContext doImpersonation(string svcUserName, string domainName, string password)
    {
        // Initialize tokens
        tokenHandle = IntPtr.Zero;
        dupeTokenHandle = IntPtr.Zero;

        // Call LogonUser to obtain a handle to an access token
        bool returnValue = LogonUser(svcUserName, domainName, password,
        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_WINNT50, ref tokenHandle);

        if (returnValue == false)
        {
            int ret = Marshal.GetLastWin32Error();

            //Check for errors
            if (ret != NO_ERROR)
                throw new Exception("LogonUser failed with error code : " + GetError(ret));
        }

        bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
        if (retVal == false)
        {
            CloseHandle(tokenHandle);
            throw new Exception("Exception thrown in trying to duplicate token.");
        }
        else
        {
            // Begin Impersonation
            bool bRetVal = DuplicateToken(tokenHandle,
            (int)SecurityImpersonation, ref dupeTokenHandle);

            newId = new WindowsIdentity(dupeTokenHandle);
            WindowsImpersonationContext impersonatedUser = newId.Impersonate();
            return impersonatedUser;
        }
    }

    public static void endImpersonation()
    {
        if (dupeTokenHandle != IntPtr.Zero)
            CloseHandle(dupeTokenHandle);
        if (tokenHandle != IntPtr.Zero)
            CloseHandle(tokenHandle);
    }

    public static WindowsImpersonationContext getWic(string userNameStringFromTextbox, string password)
    {
        try
        {
            // Establish impersonation
            string svcUser = userNameStringFromTextbox;
            string[] arrUser = new string[2];
            arrUser = svcUser.Split('\');
            string domain = arrUser[0];
            string svcUserName = arrUser[1];

            // Get Password:  Convert from Base-64 String to decrypted string            
            //string keyLength = ConfigurationManager.AppSettings["keyLength"].ToString();
            //string keyLocation = ConfigurationManager.AppSettings["keyLocation"].ToString();
            //password = RSAEncrypt.DecryptData(password, keyLength, keyLocation);

            WindowsImpersonationContext wic = doImpersonation(svcUserName, domain, password);
            return wic;
        }
        catch (Exception ex)
        {
            ErrorLog.ErrorRoutine(new Exception("getWic() Error: " + ex.ToString()), ErrorMessage.NOTIFY_APP_ERROR);
            return null;
        }
    }

    #region Errors
    const int NO_ERROR = 0;

    const int ERROR_ACCESS_DENIED = 5;
    const int ERROR_ALREADY_ASSIGNED = 85;
    const int ERROR_BAD_DEVICE = 1200;
    const int ERROR_BAD_NET_NAME = 67;
    const int ERROR_BAD_PROVIDER = 1204;
    const int ERROR_CANCELLED = 1223;
    const int ERROR_EXTENDED_ERROR = 1208;
    const int ERROR_INVALID_ADDRESS = 487;
    const int ERROR_INVALID_PARAMETER = 87;
    const int ERROR_INVALID_PASSWORD = 1216;
    const int ERROR_MORE_DATA = 234;
    const int ERROR_NO_MORE_ITEMS = 259;
    const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    const int ERROR_NO_NETWORK = 1222;
    const int ERROR_SESSION_CREDENTIAL_CONFLICT = 1219;

    const int ERROR_BAD_PROFILE = 1206;
    const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    const int ERROR_DEVICE_IN_USE = 2404;
    const int ERROR_NOT_CONNECTED = 2250;
    const int ERROR_OPEN_FILES = 2401;

    private struct ErrorClass
    {
        public int num;
        public string message;
        public ErrorClass(int num, string message)
        {
            this.num = num;
            this.message = message;
         }
    }

    private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
        new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
        new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
        new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
        new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
        new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
        new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
        new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
        new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
        new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
        new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
        new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
        new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
        new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
        new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
        new ErrorClass(ERROR_SESSION_CREDENTIAL_CONFLICT, "Error: Credential Conflict"),
        new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
        new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
        new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
        new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
        new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
    };

    private static string GetError(int errNum)
    {
        foreach (ErrorClass er in ERROR_LIST)
        {
            if (er.num == errNum) return er.message;
        }
        return "Error: Unknown, " + errNum;
    }
    #endregion
}

References:ServiceController Class. https://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller(v=vs.110).aspx

参考资料:ServiceController 类。https://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller(v=vs.110).aspx

WindowsIdentity.Impersonate Method. https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx

WindowsIdentity.Impersonate 方法。 https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx