C# 遠程服務器 安裝、卸載 Windows 服務,讀取遠程注冊表,關閉殺掉遠程進程


這里安裝windows服務我們用sc命令,這里需要遠程服務器IP,服務名稱、顯示名稱、描述以及執行文件,安裝后需要驗證服務是否安裝成功,驗證方法可以直接調用ServiceController來查詢服務,也可以通過遠程注冊表來查找服務的執行文件;那么卸載文件我們也就用SC命令了,卸載后需要檢測是否卸載成功,修改顯示名稱和描述也用sc命令。至於停止和啟動Windows服務我們可以用sc命令也可以用ServiceController的API,當停止失敗的時候我們會強制殺掉遠程進程,在卸載windows 服務我們需要關閉windows服務窗口,不然無法刪除服務(服務被標記為已刪除狀態)注意安裝和卸載Windows服務是通過sc命令來執行的,把sc命令發送到服務器上,服務器需要一段執行時間,所以在遠程注冊表不一定馬上體現安裝和卸載的效果,這里我們需要有一個重試的機制遠程服務需要引用System.ServiceProcess,關閉遠程進程需要引用 System.Management.dll 。先關code如下:

   #region Windows Service 操作
        /// <summary>
        /// 安裝Windows 服務
        /// </summary>
        /// <param name="serviceEXEPath">可執行文件的完全路徑</param>
        public void Install(string webIp, string serviceName, string displayName, string description, string serviceEXEPath)
        {
            //檢查安裝文件是否存在
            string remoteFile = PathUtil.GetRemotePath(webIp, serviceEXEPath);
            if (!File.Exists(remoteFile))
            {
                throw new Exception($"安裝文件{serviceEXEPath}在服務器{webIp}上不存在");
            }
            //生成安裝指令
            string serviceInstallCommand = $"sc \\\\{webIp} create {serviceName} binpath= \"{serviceEXEPath}\" displayname= \"{displayName}\" start= auto ";
            string updateDescriptionCommand = $"sc \\\\{webIp} description {serviceName} \"{description}\" ";
            string[] cmd = new string[] { serviceInstallCommand, updateDescriptionCommand };
            string ss = Cmd(cmd);
            //檢查安裝是否成功
            string imagePath = GetImagePath(webIp, serviceName);
            int retryTime = 0;
            int maxTime = 3;
            while (retryTime < maxTime && string.IsNullOrEmpty(imagePath))
            {
                Thread.Sleep(1000 * 30);
                retryTime++;
                imagePath = GetImagePath(webIp, serviceName);
            }
            if (string.IsNullOrEmpty(imagePath))
            {
                throw new Exception($"{serviceName}在{webIp}安裝失敗,{ss}");
            }
        }

        /// <summary>
        /// 卸載Windows 服務
        /// </summary>
        /// <param name="serviceEXEPath">可執行文件的完全路徑</param>
        public void Uninstall(string webIp, string serviceName, string serviceEXEPath)
        {
            //關閉mmc.exe進程,如果windows 服務打開 將無法卸載
            var ps = Process.GetProcessesByName(@"mmc", webIp);
            if (ps.Length > 0)
            {
                CloseProcess(webIp, "mmc.exe", string.Empty);
            }

            //檢查卸載文件是否存在
            string remoteFile = PathUtil.GetRemotePath(webIp, serviceEXEPath);
            if (!File.Exists(remoteFile))
            {
                throw new Exception($"卸載文件{serviceEXEPath}在服務器{webIp}上不存在");
            }

            //生成卸載命令
            string[] cmd = new string[] { $"sc \\\\{webIp} stop {serviceName}", $"sc \\\\{webIp} delete {serviceName}" };
            string ss = Cmd(cmd);
            string imagePath = GetImagePath(webIp, serviceName);
            //檢查卸載是否成功
            int retryTime = 0;
            int maxTime = 3;
            while (retryTime < maxTime && !string.IsNullOrEmpty(imagePath))
            {
                Thread.Sleep(1000 * 30);
                retryTime++;
                imagePath = GetImagePath(webIp, serviceName);
            }
            if (!string.IsNullOrEmpty(imagePath))
            {
                throw new Exception($"{serviceName}在{webIp}卸載失敗,{ss}");
            }
        }

        /// <summary>
        /// 修改windows 服務的顯示名稱和描述
        /// </summary>
        /// <param name="webIp"></param>
        /// <param name="serviceName"></param>
        /// <param name="displayName"></param>
        /// <param name="description"></param>
        public void UpdateDisplayNameAndDescription(string webIp, string serviceName, string displayName, string description)
        {
            //檢查服務是否存在
            string imagePath = GetImagePath(webIp, serviceName);
            if (string.IsNullOrEmpty(imagePath))
            {
                throw new Exception($"服務{serviceName}在{webIp}不存在");
            }
            //生成修改指令
            string updateDispalyNameCommand = $"sc \\\\{webIp} config {serviceName} displayname= \"{displayName}\"";
            string updateDescriptionCommand = $"sc \\\\{webIp} description {serviceName} \"{description}\" ";
            string[] cmd = new string[] { updateDispalyNameCommand, updateDescriptionCommand };
            string ss = Cmd(cmd);
        }

        /// <summary>
        /// sc 停止和啟動windows服務
        /// </summary>
        /// <param name="webIp"></param>
        /// <param name="serviceName"></param>
        /// <param name="stop"></param>
        public void StopAndStartService(string webIp, string serviceName, bool stop)
        {
            string serviceCommand = $"sc \\\\{webIp} {(stop ? "stop" : "start")} {serviceName}";//停止或啟動服務  
            string[] cmd = new string[] { serviceCommand };
            string ss = Cmd(cmd);
        }

        /// <summary>  
        /// 運行CMD命令  
        /// </summary>  
        /// <param name="cmd">命令</param>  
        /// <returns></returns>  
        public string Cmd(string[] cmd)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            p.StandardInput.AutoFlush = true;
            for (int i = 0; i < cmd.Length; i++)
            {
                p.StandardInput.WriteLine(cmd[i].ToString());
            }
            p.StandardInput.WriteLine("exit");
            string strRst = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            p.Close();
            return strRst;
        }

        /// <summary>
        /// 關閉遠程計算機進程
        /// </summary>
        /// <param name="webIp"></param>
        /// <param name="processName"></param>
        public void CloseProcess(string webIp, string processName, string executablePath)
        {
            ConnectionOptions oOptions = new ConnectionOptions();
            oOptions.Authentication = AuthenticationLevel.Default;
            ManagementPath oPath = new ManagementPath($"\\\\{webIp}\\root\\cimv2");
            ManagementScope oScope = new ManagementScope(oPath, oOptions);
            ObjectQuery oQuery = new ObjectQuery($"Select * From Win32_Process Where Name = \"{processName}\"");
            using (ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oScope, oQuery))
            {
                foreach (ManagementObject oManagementObject in oSearcher.Get())
                {
                    if (oManagementObject["Name"].ToString().ToLower() == processName.ToLower())
                    {
                        /*
                            foreach (PropertyData prop in oManagementObject.Properties)
                            {
                                Console.WriteLine($"      {prop.Name} -- -  {prop.Value } ");
                            }
                         */
                        string path = oManagementObject["ExecutablePath"].ToString();
                        if (string.IsNullOrEmpty(executablePath) || path == executablePath)
                        {
                            oManagementObject.InvokeMethod("Terminate", new object[] { 0 });
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 獲取遠程計算機 服務的執行文件
        /// </summary>
        /// <param name="serverIP">遠程計算機IP</param>
        /// <param name="serviceName">遠程服務名稱</param>
        /// <returns></returns>
        public string GetImagePath(string serverIP, string serviceName)
        {
            string registryPath = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
            using (RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, serverIP).OpenSubKey(registryPath))
            {
                if (key == null)
                {
                    return string.Empty;
                }
                string value = key.GetValue("ImagePath").ToString();
                key.Close();
                value = value.Trim('"');
                if (value.Contains("SystemRoot"))
                {
                    return ExpandEnvironmentVariables(serverIP, value);
                }
                return value;
            }
        }

        /// <summary>
        /// 替換路徑中的SystemRoot
        /// </summary>
        /// <param name="serverIP">遠程計算機IP</param>
        /// <param name="path">路徑</param>
        /// <returns></returns>
        private string ExpandEnvironmentVariables(string serverIP, string path)
        {
            string systemRootKey = @"Software\Microsoft\Windows NT\CurrentVersion\";
            using (RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, serverIP).OpenSubKey(systemRootKey))
            {
                string expandedSystemRoot = key.GetValue("SystemRoot").ToString();
                key.Close();
                path = path.Replace("%SystemRoot%", expandedSystemRoot);
                return path;
            }
        }

        /// <summary>
        /// 停止或啟動Windows 服務
        /// </summary>
        /// <param name="serviceName">服務名稱</param>
        /// <param name="serverIP">遠程IP</param>
        /// <param name="stop">是否是停止</param>
        public void StopAndStartWindowsService(string serviceName, string serverIP, bool stop)
        {
            using (ServiceController sc = ServiceController.GetServices(serverIP)
                            .FirstOrDefault(x => x.ServiceName == serviceName))
            {
                if (sc == null)
                {
                    throw new Exception($"{serviceName}不存在於{serverIP}");
                }
                StopAndStartWindowsService(sc, stop);

                if (stop)
                {
                    sc.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 1, 0));
                }
                sc.Close();
            }


        }

        /// <summary>
        /// 停止或啟動Windows 服務
        /// </summary>
        /// <param name="sc"></param>
        /// <param name="stop"></param>
        private void StopAndStartWindowsService(ServiceController sc, bool stop = true)
        {
            Action act = () =>
            {
                ServiceControllerStatus serviceSate = sc.Status;
                if (stop && (serviceSate == ServiceControllerStatus.StartPending || serviceSate == ServiceControllerStatus.Running))
                {
                    //如果當前應用程序池是啟動或者正在啟動狀態,調用停止方法
                    sc.Stop();
                }
                if (!stop && (serviceSate == ServiceControllerStatus.Stopped || serviceSate == ServiceControllerStatus.StopPending))
                {
                    sc.Start();
                }
            };
            int retryCount = 0;
            int maxCount = 4;
            while (sc != null && retryCount <= maxCount)
            {
                try
                {
                    act();
                    break;
                }
                catch (Exception ex)
                {
                    if (stop)
                    {
                        string serverIP = sc.MachineName;
                        string serviceName = sc.ServiceName;
                        var imeagePath = GetImagePath(serverIP, serviceName);
                        FileInfo fileInfo = new FileInfo(imeagePath);
                        CloseProcess(serverIP, fileInfo.Name, fileInfo.FullName);
                    }
                    retryCount++;
                    if (retryCount == maxCount)
                    {
                        throw new Exception($"{(stop ? "停止" : "啟動")}Windows服務{sc.ServiceName}出錯{ex.Message}");
                    }
                    Thread.Sleep(1000 * 30);
                }
            }//end while
        }

        /// <summary>
        /// 獲取windows 服務狀態
        /// </summary>
        /// <param name="serviceName">服務名稱</param>
        /// <param name="serverIP">服務器IP</param>
        /// <returns></returns>
        public ServiceControllerStatus GetServiceState(string serviceName, string serverIP)
        {
            ServiceControllerStatus serviceSate;
            using (ServiceController sc = ServiceController.GetServices(serverIP)
                            .FirstOrDefault(x => x.ServiceName == serviceName))
            {
                if (sc == null)
                {
                    throw new Exception($"{serviceName}不存在於{serverIP}");
                }
                serviceSate = sc.Status;
                sc.Close();
            }
            return serviceSate;
        }

        #endregion

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM