【问题标题】:appcmd.exe and dnscmd.exe behaving different when returning StandardOutputappcmd.exe 和 dnscmd.exe 在返回 StandardOutput 时表现不同
【发布时间】:2013-09-19 06:19:15
【问题描述】:

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

这是我的方法;

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),当我在命令提示符上执行此可执行文件时,我会得到所有输出。但是当涉及到 dnscmd.exe 在 DNS 上创建条目时,我什么也得不到! StandardOutput 只是空的。我使用管理员凭据来执行这些可执行文件。顺便说一句,我在 Windows Server 2012 Standart 上。我还没有在 Server 2008 R2 上测试过这种方法,但我相信结果会是一样的。

看到 appcmd 和 dnscmd 可执行文件在同一个方法上表现不同,这让我有点奇怪。

我在这里缺少什么?

谢谢!

编辑:StandardOutput 和 StandardError 都为 dnscmd.exe 返回错误。

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”在命令提示符上显示 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;
    }
}

【问题讨论】:

  • 也许 dnscmd 只写入 StandardError。调查有一个look a this answer
  • 事实上,我尝试了 StandardError 和 StandardOutput。我真的应该把它写成评论。但是它们都返回空。顺便说一句,感谢您的快速回复:)
  • 如果你尝试在命令提示符dnscmd &gt; output.txt 得到 output.txt 填充?
  • 刚刚检查:taget服务器是否安装了DNS服务?
  • 你只看第一行,dnscmd的第一行可能是空的吗?

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


【解决方案1】:

我没有可以运行 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;

【讨论】:

  • 我感觉好可怕。我玩这个代码太久了,以至于我忘记了我在 main 方法中有一个控制检查:(你的代码和我的代码在删除那个检查后都工作正常。当我尝试你的代码时我意识到我的错误。所以,我'我选择这个作为答案。但我认为,如果您还告诉您的代码和我的代码是做同一件事的不同方式,那应该会更好,除了我的代码给出的是在流程结束时创建的输出,而你的是捕获过程中的所有输出。希望我没有弄错。
  • 那是正确的!我会在我的回答中反映这一点。不要觉得尴尬。有时,很难发现明显的错误,您需要其他人来弄清楚发生了什么。我很高兴它最终对你有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-09
  • 1970-01-01
  • 2022-01-21
相关资源
最近更新 更多