13

我正在尝试从我的网络应用程序以另一个用户身份运行批处理文件。由于某种原因,批处理文件挂起!我可以在任务管理器中看到“cmd.exe”正在运行,但它只是永远坐在那里,无法被杀死,并且批处理文件没有运行。这是我的代码:

SecureString password = new SecureString();
foreach (char c in "mypassword".ToCharArray())
    password.AppendChar(c);

ProcessStartInfo psi = new ProcessStartInfo();
psi.WorkingDirectory = @"c:\build";
psi.FileName = Environment.SystemDirectory + @"\cmd.exe";
psi.Arguments = "/q /c build.cmd";
psi.UseShellExecute = false;
psi.UserName = "builder";
psi.Password = password;
Process.Start(psi);

如果您没有猜到,这个批处理文件会构建我的应用程序(与执行此命令的应用程序不同的应用程序)。

Process.Start(psi); line 应该立即返回,但批处理文件似乎挂起,没有执行。有任何想法吗?

编辑:有关批处理文件的内容,请参阅下面的答案。

  • output.txt 永远不会被创建。

我添加了这些行:

psi.RedirectStandardOutput = true;
Process p = Process.Start(psi);
String outp = p.StandardOutput.ReadLine();

并在调试模式下逐步完成它们。代码挂在ReadLine(). 我难住了!

4

9 回答 9

5

我相信我已经找到了答案。似乎微软以其无限的智慧阻止了批处理文件在 Windows Server 2003 中由 IIS 执行。Brenden Tompkins 在这里有一个解决方法:

http://codebetter.com/blogs/brendan.tompkins/archive/2004/05/13/13484.aspx

这对我不起作用,因为我的批处理文件使用 IF 和 GOTO,但它肯定适用于简单的批处理文件。

于 2008-09-01T19:41:24.163 回答
3

为什么不直接在 C# 中完成所有工作,而不是使用批处理文件?

我很无聊,所以我写得很快,这只是我将如何做的概述,因为我不知道命令行开关的作用或文件路径。

using System;
using System.IO;
using System.Text;
using System.Security;
using System.Diagnostics;

namespace asdf
{
    class StackoverflowQuestion
    {
        private const string MSBUILD = @"path\to\msbuild.exe";
        private const string BMAIL = @"path\to\bmail.exe";
        private const string WORKING_DIR = @"path\to\working_directory";

        private string stdout;
        private Process p;

        public void DoWork()
        {
            // build project
            StartProcess(MSBUILD, "myproject.csproj /t:Build", true);
        }

        public void StartProcess(string file, string args, bool redirectStdout)
        {
            SecureString password = new SecureString();
            foreach (char c in "mypassword".ToCharArray())
                password.AppendChar(c);

            ProcessStartInfo psi = new ProcessStartInfo();
            p = new Process();
            psi.WindowStyle = ProcessWindowStyle.Hidden;
            psi.WorkingDirectory = WORKING_DIR;
            psi.FileName = file;
            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = redirectStdout;
            psi.UserName = "builder";
            psi.Password = password;
            p.StartInfo = psi;
            p.EnableRaisingEvents = true;
            p.Exited += new EventHandler(p_Exited);
            p.Start();

            if (redirectStdout)
            {
                stdout = p.StandardOutput.ReadToEnd();
            }
        }

        void p_Exited(object sender, EventArgs e)
        {
            if (p.ExitCode != 0)
            {
                // failed
                StringBuilder args = new StringBuilder();
                args.Append("-s k2smtpout.secureserver.net ");
                args.Append("-f build@example.com ");
                args.Append("-t josh@example.com ");
                args.Append("-a \"Build failed.\" ");
                args.AppendFormat("-m {0} -h", stdout);

                // send email
                StartProcess(BMAIL, args.ToString(), false);
            }
        }
    }
}
于 2008-09-01T16:49:39.053 回答
2

没有看到 build.cmd 很难知道发生了什么,但是,您应该使用 Path.Combine(arg1, arg2); 构建路径。这是构建路径的正确方法。

Path.Combine( Environment.SystemDirectory, "cmd.exe" );

我现在不记得了,但您不必设置 UseShellExecute = true 吗?

于 2008-08-29T08:42:26.063 回答
1

“调试”它的另一种可能性是使用标准输出,然后从中读取:

psi.RedirectStandardOutput = True;
Process proc = Process.Start(psi);
String whatever = proc.StandardOutput.ReadLine();
于 2008-08-29T08:45:18.037 回答
1

为了“查看”正在发生的事情,我建议您将过程转换为更具交互性的过程(关闭 Echo)并放置一些“打印”以查看是否实际发生了任何事情。运行后 output.txt 文件中有什么内容?

bmail 真的执行了吗?

在之后/之前放置一些打印件,看看发生了什么。

还要在参数中添加“@”,以防万一:

psi.Arguments = @"/q /c build.cmd";

它必须非常简单:)

于 2008-08-29T08:53:58.297 回答
0

我的猜测是 build.cmd 正在等待某种用户交互/回复。如果您在最后使用“ > logfile.txt ”运算符记录命令的输出,它可能会帮助您找到问题。

于 2008-08-29T08:39:23.247 回答
0

这是 build.cmd 的内容:

@echo off
set path=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;%path%

msbuild myproject.csproj /t:Build > output.txt
IF NOT ERRORLEVEL 1 goto :end

:error
bmail -s k2smtpout.secureserver.net -f build@example.com -t josh@example.com -a "Build failed." -m output.txt -h

:end
del output.txt

正如你所看到的,我很小心不要输出任何东西。如果构建碰巧失败,这一切都会通过电子邮件发送给我的文件。实际上,我已经将这个文件作为每晚的计划任务运行了很长一段时间了。我正在尝试构建一个允许我按需运行它的网络应用程序。

感谢大家到目前为止的帮助!Path.Combine 提示特别有用。

于 2008-08-29T08:47:00.997 回答
0

如果参数不正确,我认为 cmd.exe 会挂起。

如果批处理正确执行,那么我会像这样执行它。

ProcessStartInfo psi = new ProcessStartInfo();
Process p = new Process();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = @"c:\build";
psi.FileName = @"C:\build\build.cmd";
psi.UseShellExecute = true;
psi.UserName = "builder";
psi.Password = password;
p.StartInfo = psi;
p.Start();

也可能是 cmd.exe 找不到 build.cmd 那么为什么不给出文件的完整路径呢?

于 2008-08-29T17:22:34.520 回答
0

你们批次的结尾是什么?如果代码在 ReadLine 上挂起,那么问题可能是它无法读取批处理文件...</p>

于 2008-09-01T15:51:17.663 回答