最近要写个从页面上点击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        ///         /// IISRESRT        ///         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);           }        ///         /// IISRESRT        ///         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);           }        ///         /// 判断IISReset是否成功 (已在IISControl中实现,这边代码不完全)        ///         /// 由于IISReset后会失去返回,所以需要重新发送请求来获取IISReset的结果        /// 这里采用很短时间段里面检查IISREST时记录在d:\\templog.txt中的日记来判断        ///         /// 需要判断文件的时间某段时间内,并且内容是重启正确        ///         ///         /// 
        public static bool IsResetSuccess()        {            string filePath = "d:\\templog.txt";            return File.ReadAllText(filePath).Trim().Equals("正在尝试停止...\r\r\nInternet 服务已成功停止\r\r\n正在尝试启动...\r\r\nInternet 服务已成功启动");        }        ///         /// 获取 IISRESET 日记内容        ///         /// 
        public static string GetIISResetLog()        {            string filePath = "d:\\templog.txt";            return File.ReadAllText(filePath, Encoding.Default).Trim();        }        ///         /// 获取 IISREST 日记文件的时间差,来判断是否是最近这次的日记        ///         /// 
        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
()            {                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
()            {                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秒,用另一条语句去请求检查结果

代码如下:

 

///         /// IISRESRT        ///         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
()            {                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帐号也不顶用,抓狂中。。。

先研究到这边吧,下周有新成果后再更新