我有一个以mydomain \ userA身份运行的Windows服务。我希望能够从该服务运行任意.exe。通常,我使用Process.Start()并且它可以正常工作,但是在某些情况下,我想以其他用户(mydomain \ userB)的身份运行可执行文件。
如果更改了用于启动过程以包括凭据的ProcessStartInfo,则会开始出现错误- 一个错误对话框,提示“应用程序无法正确初始化(0xc0000142)。单击OK终止应用程序。”或“访问被拒绝” Win32Exception。如果我从命令行运行流程启动代码而不是在服务中运行它,则该流程将开始使用正确的凭据(我已通过将ProcessStartInfo设置为运行whoami.exe并捕获命令行输出来验证了这一点。 )。
我还尝试使用WindowsIdentity.Impersonate()模拟,但这没有用- 据我了解,模拟仅会影响当前线程,而启动新进程将继承该进程的安全描述符,而不继承当前线程。
我在一个隔离的测试域中运行它,因此userA和userB都是域管理员,并且都具有域范围内的“登录即服务”权限。
使用ProcessStartInfo启动新进程时,该进程在与启动进程相同的窗口站和桌面中启动。如果您使用不同的凭据,则用户通常将没有足够的权限在该桌面上运行。初始化错误失败是由于user32.dll尝试在新进程中进行初始化而无法进行的。
要解决此问题,您必须首先检索与Window Station和桌面相关联的安全描述符,并为用户添加适当的权限到DACL,然后在新的凭据下启动进程。
编辑:关于如何执行此操作和示例代码的详细说明在这里有点长了,所以我整理了一篇代码文章。
//The following security adjustments are necessary to give the new //process sufficient permission to run in the service's window station //and desktop. This uses classes from the AsproLock library also from //Asprosys. IntPtr hWinSta = GetProcessWindowStation(); WindowStationSecurity ws = new WindowStationSecurity(hWinSta, System.Security.AccessControl.AccessControlSections.Access); ws.AddAccessRule(new WindowStationAccessRule("LaunchProcessUser", WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); ws.AcceptChanges(); IntPtr hDesk = GetThreadDesktop(GetCurrentThreadId()); DesktopSecurity ds = new DesktopSecurity(hDesk, System.Security.AccessControl.AccessControlSections.Access); ds.AddAccessRule(new DesktopAccessRule("LaunchProcessUser", DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); ds.AcceptChanges(); EventLog.WriteEntry("Launching application.", EventLogEntryType.Information); using (Process process = Process.Start(psi)) { }