Запуск удаленных служб Windows с помощью ServiceController и олицетворения

У меня есть приложение .NET MVC3, которое должно включать и выключать удаленный сервис. Для этого я олицетворяю конкретную учетную запись пользователя через WindowsIdentity.Impersonate (). Чтобы проверить права пользователя, я могу войти как пользователь и выполнитьsc.exe \\[server] start [service] из командной строки. Я также знаю, что команда impersonate работает должным образом, потому что приложение работает анонимно и поэтому не может управлять службами на моей локальной машине (.) без подражания, ноМожно контролировать местные службы с подражанием. Однако, когда я собираю его вместе и пытаюсь запустить удаленный сервис, а не локальный сервис, я всегда получаю сообщение об ошибке «Не удается открыть[service] сервис на компьютере[server]«»

Кто-нибудь сталкивался с подобной проблемой? Я ожидал, что это будет конфигурация сервера, а не проблема .NET, пока не понял, что sc.exe работает без проблем. Вот сокращенная версия класса, который я использую:

public class Service
{
    public string Name;
    public bool Running;
    private ServiceController serviceController;

    public Service(string name, string host)
    {
        Name = name;

        serviceController = new ServiceController(Name, host);
        Running = serviceController.Status == ServiceControllerStatus.Running;
    }

    public bool StartService()
    {
        ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, serviceController.MachineName, Name);
        scp.Assert();

        serviceController.Start();
        serviceController.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 5));
        serviceController.Refresh();

        Running = serviceController.Status == ServiceControllerStatus.Running;

        return Running;
    }
}

Еще одно примечание: если вместо сервера я указываю приложение на другой ПК с Windows 7 в домене и изменяю учетные данные пользователя для этого владельца, я фактически могу удаленно управлять их службами без проблем.

По запросу я добавляю здесь код олицетворения. Это немного дольше, так что терпите меня:

public class Impersonate
{
    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_PROVIDER_DEFAULT = 0;

    WindowsImpersonationContext impersonationContext;

    [DllImport("advapi32.dll")]
    public static extern int LogonUserA(String lpszUserName,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool RevertToSelf();

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

    public bool impersonateValidUser(String userName, String domain, String password)
    {
        WindowsIdentity tempWindowsIdentity;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (RevertToSelf())
        {
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    impersonationContext = tempWindowsIdentity.Impersonate();
                    if (impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        return true;
                    }
                }
            }
        }
        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
        return false;
    }

    public void undoImpersonation()
    {
        impersonationContext.Undo();
    }
}

Я вызываю этот код непосредственно перед попыткой запустить или остановить службу:

Service s = new Service(ServiceName, MachineName);

if (Impersonation.impersonateValidUser(Username, Domain, Password))
{
    if (s.Running)
        s.StopService();
    else
        s.StartService();

    Impersonation.undoImpersonation();
}

Возможно, стоит отметить, что я могу перечислить службы и получить статус отдельной службы (как я делаю здесь) просто отлично - только когда я иду, чтобы запустить или остановить службу, у меня возникают проблемы.

Ответы на вопрос(2)

Ваш ответ на вопрос