如何设置Windows服务登录凭据?

如何使用c#以编程方式为任意Windows服务设置“登录”凭据(wmi / interop很好)?

注意,我的程序是以管理员身份运行的,我需要保持更改(对于所有后续服务重新启动)

理想情况下,该方法具有以下sig:

void SetWindowsServiceCreds(string serviceName, string username, string password) { // TODO write me } 

 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ChangeServiceConfig(IntPtr hService, UInt32 nServiceType, UInt32 nStartType, UInt32 nErrorControl, String lpBinaryPathName, String lpLoadOrderGroup, IntPtr lpdwTagId, String lpDependencies, String lpServiceStartName, String lpPassword, String lpDisplayName); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] internal static extern IntPtr OpenSCManager( string machineName, string databaseName, uint dwAccess); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded); [StructLayout(LayoutKind.Sequential)] public class QUERY_SERVICE_CONFIG { [MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)] public UInt32 dwServiceType; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)] public UInt32 dwStartType; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)] public UInt32 dwErrorControl; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] public String lpBinaryPathName; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] public String lpLoadOrderGroup; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.U4)] public UInt32 dwTagID; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] public String lpDependencies; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] public String lpServiceStartName; [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)] public String lpDisplayName; }; private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F; private const uint SERVICE_QUERY_CONFIG = 0x00001; private const uint SERVICE_CHANGE_CONFIG = 0x00002; private const uint SERVICE_NO_CHANGE = 0xffffffff; private const int ERROR_INSUFFICIENT_BUFFER = 122; public static void SetWindowsServiceCreds(string serviceName, string username, string password) { IntPtr hManager = IntPtr.Zero; IntPtr hService = IntPtr.Zero; try { hManager = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); if (hManager == IntPtr.Zero) { ThrowWin32Exception(); } hService = OpenService(hManager, serviceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG); if (hService == IntPtr.Zero) { ThrowWin32Exception(); } if (!ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, username, password, null)) { ThrowWin32Exception(); } } finally { if (hService != IntPtr.Zero) CloseServiceHandle(hService); if (hManager != IntPtr.Zero) CloseServiceHandle(hManager); } } private static void ThrowWin32Exception() { int error = Marshal.GetLastWin32Error(); Win32Exception e = new Win32Exception(error); throw e; } 

这也有效:

  void SetWindowsServiceCreds(string serviceName, string username, string password) { string objPath = string.Format("Win32_Service.Name='{0}'", serviceName); using (ManagementObject service = new ManagementObject(new ManagementPath(objPath))) { object[] wmiParams = new object[10]; wmiParams[6] = username; wmiParams[7] = password; service.InvokeMethod("Change", wmiParams); } }