it-swarm.com.de

Batchdatei in C # ausführen

Ich versuche, eine Batchdatei in C # auszuführen, aber ich habe kein Glück dabei.

Ich habe im Internet mehrere Beispiele dafür gefunden, aber es funktioniert nicht für mich.

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process Process;

    ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;

    Process = Process.Start(ProcessInfo);
    Process.WaitForExit();

    ExitCode = Process.ExitCode;
    Process.Close();

    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}

Die Befehlszeichenfolge enthält den Namen der Stapeldatei (in system32 gespeichert) und einige Dateien, die bearbeitet werden sollen. (Beispiel: txtmanipulator file1.txt file2.txt file3.txt). Wenn ich die Batchdatei manuell ausführe, funktioniert sie korrekt.

Bei der Ausführung des Codes erhält ich eine **ExitCode: 1** (Catch all for general errors)

Was mache ich falsch?

118
Wessel T.

Das sollte funktionieren. Sie könnten versuchen, den Inhalt der Ausgabe- und Fehlerströme auszugeben, um herauszufinden, was passiert:

static void ExecuteCommand(string command)
{
    int exitCode;
    ProcessStartInfo processInfo;
    Process process;

    processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    // *** Redirect the output ***
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    process = Process.Start(processInfo);
    process.WaitForExit();

    // *** Read the streams ***
    // Warning: This approach can lead to deadlocks, see Edit #2
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    exitCode = process.ExitCode;

    Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
    process.Close();
}

static void Main()
{
    ExecuteCommand("echo testing");
}   

* EDIT * 

Aufgrund der zusätzlichen Informationen in Ihrem Kommentar konnte ich das Problem erneut erstellen. Es scheint einige Sicherheitseinstellungen zu geben, die zu diesem Verhalten führen (haben dies nicht im Detail untersucht). 

Dieses funktioniert, wenn sich die Batchdatei nicht in C:\Windows\System32 befindet. Verschieben Sie es an einen anderen Ort, z. der Ort Ihrer ausführbaren Datei. Beachten Sie, dass das Speichern von benutzerdefinierten Stapeldateien oder ausführbaren Dateien im Windows-Verzeichnis trotzdem eine schlechte Praxis ist.

* EDIT 2 * Es stellt sich heraus , dass, wenn die Streams synchron gelesen werden, ein Deadlock auftreten kann, entweder durch synchrones Lesen vor WaitForExit oder durch synchrones Lesen von stderr und stdout nach dem andere. 

Dies sollte nicht passieren, wenn stattdessen die asynchronen Lesemethoden verwendet werden, wie im folgenden Beispiel:

static void ExecuteCommand(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    var process = Process.Start(processInfo);

    process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("output>>" + e.Data);
    process.BeginOutputReadLine();

    process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("error>>" + e.Data);
    process.BeginErrorReadLine();

    process.WaitForExit();

    Console.WriteLine("ExitCode: {0}", process.ExitCode);
    process.Close();
}
160
steinar
System.Diagnostics.Process.Start("c:\\batchfilename.bat");

diese einfache Zeile führt die Batchdatei aus.

117
T.S.Sathish

Nach einer großartigen Hilfe von steinar hat dies für mich funktioniert:

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process process;

    ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;
    ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator";
    // *** Redirect the output ***
    ProcessInfo.RedirectStandardError = true;
    ProcessInfo.RedirectStandardOutput = true;

    process = Process.Start(ProcessInfo);
    process.WaitForExit();

    // *** Read the streams ***
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    ExitCode = process.ExitCode;

    MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
    process.Close();
}
15
Wessel T.

Es funktioniert gut. Ich habe es so getestet:

String command = @"C:\Doit.bat";

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;

Ich kommentierte das Fenster aus, damit ich es laufen sehen konnte.

13
Steve Wellens

Der folgende Code hat für mich gut funktioniert

using System.Diagnostics;

public void ExecuteBatFile()
{
    Process proc = null;

    string _batDir = string.Format(@"C:\");
    proc = new Process();
    proc.StartInfo.WorkingDirectory = _batDir;
    proc.StartInfo.FileName = "myfile.bat";
    proc.StartInfo.CreateNoWindow = false;
    proc.Start();
    proc.WaitForExit();
    ExitCode = proc.ExitCode;
    proc.Close();
    MessageBox.Show("Bat file executed...");
}
3
Anjan Kant

Haben Sie versucht, es als Administrator zu starten? Starten Sie Visual Studio als Administrator, wenn Sie es verwenden, da für die Arbeit mit .bat-Dateien diese Berechtigungen erforderlich sind.

1
Kristifor
using System.Diagnostics;

private void ExecuteBatFile()
{
    Process proc = null;
    try
    {
        string targetDir = string.Format(@"D:\mydir");   //this is where mybatch.bat lies
        proc = new Process();
        proc.StartInfo.WorkingDirectory = targetDir;
        proc.StartInfo.FileName = "lorenzo.bat";
        proc.StartInfo.Arguments = string.Format("10");  //this is argument
        proc.StartInfo.CreateNoWindow = false;
        proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;  //this is for hiding the cmd window...so execution will happen in back ground.
        proc.Start();
        proc.WaitForExit();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
    }
}
1
Lijo

System.Diagnostics.Process.Start(BatchFileName, Parameters);

Ich weiß, dass dies für Batchdateien und Parameter funktioniert, aber ich habe keine Ahnung, wie ich die Ergebnisse in C # erhalten kann. Normalerweise werden die Ausgaben in der Batch-Datei definiert.

0
macunix

Ich wollte etwas, das ohne organisationsspezifische, hartcodierte Zeichenfolgenwerte direkt verwendbar ist. Ich biete Folgendes als direkt wiederverwendbaren Code an. Der kleinere Nachteil ist, dass der Arbeitsordner beim Anrufen ermittelt und übergeben werden muss.

public static void ExecuteCommand(string command, string workingFolder)
        {
            int ExitCode;
            ProcessStartInfo ProcessInfo;
            Process process;

            ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
            ProcessInfo.CreateNoWindow = true;
            ProcessInfo.UseShellExecute = false;
            ProcessInfo.WorkingDirectory = workingFolder;
            // *** Redirect the output ***
            ProcessInfo.RedirectStandardError = true;
            ProcessInfo.RedirectStandardOutput = true;

            process = Process.Start(ProcessInfo);
            process.WaitForExit();

            // *** Read the streams ***
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            ExitCode = process.ExitCode;

            MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
            MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
            MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
            process.Close();
        }

So genannt:

    // This will get the current WORKING directory (i.e. \bin\Debug)
    string workingDirectory = Environment.CurrentDirectory;
    // This will get the current PROJECT directory
    string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
    string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat");
    string workingFolder = Path.GetDirectoryName(commandToExecute);
    commandToExecute = QuotesAround(commandToExecute);
    ExecuteCommand(commandToExecute, workingFolder);

In diesem Beispiel möchte ich in Visual Studio 2017 im Rahmen eines Testlaufs eine Batch-Datei für die Umgebungsrücksetzung ausführen, bevor einige Tests ausgeführt werden. (SpecFlow + xUnit). Ich war müde von zusätzlichen Schritten zum manuellen Ausführen der bat-Datei separat und wollte die bat-Datei einfach als Teil des C # -Test-Setup-Codes ausführen. Die Batch-Datei zum Zurücksetzen der Umgebung verschiebt Testfalldateien zurück in den Eingabeordner, bereinigt Ausgabeordner usw., um den Teststatus zum Testen zu erhalten. Die QuotesAround-Methode fügt die Befehlszeile einfach in Anführungszeichen ein, falls in den Ordnernamen Leerzeichen stehen ("Programmdateien", jemand?). Alles, was darin enthalten ist, ist Folgendes: private Zeichenfolge QuotesAround (Zeichenfolgeingabe) {return "\" "+ Eingabe +"\"";}

Ich hoffe, einige finden dies nützlich und sparen ein paar Minuten, wenn Ihr Szenario meinem ähnlich ist.

0
Developer63