以编程方式在远程计算机上安装Windows服务

与https://stackoverflow.com/a/467565/774828类似,它显示了如何在远程计算机上启动和停止现有Windows服务,我正在尝试在远程计算机上安装Windows服务。 我可以启动和停止远程机器上的服务,但是我无法找到如何远程安装新服务,而无需调用sc.exe进程( https://stackoverflow.com/a/1159059/774828 )如果可能的话我想避免。

我知道有一个System.Configuration.Install.ManagedInstallerClass.InstallHelper方法,但我不能让它在远程机器上安装。 而且,我无法弄清楚我是否可以使用System.ServiceProcess.ServiceInstaller或System.ServiceProcess.ServiceProcessInstaller。

执行此操作的C#代码如下:

using (var scmHandle = NativeMethods.OpenSCManager("MachineName", null, NativeMethods.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE)) { if (scmHandle.IsInvalid) { throw new Win32Exception(); } using ( var serviceHandle = NativeMethods.CreateService( scmHandle, "ServiceName", "Service Display Name", NativeMethods.SERVICE_ACCESS.SERVICE_ALL_ACCESS, NativeMethods.SERVICE_TYPES.SERVICE_WIN32_OWN_PROCESS, NativeMethods.SERVICE_START_TYPES.SERVICE_AUTO_START, NativeMethods.SERVICE_ERROR_CONTROL.SERVICE_ERROR_NORMAL, "Path to your service.exe", null, IntPtr.Zero, null, null, null)) { if (serviceHandle.IsInvalid) { throw new Win32Exception(); } NativeMethods.StartService(serviceHandle, 0, null); } } 

安全处理

处理非托管句柄时,应使用SafeHandles,以确保在C#中正确释放资源。

 [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)] [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] public class ServiceControlHandle : SafeHandleZeroOrMinusOneIsInvalid { // Create a SafeHandle, informing the base class // that this SafeHandle instance "owns" the handle, // and therefore SafeHandle should call // our ReleaseHandle method when the SafeHandle // is no longer in use. private ServiceControlHandle() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] override protected bool ReleaseHandle() { // Here, we must obey all rules for constrained execution regions. return NativeMethods.CloseServiceHandle(this.handle); // If ReleaseHandle failed, it can be reported via the // "releaseHandleFailed" managed debugging assistant (MDA). This // MDA is disabled by default, but can be enabled in a debugger // or during testing to diagnose handle corruption problems. // We do not throw an exception because most code could not recover // from the problem. } } 

P / Invoke签名

所有您需要的function的签名都可以在http://pinvoke.net上找到,整个服务控制API可以在MSDN上找到: https : //msdn.microsoft.com/en-us/library/窗户/桌面/ ms685942(v = vs.85)的.aspx

 using System; using System.Runtime.InteropServices; public static class NativeMethods { [DllImport("advapi32.dll")] public static extern ServiceControlHandle OpenSCManager(string lpMachineName, string lpSCDB, SCM_ACCESS scParameter); [DllImport("Advapi32.dll")] public static extern ServiceControlHandle CreateService( ServiceControlHandle serviceControlManagerHandle, string lpSvcName, string lpDisplayName, SERVICE_ACCESS dwDesiredAccess, SERVICE_TYPES dwServiceType, SERVICE_START_TYPES dwStartType, SERVICE_ERROR_CONTROL dwErrorControl, string lpPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword); [DllImport("advapi32.dll")] public static extern bool CloseServiceHandle(IntPtr serviceHandle); [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll")] public static extern int StartService(ServiceControlHandle serviceHandle, int dwNumServiceArgs, string lpServiceArgVectors); [DllImport("advapi32.dll", SetLastError = true)] public static extern ServiceControlHandle OpenService(ServiceControlHandle serviceControlManagerHandle, string lpSvcName, SERVICE_ACCESS dwDesiredAccess); [DllImport("advapi32.dll")] public static extern int DeleteService(ServiceControlHandle serviceHandle); [DllImport("kernel32.dll")] public static extern int GetLastError(); [Flags] public enum ACCESS_MASK : uint { DELETE = 0x00010000, READ_CONTROL = 0x00020000, WRITE_DAC = 0x00040000, WRITE_OWNER = 0x00080000, SYNCHRONIZE = 0x00100000, STANDARD_RIGHTS_REQUIRED = 0x000F0000, STANDARD_RIGHTS_READ = 0x00020000, STANDARD_RIGHTS_WRITE = 0x00020000, STANDARD_RIGHTS_EXECUTE = 0x00020000, STANDARD_RIGHTS_ALL = 0x001F0000, SPECIFIC_RIGHTS_ALL = 0x0000FFFF, ACCESS_SYSTEM_SECURITY = 0x01000000, MAXIMUM_ALLOWED = 0x02000000, GENERIC_READ = 0x80000000, GENERIC_WRITE = 0x40000000, GENERIC_EXECUTE = 0x20000000, GENERIC_ALL = 0x10000000, DESKTOP_READOBJECTS = 0x00000001, DESKTOP_CREATEWINDOW = 0x00000002, DESKTOP_CREATEMENU = 0x00000004, DESKTOP_HOOKCONTROL = 0x00000008, DESKTOP_JOURNALRECORD = 0x00000010, DESKTOP_JOURNALPLAYBACK = 0x00000020, DESKTOP_ENUMERATE = 0x00000040, DESKTOP_WRITEOBJECTS = 0x00000080, DESKTOP_SWITCHDESKTOP = 0x00000100, WINSTA_ENUMDESKTOPS = 0x00000001, WINSTA_READATTRIBUTES = 0x00000002, WINSTA_ACCESSCLIPBOARD = 0x00000004, WINSTA_CREATEDESKTOP = 0x00000008, WINSTA_WRITEATTRIBUTES = 0x00000010, WINSTA_ACCESSGLOBALATOMS = 0x00000020, WINSTA_EXITWINDOWS = 0x00000040, WINSTA_ENUMERATE = 0x00000100, WINSTA_READSCREEN = 0x00000200, WINSTA_ALL_ACCESS = 0x0000037F } [Flags] public enum SCM_ACCESS : uint { ///  /// Required to connect to the service control manager. ///  SC_MANAGER_CONNECT = 0x00001, ///  /// Required to call the CreateService function to create a service /// object and add it to the database. ///  SC_MANAGER_CREATE_SERVICE = 0x00002, ///  /// Required to call the EnumServicesStatusEx function to list the /// services that are in the database. ///  SC_MANAGER_ENUMERATE_SERVICE = 0x00004, ///  /// Required to call the LockServiceDatabase function to acquire a /// lock on the database. ///  SC_MANAGER_LOCK = 0x00008, ///  /// Required to call the QueryServiceLockStatus function to retrieve /// the lock status information for the database. ///  SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, ///  /// Required to call the NotifyBootConfigStatus function. ///  SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, ///  /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access /// rights in this table. ///  SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG, GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS, GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG, GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK, GENERIC_ALL = SC_MANAGER_ALL_ACCESS, } [Flags] public enum SERVICE_CONTROL : uint { STOP = 0x00000001, PAUSE = 0x00000002, CONTINUE = 0x00000003, INTERROGATE = 0x00000004, SHUTDOWN = 0x00000005, PARAMCHANGE = 0x00000006, NETBINDADD = 0x00000007, NETBINDREMOVE = 0x00000008, NETBINDENABLE = 0x00000009, NETBINDDISABLE = 0x0000000A, DEVICEEVENT = 0x0000000B, HARDWAREPROFILECHANGE = 0x0000000C, POWEREVENT = 0x0000000D, SESSIONCHANGE = 0x0000000E } [Flags] public enum SERVICE_ACCESS : uint { STANDARD_RIGHTS_REQUIRED = 0xF0000, SERVICE_QUERY_CONFIG = 0x00001, SERVICE_CHANGE_CONFIG = 0x00002, SERVICE_QUERY_STATUS = 0x00004, SERVICE_ENUMERATE_DEPENDENTS = 0x00008, SERVICE_START = 0x00010, SERVICE_STOP = 0x00020, SERVICE_PAUSE_CONTINUE = 0x00040, SERVICE_INTERROGATE = 0x00080, SERVICE_USER_DEFINED_CONTROL = 0x00100, SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL) } [Flags] public enum SERVICE_TYPES : int { SERVICE_KERNEL_DRIVER = 0x00000001, SERVICE_FILE_SYSTEM_DRIVER = 0x00000002, SERVICE_WIN32_OWN_PROCESS = 0x00000010, SERVICE_WIN32_SHARE_PROCESS = 0x00000020, SERVICE_INTERACTIVE_PROCESS = 0x00000100 } public enum SERVICE_ERROR_CONTROL : int { ///  /// The startup program logs the error in the event log, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration. ///  SERVICE_ERROR_CRITICAL = 0x00000003, ///  /// The startup program ignores the error and continues the startup operation. ///  SERVICE_ERROR_IGNORE = 0x00000000, ///  /// The startup program logs the error in the event log but continues the startup operation. ///  SERVICE_ERROR_NORMAL = 0x00000001, ///  /// The startup program logs the error in the event log. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration. ///  SERVICE_ERROR_SEVERE = 0x00000002, } public enum SERVICE_START_TYPES : int { ///  /// A service started automatically by the service control manager during system startup. For more information, see Automatically Starting Services. ///  SERVICE_AUTO_START = 0x00000002, ///  /// A device driver started by the system loader. This value is valid only for driver services. ///  SERVICE_BOOT_START = 0x00000000, ///  /// A service started by the service control manager when a process calls the StartService function. For more information, see Starting Services on Demand. ///  SERVICE_DEMAND_START = 0x00000003, ///  /// A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED. ///  SERVICE_DISABLED = 0x00000004, ///  /// A device driver started by the IoInitSystem function. This value is valid only for driver services. ///  SERVICE_SYSTEM_START = 0x00000001 } public enum SERVICE_STATE : uint { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007 } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SERVICE_STATUS { public static readonly int SizeOf = Marshal.SizeOf(typeof(SERVICE_STATUS)); public SERVICE_TYPES dwServiceType; public SERVICE_STATE dwCurrentState; public uint dwControlsAccepted; public uint dwWin32ExitCode; public uint dwServiceSpecificExitCode; public uint dwCheckPoint; public uint dwWaitHint; } }