How to Start and Fire a Command - c#

It is supposed to be easy, but I can't get it work.
When I run the following command inside cmd, it works perfectly fine. When I run the command inside the c# code, it won't do anything (no exception has been thrown either).
Here is the command I'm using (which works perfectly fine when using directly on cmd.exe):
cd %ProgramFiles%\PostgreSQL\12\bin && SET PGPASSWORD=mypassword&& pg_restore.exe -U username -d dbname C:\file\to\dump\my.dump
Here is what I'm trying to do in c# (not working):
var arg = #"cd %ProgramFiles%\PostgreSQL\12\bin && SET PGPASSWORD=mypassword&& pg_restore.exe -U username -d dbname C:\file\to\dump\my.dump";
Process.Start("cmd.exe", arg);
Am I missing something? I found a lot of posts concerning c# starting a process, but nothing solved my problem. I also tried to start the process with StartInfo and added the Properties like Arguments, FileName, etc., but it did not work either.
Be aware, the question process.start() arguments is not the same - in my case, I neet to set the system variable (SET PGPASSWORD), since pg_restore has no password argument.

cmd is just the console, it isn't needed to start another process.
The application you want to run is pg_restore.exe in the %ProgramFiles%\PostgreSQL\12\bin folder. You can pass environment variables through ProcessStartInfo.EnvironmentVariables dictionary. I'm not sure if the ProcessStartInfo constructor expands environment variables. You can use Environment.ExpandEnvironmentVariables to ensure the path is correct :
var binFolder=#"%ProgramFiles%\PostgreSQL\12\bin\";
var fullPath=Path.Combine(binFolder,"pg_restore.exe");
var arguments=#"-U username -d dbname C:\file\to\dump\my.dump";
var fullPath=Environment.ExpandEnvironmentVariables(pathToRestore);
var startInfo=new ProcessStartInfo(fullPath,arguments) {
UseShellExecute =false,
//Need this to read the output if needed
RedirectStandardOutput = true;
//Set if needed
WorkingDirectory = binFolder
};
startInfo.EnvironmentVariables["PGPASSWORD"]=password;
var process=Process.Start(startInfo);
Console.WriteLine(process.StandardOutput.ReadToEnd());

You need to prefix your argument string with /c so that cmd knows that you're telling it what to do:
var arg = #"/c cd %ProgramFiles%\PostgreSQL\12\bin && SET PGPASSWORD=mypassword&& pg_restore.exe -U username -d dbname C:\file\to\dump\my.dump";
Process.Start("cmd.exe", arg);

Try this:
var command = "SET PGPASSWORD=mypassword && pg_restore.exe";
var param = "-U username -d dbname C:\file\to\dump\my.dump";
var process = new Process();
var processInfo = new ProcessStartInfo(command, param)
{
WorkingDirectory = #"%ProgramFiles%\PostgreSQL\12\bin"
};
process.StartInfo = processInfo;
process.WaitForExit();

Related

How to open and use Git Bash through c# code

I'm trying to include opening Git Bash, pushing and pulling in my c# code. Whilst opening Git Bash with Process.Start() is not the problem, I cannot manage to write commands into Git Bash.
I've tried including commands in ProcessStartInfo.Arguments, as well as redirecting the standard Output. Both has not worked at all. Down below you can see the different code snippets I tried.
private void Output()
{
//Try 1
processStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk";
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Argument = "git add *";
Process p = Process.Start(psi);
string strOutput = p.StandardOutput.ReadToEnd();
Console.WriteLine(strOutput);
//Try 2
ProcessStartInfo psi = new ProcessStartInfo(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk");
Process.Start(psi);
psi.Arguments = "git add *";
Process.Start(psi);
//Try 3
var escapedArgs = cmd.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk",
Arguments = "cd C:\\Users\\strit\\autocommittest2\\autocommittest2\n",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
Git Bash opens but nothing is written in the command line.
I know it is old question, still adding answer as few days ago I was also facing same issue.
I think what you are missing is -c parameter. I used below code and it solved this issue. -c tells git-bash to execute whatever follows, it is similar to -cmd parameter in command line.
In below mentioned function -
fileName = path of git-bash.exe.
command = git command which you want to execute.
workingDir = Local path of git repository.
public static void ExecuteGitBashCommand(string fileName, string command, string workingDir)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(fileName, "-c \" " + command + " \"")
{
WorkingDirectory = workingDir,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var process = Process.Start(processStartInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
var exitCode = process.ExitCode;
process.Close();
}
I hope it solves the issue.
I think you are on the right way. I would try to use the git in the path, but it should be possible to also use the git-bash.exe directly, at my machine it is located here: C:\Program Files\Git\git-bash.exe.
Process gitProcess = new Process();
gitInfo.Arguments = YOUR_GIT_COMMAND; // such as "fetch origin"
gitInfo.WorkingDirectory = YOUR_GIT_REPOSITORY_PATH;
gitInfo.UseShellExecute = false;
gitProcess.StartInfo = gitInfo;
gitProcess.Start();
string stderr_str = gitProcess.StandardError.ReadToEnd(); // pick up STDERR
string stdout_str = gitProcess.StandardOutput.ReadToEnd(); // pick up STDOUT
gitProcess.WaitForExit();
gitProcess.Close();
Like #S.Spieker already told you in it's good answer, no need to use git bash (it makes it harder to achieve and less performant), just call directly the git executable.
You could have a look to the GitExtensions code that is doing that: https://github.com/gitextensions/gitextensions/blob/027eabec3be497f8d780cc68ece268c64a43a7d5/GitExtensionsVSIX/Git/GitCommands.cs#L112
You could also achieve what you want using libgit2sharp (https://github.com/libgit2/libgit2sharp). That could be easier if you want to interpret the results of the command run.

Why is Process.StandardOutput different from the actual output and/or incomplete?

Well, first of all, when executing PsExec commands from C#, part of the output is in the StandardOutput and another part is in the StandardError for some reason, as mentioned in other posts, but that's not big of a deal.
Now, the problem is: Even when combining the two parts together, the "output" isn't exactly the same compared to what gets displayed on the Command Prompt window. Sometimes it's different and sometimes it's incomplete.
Here's my code:
string args = $#"{computerName} -u ""{username}"" -p ""{password}"" {pathOrCommand}";
var pi = new ProcessStartInfo("PsExec.exe", args);
pi.CreateNoWindow = true;
pi.WindowStyle = ProcessWindowStyle.Hidden;
pi.UseShellExecute = false;
pi.RedirectStandardOutput = true;
pi.RedirectStandardError = true;
using (Process p = Process.Start(pi))
{
var resultLines = new List<string>();
var handler = new DataReceivedEventHandler(delegate (object o, DataReceivedEventArgs e)
{
resultLines.Add(e.Data);
});
p.ErrorDataReceived += handler;
p.OutputDataReceived += handler;
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
string result = string.Join("\r\n", resultLines);
}
An example of when it's different:
When passing the wrong username or password, the following message will be displayed on Command Prompt: *
Logon failure: unknown user name or bad password.
..while the output of the above code will be:
The handle is invalid.
An example of when it's incomplete (this is more important):
When executing this command PsExec \\computer -u username -p password query session, the result looks something like this: *
SESSIONNAME USERNAME ID STATE TYPE DEVICE
>services 0 Disc
console someUserName 1 Active
rdp-tcp 65537 Listen
..but the output when executing from C# is only:
SESSIONNAME USERNAME ID STATE TYPE DEVICE
So, my questions are:
Why is Process.StandardOutput / Process.StandardError different from the actual output?
Is there any way around this?
* I'm only presenting the relevant part of the output here.
I still don't understand why the output is different but I managed to create a workaround which I'm going to use unless someone provides a better solution.
I used cmd.exe to redirect the stdout and stderr to a temp file. After the process exits, I read the contents of the file and then delete it:
string tempFile = Path.GetTempFileName();
string args = $#"/c PsExec.exe {computerName} -u ""{username}"" -p ""{password}"" {pathOrCommand}";
var pi = new ProcessStartInfo("cmd.exe", $"{args} 1> {tempFile} 2>&1");
pi.CreateNoWindow = true;
pi.WindowStyle = ProcessWindowStyle.Hidden;
using (Process p = Process.Start(pi))
{
p.WaitForExit();
string result = File.ReadAllText(tempFile);
File.Delete(tempFile);
}
Hope this could help someone else having the same problem.

Unable to run nbtstat using System.Diagnostic.Process

I have a working piece of code which executes commands using System.Diagnostic.Process. However, when I try to run nbtstat using the same code it does not return anything (neither is there an exception). When I run hostname (as an example) it returns the hostname.
string result = "";
//string commandToExec = "hostname";
string commandToExec = "nbtstat -A 10.10.10.5";
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("C:\\Windows\\System32\\cmd.exe", "/c " + commandToExec);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
result = proc.StandardOutput.ReadToEnd();
This command
nbtstat -A 10.10.10.5
works perfectly well from the command prompt. I am not able to understand the problem, neither find resources on the net which could help. If anyone can guide me in the right direction please?
You should call the nbtstat.exe program directly, there is no need to invoke CMD to call it. So use this line instead;
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(#"c:\windows\sysnative\nbtstat.exe", "-A 10.10.10.5");
I also use Sysnative because of Windows64bit redirection. As exaplained in this post

Parameters from bat file to sql script not working

I have a C# application calling a bat file:
new string[] { branchName + ".Order", "Order.bak", "Order"}
var arguments = String.Format("\"{0}\"\"{1}\"\"{2}\"\"{3}\"", stringse[0], stringse[1], stringse[2], sqlPath + "\\");
var psi = new System.Diagnostics.ProcessStartInfo(filename)
{
RedirectStandardOutput = true,
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
UseShellExecute = false,
Arguments = arguments
};
Process createDBs = Process.Start(psi);
System.IO.StreamReader myOutput = createDBs.StandardOutput;
while (!createDBs.HasExited)
{
string output = myOutput.ReadToEnd();
LogStep(output);
}
The bat file looks like this:
#echo off
REM ************************************************
REM * RestoreDB script for use by Development Team *
REM ************************************************
#echo %1 %2 %3 %4
#echo Restore of database started...
SQLCMD -S (local) -d Master -i RestoreDB.sql -v varDatabaseName=%1 varDatabaseBackupFileName= %2 varLogicalName= %3 varSQLDataFolder= %4
#echo Restore of database finished...
pause
The Sql script looks receive these parameters like this:
SET #DatabaseName = N'$(varDatabaseName)'
SET #DatabaseBackupFileName = N'$(varDatabaseBackupFileName)'
SET #LogicalName = N'$(varLogicalName)'
SET #SQLDataFolder = N'$(varSQLDataFolder)'
(Can't paste complete code due to security reasons)
Now my problem is that I don't think I'm passing the variables from bat to sql script correctly.
When calling the bat file out of C# it echo's the values
When calling the sql directly out of command prompt it works correctly, so I know my sql script is working:
SQLCMD -S (local) -d Master -i RestoreDB.sql -v varDatabaseName="Piet.Order.Test" varDatabaseBackupFileName="Order.bak" varLogicalName="Order" varSQLDataFolder="C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\"
I don't get any errors back to my C# application, so when running my application it just runs and calls the bat with parameters, the call from bat to sql seems to go wrong.Is it a format problem with my parameters. I tried single quotes '%1' and tried doubele quotes "%1", nothing seems to work.Can anybody shine some light.Any way maybe how I can retrieve the error that is happening with the call to sql
You need to add a space between arguments
var arguments = String.Format("\"{0}\" \"{1}\" \"{2}\" \"{3}\"",
stringse[0], stringse[1], stringse[2], sqlPath + "\\");
In these scenarios (debugging parameters) could be very useful to start the command processor and leave the console window open after the execution of the program
var arguments = String.Format("/K {4} \"{0}\" \"{1}\" \"{2}\" \"{3}\"",
stringse[0], stringse[1], stringse[2], sqlPath + "\\", filename);
and call the command processor in the ProcessStartInfo
var psi = new System.Diagnostics.ProcessStartInfo("cmd.exe")

Trying to use cmd via c#

I am trying to use a cmd command prompt that works just fine when I use it in a normal cmd window via Windows --> Start --> cmd
My code looks like this
"C:\Program Files\Rapid-I\RapidMiner5\scripts\rapidminer.bat" -f
"C:\Users\user\.RapidMiner5\repositories\Local Repository\test.rmp"
That works just fine.
The problem is when I am trying to write this code in C# by opening a cmd window via C#
This is the c# code
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c \"C:\\Program Files\\Rapid-I\\RapidMiner5\\scripts\\rapidminer.bat\" -f \"C:\\Users\\user\\.RapidMiner5\\repositories\\Local Repository\\test.rmp\"");
You can see I quoted the same way like the code that work in the regular cmd
But I am getting a can't recognize program files.
Try this:
string fullPath = #"C:\Program Files\Rapid-I\RapidMiner5\scripts\rapidminer.bat";
ProcessStartInfo p = new ProcessStartInfo();
p.FileName = Path.GetFileName(fullPath);
p.WorkingDirectory = Path.GetDirectoryName(fullPath);
p.Arguments = #"/c -f ""C:\Users\user\.RapidMiner5\repositories\Local Repository\test.rmp""";
Process.Start(p);
I modified my original code to add arguments to your process.
One last thing you could try is putting your original command into a batch file and calling the batch file from your ProcessStartInfo object like so:
C#:
string fullPath = #"C:\Program Files\Rapid-I\RapidMiner5\scripts\run.bat";
ProcessStartInfo p = new ProcessStartInfo();
p.FileName = Path.GetFileName(fullPath);
p.WorkingDirectory = Path.GetDirectoryName(fullPath);
Process.Start(p);

Categories

Resources