2010-12-19 67 views
5

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

注意,我的程序运行作为一个系统管理员,我需要坚持(对于所有后续的服务重新启动)的变化

理想的情况下,该方法具有以下签名:

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

回答

7
[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;    
} 
+0

我选择了这个,导致它涉及较少的依赖关系,并可能提供更丰富的呃ror消息 – 2010-12-19 22:19:33

6

这作品以及:

 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); 
      } 

     } 
+0

似乎无法将凭证更改为任何内置帐户(空密码)。 invoke调用会引发一个InvalidOperationException异常,并显示消息“操作由于对象的当前状态而无效”。即使服务处于停止状态,也会发生这种情况。 – BrutalDev 2015-03-25 06:29:06

相关问题