Note that there are some explanatory texts on larger screens.

plurals
  1. POStarting remote Windows services with ServiceController and impersonation
    text
    copied!<p>I have a .NET MVC3 application that needs to be able to turn a remote service on and off. In order to do this I am impersonating a specific user account via WindowsIdentity.Impersonate(). To test the user's permissions I can log in as the user and execute <code>sc.exe \\[server] start [service]</code> from the command prompt. I also know that the impersonate command is working as expected because the application runs anonymously and therefore cannot control services on my local machine (<code>.</code>) without impersonation, but <em>can</em> control local services with impersonation. However, when I put it together and attempt to start the remote service rather than local service I always get the error "Cannot open <code>[service]</code> service on computer '<code>[server]</code>'"</p> <p>Has anyone ever experienced a similar issue? I was expecting it to be a server configuration rather than .NET issue until I realized that sc.exe works without issue. Here is an abbreviated version of the class that I am using:</p> <pre><code>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; } } </code></pre> <p>One additional note: If instead of the server I point the application at another Windows 7 PC on the domain and change the impersonation credentials to those of the owner of that PC, I am actually able to remotely control their services without issue.</p> <p>Per request, I am adding the impersonation code here. It is a little longer so bear with me:</p> <pre><code>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(); } } </code></pre> <p>I call this code just before attempting to start or stop the service:</p> <pre><code>Service s = new Service(ServiceName, MachineName); if (Impersonation.impersonateValidUser(Username, Domain, Password)) { if (s.Running) s.StopService(); else s.StartService(); Impersonation.undoImpersonation(); } </code></pre> <p>It may be worth noting that I can list the services and get the status of an individual service (as I do here) just fine - it is only when I go to start or stop the service that I run into trouble.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload