.net 使用ServiceController和模拟启动远程Windows服务
我有一个.NETMVC3应用程序,需要能够打开和关闭远程服务。为此,我正在通过WindowsIdentity.Impersonate()模拟特定的用户帐户。要测试用户的权限,我可以以用户身份登录,并从命令提示符下执行.net 使用ServiceController和模拟启动远程Windows服务,.net,windows-services,impersonation,servicecontroller,.net,Windows Services,Impersonation,Servicecontroller,我有一个.NETMVC3应用程序,需要能够打开和关闭远程服务。为此,我正在通过WindowsIdentity.Impersonate()模拟特定的用户帐户。要测试用户的权限,我可以以用户身份登录,并从命令提示符下执行sc.exe\\[server]start[service]。我还知道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 PC而不是服务器,并将模拟凭据更改为该PC所有者的凭据,那么我实际上可以毫无问题地远程控制他们的服务
根据请求,我在这里添加模拟代码。时间长了一点,请耐心听我说:
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();
}
可能值得注意的是,我可以列出服务并获取单个服务的状态(就像我在这里所做的那样)——只有在启动或停止服务时,我才会遇到麻烦。也许我已经找到了答案: 在模拟方法中LogonUserA 使用LOGON32\u LOGON\u服务(=5)代替LOGON32\u LOGON\u INTERACTIVE 确保您模拟的用户与运行该服务的用户相同 在我的例子中,用户包含在本地策略-->启动会话作为服务中。我没有与未包含在该本地策略中的用户进行测试
希望有帮助 如果要模拟的用户是机器管理员,那么这是正确的。如果不是,则必须授予用户启动服务的特定权限 由于我不是网络管理员,我不知道如何制作,但我找到了这个链接,它解释了如何使用subinacl工具进行操作:
- subinacl/service SERVICENAME/grant=DOMAINNAME\USERNAME Users=TO
在这种情况下,您必须使用交互模式模拟用户,而不是使用服务模式您能显示执行模拟的代码吗?我想这可能就是问题所在。@Competable\u tech感谢您的帮助。我已在问题中添加了与模拟相关的代码。您是使用AD域作为域还是使用运行该服务的本地计算机?如果您要模拟的用户是计算机管理员,这是正确的。