I use System.Diagnostics.Process in C# to call the PostgreSQL backup database component pg_dump.exe. Here is my code:
string argbackup = #"--host localhost --port 5432 --username ""postgres"" --no-password --format custom --blobs --verbose --file dtname dtname";
Process backupProcess = new Process();
backupProcess.StartInfo.FileName = #"C:/Program Files/PostgreSQL/9.5/bin/pg_dump.exe";
backupProcess.StartInfo.Arguments = argbackup;
backupProcess.EnableRaisingEvents = true;
backupProcess.Exited += (object sender, EventArgs args) =>
{
//Execution after the process ends.
};
backupProcess.Start();
The code can run successfully in C#. But pg_dum.exe cannot be called when I publish the project in Visual Studio and deploy it on IIS. And the code that was run after the process ended successfully ran.
I modified the above code:
var pinfo = new ProcessStartInfo();
pinfo.Arguments = #"--host localhost --port 5432 --username ""postgres"" --no-password --format custom --blobs --verbose --file dtname dtname";
info.FileName = #"C:/Program Files/PostgreSQL/9.5/bin/pg_dump.exe";
pinfo.UseShellExecute = false;
using (var process = new Process())
{
process.EnableRaisingEvents = true;
process.StartInfo = pinfo;
process.Start();
while (!process.HasExited)
Thread.Sleep(10000);
process.WaitForExit();
if (process.ExitCode != 0)
throw new Exception("error");
process.Close();
}
It can also be used in C#, but it still won't work in IIS.
I modified the code again:
string argpostgre = #"c: && cd C:/Program Files/PostgreSQL/9.5/bin";
string argbackup = #"pg_dump.exe --host localhost --port 5432 --username ""postgres"" --no-password --format custom --blobs --verbose --file dtname dtname";
Process theProcess = new Process();
theProcess.StartInfo.FileName = #"cmd.exe";
theProcess.StartInfo.UseShellExecute = false;
theProcess.StartInfo.RedirectStandardInput = true;
theProcess.StartInfo.RedirectStandardOutput = true;
theProcess.StartInfo.RedirectStandardError = true;
theProcess.StartInfo.CreateNoWindow = false;
theProcess.EnableRaisingEvents = true;
theProcess.Exited += (object sender, EventArgs args) =>
{
//Execution after the process ends.
};
string strOutput = null;
try
{
theProcess.Start();
theProcess.StandardInput.WriteLine(argpostgre + " && " + argbackup + " & exit");
theProcess.WaitForExit();
}
catch (Exception ex)
{
strOutput = ex.Message;
}
It has been runnning in C# and will not exit. But the database can be backed up successfully after I forcefully close the C# program. And it will automatically stop process but the situation is the same as above when I deploy to IIS.
I am sure it is not the setup issue in IIS, because I have also used the Process component to access the WinRAR.exe (C:\Program Files\WinRAR\WinRAR.exe) compression program, which can run successfully.
I wonder if PostgreSQL has permissions so I can not access pg_dump.exe and other components such as pg_restore.exe.
Related
I've got a WPF application that whilst processing a file needs to use a docker process. The docker container is built on the box, currently after processing a file with the WPF application the user has to start a command prompt and type in
docker run --it --rm -v folderdedirect process parameters_including_filePath
to do further processing.
I want to include that in the WPF application. I could presumably use system.diagnostics.process with cmd.exe? I looked at the Docker.dotnet but couldn't for the life of me work out how it's supposed to just run a local container.
Here's how I did it in the end but there may be a better way.
var processInfo = new ProcessStartInfo("docker", $"run -it --rm blahblahblah");
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
int exitCode;
using (var process = new Process())
{
process.StartInfo = processInfo;
process.OutputDataReceived += new DataReceivedEventHandler(logOrWhatever());
process.ErrorDataReceived += new DataReceivedEventHandler(logOrWhatever());
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit(1200000);
if (!process.HasExited)
{
process.Kill();
}
exitCode = process.ExitCode;
process.Close();
}
Adapted the code above for my context. The hardest part is determining how you want to monitor if your process finished. You can try setting up event listeners as shown here. Having other conditions to verify (if client sends a kill signal), I decided to just continually monitor process.HasExited value.
private static void RunDockerImage(ContainerData containerData)
{
var processInfo = new ProcessStartInfo("docker", $"run "+containerData.ImageName);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
int exitCode;
using (var process = new Process())
{
process.StartInfo = processInfo;
// indicate process is started
StartUpdateOrch(containerData);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
while(!process.HasExited)
{
// continually check if kill signal is set
if (getKillSignal())
{
process.Kill();
}
Thread.Sleep(2000);
}
exitCode = process.ExitCode;
containerData.exitCode = exitCode;
// indicate process is done
FinishUpdateOrch(containerData);
process.Close();
}
}
This is the program I wrote to open cmd, run IPERF as a client.
After connecting with the server, it is supposed to show the bandwidth of the network.
But the command prompt closes and the information I require is only available at the server side.
How do I get the information and display it in a MessageBox ?
Any form of assistance is most appreciated.
string output;
ProcessStartInfo start = new ProcessStartInfo(#"C:\Windows\System32\cmd.exe");
start.UseShellExecute = false;
start.ErrorDialog = false;
start.WindowStyle = ProcessWindowStyle.Normal;
start.RedirectStandardError = true;
start.RedirectStandardInput = true;
start.RedirectStandardOutput = true;
Process cmd = new Process();
cmd.StartInfo = start;
cmd.Start();
try
{
Process.Start("cmd", "/C iperf -c " + IP_Address);
}
catch
{
}
Thread.Sleep(1000);
StreamReader outputReader = cmd.StandardOutput;
StreamReader errorReader = cmd.StandardError;
output = outputReader.ReadToEnd();
MessageBox.Show( output );
try
{
Process.Start("cmd", "/C iperf -c " + IP_Address);
}
Have you tried "cmd /k"? It should prevent the terminal from closing after completion of your argument.
try
{
Process.Start("cmd /k", "/C iperf -c " + IP_Address);
}
I have to start an executable (installPrint.exe) within my C# code. For this purposes I used the System.Diagnostics.Process class. The exe file installs a printer driver and copy several files into different directories. I can execute the exe from command line and everything work fine. But if i execute the file with the Process class from my C# application, the printer driver will not be installed.
I start my C# application as a admin user on a Windows XP SP2 x86 machine. Why do my executable dont work in the context of my C# application? What possibilities do i have to get it work?
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = "-i \"My Printer\" -dir . -port myPort -spooler";
startInfo.CreateNoWindow = true;
startInfo.FileName = #"C:\Printer\install.exe";
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
//startInfo.Verb = "runas";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.WorkingDirectory = #"C:\Printer\";
session.Log("Working Directory: " + startInfo.WorkingDirectory);
session.Log("Executing " + startInfo.FileName);
try
{
Process process = new Process();
//process.EnableRaisingEvents = false;
process.StartInfo = startInfo;
process.Start();
session.Log("installer.exe started");
StreamReader outReader = process.StandardOutput;
StreamReader errReader = process.StandardError;
process.WaitForExit();
//session.Log(outReader.ReadToEnd());
//session.Log(errReader.ReadToEnd());
session.Log("RETURN CODE: " + process.ExitCode);
}
catch (Exception ex)
{
session.Log("An error occurred during printer installation.");
session.Log(ex.ToString());
}
I take it, you are running your program on Windows Vista or 7. Then, you have to request elevation for your newly created process to run with full access rights. Look at those questions for details:
Request Windows Vista UAC elevation if path is protected?
Windows 7 and Vista UAC - Programmatically requesting elevation in C#
Ok, I see now, that you're using Win XP. Then it may be because of some settings of Process when you start it. Try to start you process as ShellExecute, this way it will be most close to normal starting by the user.
Here's a sample:
var p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo { FileName = "yourfile.exe", UseShellExecute = true };
p.Start();
I use this class in many parts of my projects:
public class ExecutableLauncher
{
private string _pathExe;
public ExecutableLauncher(string pathExe)
{
_pathExe = pathExe;
}
public bool StartProcessAndWaitEnd(string argoment, bool useShellExecute)
{
try
{
Process currentProcess = new Process();
currentProcess.EnableRaisingEvents = false;
currentProcess.StartInfo.UseShellExecute = useShellExecute;
currentProcess.StartInfo.FileName = _pathExe;
// Es.: currentProcess.StartInfo.Arguments="http://www.microsoft.com";
currentProcess.StartInfo.Arguments = argoment;
currentProcess.Start();
currentProcess.WaitForExit();
currentProcess.Close();
return true;
}
catch (Exception currentException)
{
throw currentException;
}
}
}
I hope to have answered at your question.
M.
I am having trouble with permissions on Windows 2008 server. i have a command line utility that I need to run to convert some standard files to CSV files. That are in turn used to import data to my SQL database. I am able to get the done to work fine on my 2003 server but my windows 2008 server is not allowing the code to run. Below is a watered down version of the code. Basically in this example I am just trying to run a simple command. But I keep getting the output access denied. How do I correct this?
public partial class _Bank : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btn_Click(object sender, EventArgs e)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
Process process = Process.Start(processStartInfo);
if (process != null)
{
process.StandardInput.WriteLine("dir");
process.StandardInput.Close();
string outputString = process.StandardOutput.ReadToEnd();
Response.Write(outputString);
string error = process.StandardError.ReadToEnd();
Response.Write(error);
}
}
private string ProcessRunner()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
if (process != null)
{
//process.StandardInput.WriteLine("This is a test line");
process.StandardInput.WriteLine("c:\\");
process.StandardInput.WriteLine("This is a test line");
process.StandardInput.Close(); // line added to stop process from hanging on ReadToEnd()
string outputString = process.StandardOutput.ReadToEnd();
Response.Write(outputString);
return outputString;
}
return string.Empty;
}
public static int ExecuteCommand(string Command, int Timeout)
{
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(Timeout);
ExitCode = Process.ExitCode;
Process.Close();
return ExitCode;
}
}
This is running within an asp.net application with an App-Pool. The App-Pool has an identity (LocalSystem, Network Service etc) this process is executed.
Make sure that this user does have the necessary privileges on the folders you are planning to access.
IMHO: for security reasons starting another process within a web application is not best practice and should never be done on internet web applications.
EDIT:
Usualy the user is named ASPNET or IWAM_[Servername] (IWAM_... Built-in account for Internet Information Services to start out of process applications). Just give access to the folder to that user.
I am writing a InstallerClass using C# as a custom action for my installer, and I can successfully run an external exe (installation) using the InstallerClass, but when I try to use /quiet in the InstallerClass, it does not install the exe. But I can successfully install this in silent mode using /quiet in the command prompt.
Is there any reason for this or otherwise how to install in silent mode using C#?
Following is the code I use within the Commit method (overriden):
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = pathExternalInstaller;
p.StartInfo.Arguments = "/quiet";
p.Start();
Here is what I use to do a quiet Install and Uninstall:
public static bool RunInstallMSI(string sMSIPath)
{
try
{
Console.WriteLine("Starting to install application");
Process process = new Process();
process.StartInfo.FileName = "msiexec.exe";
process.StartInfo.Arguments = string.Format(" /qb /i \"{0}\" ALLUSERS=1", sMSIPath);
process.Start();
process.WaitForExit();
Console.WriteLine("Application installed successfully!");
return true; //Return True if process ended successfully
}
catch
{
Console.WriteLine("There was a problem installing the application!");
return false; //Return False if process ended unsuccessfully
}
}
public static bool RunUninstallMSI(string guid)
{
try
{
Console.WriteLine("Starting to uninstall application");
ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe", string.Format("/c start /MIN /wait msiexec.exe /x {0} /quiet", guid));
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process process = Process.Start(startInfo);
process.WaitForExit();
Console.WriteLine("Application uninstalled successfully!");
return true; //Return True if process ended successfully
}
catch
{
Console.WriteLine("There was a problem uninstalling the application!");
return false; //Return False if process ended unsuccessfully
}
}
This works for me.
Process process = new Process();
process.StartInfo.FileName = # "C:\PATH\Setup.exe";
process.StartInfo.Arguments = "/quiet";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
process.WaitForExit();
Have you tried using the /Q or /QB parameter that is listed in the Installation parameters? It might look something like this:
p.StartInfo.Arguments = "/Q";
I got that out of this document: http://msdn.microsoft.com/en-us/library/ms144259(v=sql.100).aspx
Here is my logic to silent install an app for all users:
public void Install(string filePath)
{
try
{
Process process = new Process();
{
process.StartInfo.FileName = filePath;
process.StartInfo.Arguments = " /qb ALLUSERS=1";
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
process.Start();
process.WaitForExit();
}
}
catch (InvalidOperationException iex)
{
Interaction.MsgBox(iex.Message, MsgBoxStyle.OkOnly, MethodBase.GetCurrentMethod().Name);
}
catch (Exception ex)
{
Interaction.MsgBox(ex.Message, MsgBoxStyle.OkOnly, MethodBase.GetCurrentMethod().Name);
}
}
private void process_Exited(object sender, EventArgs e)
{
var myProcess = (Process)sender;
if (myProcess.ExitCode == 0)
// do yours here...
}
string filePath = #"C:\Temp\Something.msi";
Process.Start(filePath, #"/quiet").WaitForExit();
It worked for me.