返回StandardOutput时,appcmd.exe和dnscmd.exe的行为不同

时间:2013-09-14 18:58:06

标签: c# asp.net iis dns windows-server-2012

我正在开发一些应该像自助部署应用程序的托管面板一样工作的东西。我创建了一个方法,它将文件名和参数作为参数,并在执行时在面板网页上给出输出。

这是我的方法;

private string ExecuteCmd(string sysUser, SecureString secureString, string argument, string fileName)
{
    using (Process p = new Process())
    {
        p.StartInfo.FileName = fileName;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardOutput = true;

        p.StartInfo.UserName = sysUser;
        p.StartInfo.Password = secureString;

        p.StartInfo.Arguments = argument;
        p.Start();
        p.WaitForExit();

        StreamReader sr = p.StandardOutput;

        p.Close();

        string message = sr.ReadToEnd();

        return message;
    }
}

当我使用此方法在IIS上创建网站(使用appcmd.exe)时,我在命令promt上执行此可执行文件时获得所有输出。但是当谈到dnscmd.exe在DNS上创建条目时,我什么都没得到! StandardOutput刚刚出来。我使用管理员凭据来执行这些可执行文件。顺便说一下,我在Windows Server 2012 Standart上。我还没有在Server 2008 R2上测试这种方法,但我相信无论如何结果都是一样的。

对于我来说,看到appcmd和dnscmd可执行文件在同一方法上的行为方式有点奇怪。

我在这里缺少什么?

谢谢!

编辑:对于dnscmd.exe,StandardOutput和StandardError都返回错误。

Edit2:我将ReadLine()更改为ReadToEnd()。这是我在玩游戏时尝试改变的事情。原始代码具有ReadToEnd()。

Edit3:包含文件路径和参数的完整方法。 这适用于IIS,它显示输出没有问题;

private string ExecuteAppCmd(string sysUser, SecureString secureString)
{
    using (Process p = new Process())
    {
        p.StartInfo.FileName = @"C:\Windows\System32\inetsrv\APPCMD.EXE";
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

        p.StartInfo.UserName = sysUser;
        p.StartInfo.Password = secureString;

        p.StartInfo.Arguments = " list site domain.com";
        p.Start();
        p.WaitForExit();

        StreamReader sr = p.StandardOutput;

        p.Close();

        string message = sr.ReadToEnd().Replace("\n", "<br />");

        return message;
    }
}

“appcmd list site domain.com”在命令promt上显示domain.com的iis站点配置。如果domain.com不在iis中,则显示错误。无论哪种方式,都有一个输出,它可以正常使用此代码。

这是针对dnscmd的。这个在asp.net页面上完成工作,但没有用StandardOutput显示它的输出。但是,输出显示在命令提示符下。

private string ExecuteDnsCmd(string sysUser, SecureString secureString)
{
    using (Process p = new Process())
    {
        p.StartInfo.FileName = @"C:\Windows\System32\DNSCMD.EXE";
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

        p.StartInfo.UserName = sysUser;
        p.StartInfo.Password = secureString;

        p.StartInfo.Arguments = " /zoneadd domain.com /primary";
        p.Start();
        p.WaitForExit();

        StreamReader sr = p.StandardError;

        p.Close();

        string message = sr.ReadToEnd().Replace("\n", "<br />");

        return message;
    }
}

1 个答案:

答案 0 :(得分:0)

我没有可以运行dnscmd.exe的盒子,但因为你声称其他一切正常,我只能想象错误和输出流的处理会以某种方式纠缠在一起。如果您尝试使用此代码,唯一的区别是此代码在不同的线程上处理错误和输出流,并在运行期间收集它们的输出。如果这样可行,您的代码也应该没问题。

        // as there will not be an input stream so don't Redirect 
        p.StartInfo.RedirectStandardInput = false;

        // use a stringbuilder to capture everything
        var sb = new StringBuilder();
        // raise events on stdout and stderr and handle them
        p.EnableRaisingEvents = true;
        p.OutputDataReceived += (sender, args) => sb.AppendFormat("Out: {0}<br />",args.Data);
        p.ErrorDataReceived  += (sender, args) => sb.AppendFormat("Err: {0}<br />",args.Data);

        p.Start();

        // start consuming
        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        // wait for process to exit
        p.WaitForExit();

        p.Close();

        // obtain out stringbuilder value
        string message = sb.ToString();

        return message;