C#IISRESET服務

最近要寫個從頁面上點擊IISRESET按鈕,就把服務器IISREST的功能。


難點:

1. IISREST後程序池停掉,失去EnvAgent的連接,response會失去,就不能返回狀態,來判斷是否IISRESET成功

2. IISREST由於成功率不高,必須判斷是否成功啓動,要是沒有成功啓動,影響很大,所以想到如下方法判斷:

IISRESET >D:\\tmplog.txt

該命令會把執行結果放到D:\\tmplog.txt中,如果內容如下就可以判斷是啓動成功了

正在嘗試停止...
Internet 服務已成功停止
正在嘗試啓動...
Internet 服務已成功啓動

所以,思路如下:

先發送請求,執行 “IISRESET >D:\\tmplog.txt”這條命令

在等待一定時間,如40秒(等程序池啓動起來),發送檢查結果命令,

該命令判斷tmplog.txt文件是否是最新的(最後修改時間是否是一分鐘內),

再判斷內容是否正確,

如果都正確,則IISRESET成功


(該代碼已被淘汰,複製請看最後的代碼)


核心代碼如下

#region IISRest
        /// <summary>
        /// IISRESRT
        /// </summary>
        public static void IISReset()
        {
            try
            {
                Logger.Info("IIS Reset Start");
                string filePath = "d:\\templog.txt";
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;    //是否使用操作系統shell啓動
                p.StartInfo.RedirectStandardInput = true;//接受來自調用程序的輸入信息
                p.StartInfo.RedirectStandardOutput = true;//由調用程序獲取輸出信息
                p.StartInfo.RedirectStandardError = true;//重定向標準錯誤輸出
                p.StartInfo.CreateNoWindow = true;//不顯示程序窗口
                p.Start();//啓動程序
                //向cmd窗口發送輸入信息
                p.StandardInput.WriteLine("IISRESET > " + filePath + "&exit");
                p.StandardInput.AutoFlush = true;
                //p.StandardInput.WriteLine("exit");
                //向標準輸入寫入要執行的命令。這裏使用&是批處理命令的符號,表示前面一個命令不管是否執行成功都執行後面(exit)命令,如果不執行exit命令,後面調用ReadToEnd()方法會假死
                //同類的符號還有&&和||前者表示必須前一個命令執行成功纔會執行後面的命令,後者表示必須前一個命令執行失敗纔會執行後面的命令
                //獲取cmd窗口的輸出信息
                //string output = p.StandardOutput.ReadToEnd();
                //StreamReader reader = p.StandardOutput;
                //string line=reader.ReadLine();
                //while (!reader.EndOfStream)
                //{
                //    str += line + "  ";
                //    line = reader.ReadLine();
                //}
                p.WaitForExit();//等待程序執行完退出進程
                p.Close();
            }
            catch (Exception ex)
            {
                Logger.Error("IIS Reset Exception:" + ex.ToString());
            }
            Logger.Info("IIS Reset Finish");
            //Console.WriteLine(output);   
        }
        /// <summary>
        /// IISRESRT
        /// </summary>
        public static void IISReset(string ip)
        {
            try
            {
                Logger.Info("IIS Reset Start");
                string filePath = "d:\\templog.txt";
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;    //是否使用操作系統shell啓動
                p.StartInfo.RedirectStandardInput = true;//接受來自調用程序的輸入信息
                p.StartInfo.RedirectStandardOutput = true;//由調用程序獲取輸出信息
                p.StartInfo.RedirectStandardError = true;//重定向標準錯誤輸出
                p.StartInfo.CreateNoWindow = true;//不顯示程序窗口
                p.Start();//啓動程序
                //向cmd窗口發送輸入信息
                p.StandardInput.WriteLine("iisreset \\"+ip+" /restart >" + filePath + "&exit");
                p.StandardInput.AutoFlush = true;
                //p.StandardInput.WriteLine("exit");
                //向標準輸入寫入要執行的命令。這裏使用&是批處理命令的符號,表示前面一個命令不管是否執行成功都執行後面(exit)命令,如果不執行exit命令,後面調用ReadToEnd()方法會假死
                //同類的符號還有&&和||前者表示必須前一個命令執行成功纔會執行後面的命令,後者表示必須前一個命令執行失敗纔會執行後面的命令
                //獲取cmd窗口的輸出信息
                //string output = p.StandardOutput.ReadToEnd();
                //StreamReader reader = p.StandardOutput;
                //string line=reader.ReadLine();
                //while (!reader.EndOfStream)
                //{
                //    str += line + "  ";
                //    line = reader.ReadLine();
                //}
                p.WaitForExit();//等待程序執行完退出進程
                p.Close();
            }
            catch (Exception ex)
            {
                Logger.Error("IIS Reset Exception:" + ex.ToString());
            }
            Logger.Info("IIS Reset Finish");
            //Console.WriteLine(output);   
        }
        /// <summary>
        /// 判斷IISReset是否成功 (已在IISControl中實現,這邊代碼不完全)
        /// 
        /// 由於IISReset後會失去返回,所以需要重新發送請求來獲取IISReset的結果
        /// 這裏採用很短時間段裏面檢查IISREST時記錄在d:\\templog.txt中的日記來判斷
        /// 
        /// 需要判斷文件的時間某段時間內,並且內容是重啓正確
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool IsResetSuccess()
        {
            string filePath = "d:\\templog.txt";
            return File.ReadAllText(filePath).Trim().Equals("正在嘗試停止...\r\r\nInternet 服務已成功停止\r\r\n正在嘗試啓動...\r\r\nInternet 服務已成功啓動");
        }
        /// <summary>
        /// 獲取 IISRESET 日記內容
        /// </summary>
        /// <returns></returns>
        public static string GetIISResetLog()
        {
            string filePath = "d:\\templog.txt";
            return File.ReadAllText(filePath, Encoding.Default).Trim();
        }
        /// <summary>
        /// 獲取 IISREST 日記文件的時間差,來判斷是否是最近這次的日記
        /// </summary>
        /// <returns></returns>
        public static string IISResetTimeSpan()
        {
            DateTime t1 = DateTime.Now;
            string filePath = "d:\\templog.txt";
            FileInfo fi = new FileInfo(filePath);
            DateTime t2 = fi.LastWriteTime;
            return ExecDateDiff(t2, t1);
        }
        #endregion IISRest


Service代碼如下

public JsonResult IISReset(MachinePack pack)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(pack.Token);
            if (accessToken == null)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "操作用戶無法識別!";
            }
            else if (accessToken.ExpiredTime < DateTime.Now)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "登陸信息過期!";
            }
            else
            {
                try
                {
                     var token = LoginSecurity.DecodeAccessToken(pack.Token);
                     string ip = pack.IPAddress;
                    Logger.Info("IISReset start by " + token.Alias+" on "+ip);
                    IISUtil.IISReset(ip);                    
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.Message;
                    resp.Message += ex.ToString();
                }
            }
            return Json(resp, JsonRequestBehavior.DenyGet);
        }
        public JsonResult CheckIISResetStatus(MachinePack pack)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(pack.Token);
            if (accessToken == null)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "操作用戶無法識別!";
            }
            else if (accessToken.ExpiredTime < DateTime.Now)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "登陸信息過期!";
            }
            else
            {
                try
                {
                    var token = LoginSecurity.DecodeAccessToken(pack.Token);
                    EnvSub envSub = EnvSubBiz.FindByName(pack.DomainName);
                    resp.Message += "EnvSubBiz.FindByName success;";
                    EnvMachine envmachine = EnvMachineBiz.FindByIP(pack.IPAddress);
                    resp.Message += "EnvMachineBiz.FindByIP success;";
                    Logger.Info("IISReset status check by " + token.Alias);
                    string timespan = IISUtil.IISResetTimeSpan();
                    Logger.Info("IISReset status check : timespan" + timespan);
                    if (Double.Parse(timespan) > 40000)
                    {
                        resp.Data = "2";
                        resp.Message = "時間差:" + timespan+";";
                        Logger.Info("IISReset status check : timespan結果 :不是最新的");
                        string str = string.Format("{0} Reset IIS on {1} on {2}", token.Alias, pack.IPAddress)+" : fail";
                        EnvOperationLogBiz.LogOptIISReset(envSub.EnvSubId, token.Alias, str, envmachine.Id);
                    }
                    else
                    {
                        string log = IISUtil.GetIISResetLog();
                        resp.Message = "log:" + log + ";";
                        Logger.Info("IISReset status check : log :"+log);
                        if (log.Equals("正在嘗試停止...\r\r\nInternet 服務已成功停止\r\r\n正在嘗試啓動...\r\r\nInternet 服務已成功啓動"))
                        {
                            resp.Data = "0";
                            string str = string.Format("{0} Reset IIS on {1} on {2}", token.Alias, pack.IPAddress) + " : success";
                            EnvOperationLogBiz.LogOptIISReset(envSub.EnvSubId, token.Alias, str, envmachine.Id);
                            Logger.Info("IISReset status check : result : success");
                        }
                        else
                        {
                            resp.Data = "1";
                            string str = string.Format("{0} Reset IIS on {1} on {2}", token.Alias, pack.IPAddress) + " : fail";
                            EnvOperationLogBiz.LogOptIISReset(envSub.EnvSubId, token.Alias, str, envmachine.Id);
                            Logger.Info("IISReset status check : result : fail");
                        }
                    }
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.Message;
                    resp.Message += ex.ToString();
                }
            }

3. 但是又有個問題,就是IISRESET失敗後,再發檢查結果命令時,由於程序池沒有成功啓動起來,所以返回404,

這時也接受不了IISRESET的請求,後果很嚴重。

所以想到用另一臺機器遠程IISRESET,遠程重啓命令如下:

iisreset \\10.2.8.80 /restart >D:\\tmplog.txt

如果是遠程IISRESET就不需要等40秒,用另一條語句去請求檢查結果


代碼如下:

 

/// <summary>
        /// IISRESRT
        /// </summary>
        public static bool IISReset(string ip)
        {
            Logger.Info("IISReset start");
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            try
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;    //是否使用操作系統shell啓動
                p.StartInfo.RedirectStandardInput = true;//接受來自調用程序的輸入信息
                p.StartInfo.RedirectStandardOutput = true;//由調用程序獲取輸出信息
                p.StartInfo.RedirectStandardError = true;//重定向標準錯誤輸出
                p.StartInfo.CreateNoWindow = false;//不顯示程序窗口
                p.Start();//啓動程序
                //向cmd窗口發送輸入信息
                p.StandardInput.WriteLine("iisreset \\\\" + ip + " /restart");
                Logger.Info("IISReset send command");
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine("exit");
                //向標準輸入寫入要執行的命令。這裏使用&是批處理命令的符號,表示前面一個命令不管是否執行成功都執行後面(exit)命令,如果不執行exit命令,後面調用ReadToEnd()方法會假死
                //同類的符號還有&&和||前者表示必須前一個命令執行成功纔會執行後面的命令,後者表示必須前一個命令執行失敗纔會執行後面的命令
                Logger.Info("IISReset read output");
                //獲取cmd窗口的輸出信息
                string output = p.StandardOutput.ReadToEnd();
                
                p.WaitForExit();//等待程序執行完退出進程
                p.Close();
                Logger.Info("output:" + output);
                if (output.Contains("正在嘗試停止...\r\r\nInternet 服務已成功停止\r\r\n正在嘗試啓動...\r\r\nInternet 服務已成功啓動"))
                {
                    Logger.Info("return true");
                    return true;
                }
                else
                {
                    Logger.Info("return false");
                }
                //StreamReader reader = p.StandardOutput;
                //string line=reader.ReadLine();
                //while (!reader.EndOfStream)
                //{
                //    str += line + "  ";
                //    line = reader.ReadLine();
                //}
            }
            catch (Exception ex)
            {
                Logger.Error("IIS Reset Exception:" + ex.ToString());
            }
            return false;
            //Console.WriteLine(output);   
        }


service代碼

public JsonResult IISReset(MachinePack pack)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(pack.Token);
            if (accessToken == null)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "操作用戶無法識別!";
            }
            else if (accessToken.ExpiredTime < DateTime.Now)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message = "登陸信息過期!";
            }
            else
            {
                try
                {
                    var token = LoginSecurity.DecodeAccessToken(pack.Token);
                    EnvSub envSub = EnvSubBiz.FindByName(pack.DomainName);
                    EnvMachine envmachine = EnvMachineBiz.FindByIP(pack.IPAddress);
                    string ip = pack.IPAddress;
                    Logger.Info("IISReset start by " + token.Alias + " on " + ip);
                    if (IISUtil.IISReset(ip))
                    {
                        resp.Data = "0";
                        string str = string.Format("{0} Reset IIS on {1} on {2}", token.Alias, pack.IPAddress) + " : success";
                        EnvOperationLogBiz.LogOptIISReset(envSub.EnvSubId, token.Alias, str, envmachine.Id);
                        Logger.Info("IISReset status result : success");
                    }
                    else
                    {
                        resp.Data = "1";
                        string str = string.Format("{0} Reset IIS on {1} on {2}", token.Alias, pack.IPAddress) + " : fail";
                        EnvOperationLogBiz.LogOptIISReset(envSub.EnvSubId, token.Alias, str, envmachine.Id);
                        Logger.Info("IISReset status result : fail");
                    }
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.Message;
                    resp.Message += ex.ToString();
                }
             
            }
            return Json(resp, JsonRequestBehavior.DenyGet);
        }

注意:

本機跟部署的服務器的機子向目標服務器方式該命令返回 RPC服務不可用,

網上查到些解決方法,試了後發現都沒用。

原因是由於上海機子的防火牆問題,不能像南通的機子發送遠程IISRSET命令,

所以找了臺南通機子布上EnvAgent


結果運行的時候,報如下錯誤:

c:\windows\system32\inetsrv>iisreset \\10.2.9.80 /restart
訪問被拒絕,必須是該遠程計算機的管理員才能使用此命令。
請將您的用戶名添加到該遠程計算機的管理員本地組或者
域管理員全局組中。

納尼,


領導說是由於域帳號,跟組帳號間帳號不通用,模擬Admin帳號也不頂用,抓狂中。。。


先研究到這邊吧,下週有新成果後再更新

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章