I´m trying to run an old .NET application from an ASP.NET website. After reading the web and Stackoverflow (for similar problem) I come to the following code.
The Problem is that I get always an error code (I am using administrator account
just to testing purposes). If I run the exe manually it works ok.
private void Execute(string sPath)
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.UserName = "administrador";
string pass = ".............";
System.Security.SecureString secret = new System.Security.SecureString();
foreach (char c in pass) secret.AppendChar(c);
proc.StartInfo.Password = secret;
proc.StartInfo.WorkingDirectory = ConfigurationManager.AppSettings["WORKINGDIRECTORY"].ToString();
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName = sPath;
proc.Start();
proc.WaitForExit();
string result = proc.StandardOutput.ReadToEnd();
Response.Write(result + " - " + proc.ExitCode);
proc.Close();
}
}
The exitcode I get is: -1066598274
Result variable is empty.
No exception is thrown
I am using Windows 2008 with IIS 7.0
Thanks in advance,
Ezequiel
Don't do this. This is just plain dirty and should not be done from ASP.NET
Write a windows service
Store the request in a queue
The service should poll the queue and process. If needed run the exe. It is suggested that the service stays in a different server.
Don't do this. This is very bad and not scalable and bad for the web server
Don't
Don't
Don't
protected void btnSubmit_Click(object sender, System.EventArgs e)
{
if (Page.IsValid)
{
litMessage.Visible = true;
System.Diagnostics.Process oProcess = null;
try
{
string strRootRelativePathName = "~/Application.exe";
string strPathName =
Server.MapPath(strRootRelativePathName);
if (System.IO.File.Exists(strPathName) == false)
{
litMessage.Text = "Error: File Not Found!";
}
else
{
oProcess =
new System.Diagnostics.Process();
oProcess.StartInfo.Arguments = "args";
oProcess.StartInfo.FileName = strPathName;
oProcess.Start();
oProcess.WaitForExit();
System.Threading.Thread.Sleep(20000);
litMessage.Text = "Application Executed Successfully...";
}
}
catch (System.Exception ex)
{
litMessage.Text =
string.Format("Error: {0}", ex.Message);
}
finally
{
if (oProcess != null)
{
oProcess.Close();
oProcess.Dispose();
oProcess = null;
}
}
}
}
If you use
proc.StartInfo.RedirectStandardOutput = true;
then you have to read the stream as the process executes, instead of before the call to
proc.WaitForExit();
Same goes for the standard error stream. See the MSDN docs for more detail.
You need to reorder the output reading at the end.
It expects you to read before the waitforexit() call, so you should have:
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
Response.Write(result + " - " + proc.ExitCode);
proc.WaitForExit();
proc.Close();
If the application you're trying to run is really a .NET application as you say, you may not need to run it in a separate process at all. Instead, you can take advantage of the fact that .NET executables are also assemblies. I don't think Visual Studio will let you reference assemblies that end in .exe, but the command-line compiler will.
I would try using the command-line compiler to create a wrapper assembly that simply references the executable assembly, and directly calls its Main() method, passing in a string array of any command-line parameters you would normally specify. The exit code, if any, will be an integer return value from the Main method. Then you can simply call your wrapper assembly from your ASP.NET app.
Depending on what the executable does, and how much it interacts with the console, this approach may not work at all. But if it does work for your case, it should perform much better than spinning up a separate process.
What i do is to have the executable called by a ms sql job.
The executable would be run as SQL server agent service account.
Create a new sql server job
Give it a name in the job property's general page
In the steps page, create a new step of type Operating system (CmdExec)
Speeify the command and click ok to save the job parameters
The new job can be called using EXEC msdb.dbo.sp_start_job #jobname, where #jobname is
the variable carrying the name of the job you want to start.
Note that when this job starts, the UI of the exe will be hidden and will not be displayed; but you can find it in your task manager.
I have employed this method in several applications especially time consuming operations that cannot be done on the web page.
You may need to set the proc.StartInfo.LoadUserProfile property to true so the administrator's user profile stuff is loaded into the registry (AFAIK this does not happen by default).
Also, it might be educational to run a 'hello world' program to see if the problem is with actaully creating the process or if the process itself is having problems running in the context it's given.
Finally, as a step in trying to narrow down where the problem might be, you might want to run the ASP.NET process itself with admin or system credentials to see if something in the permissions of the account the ASP.NET instance is running under is part of the problem (but please do this only for troubleshooting).
Use below code:
ProcessStartInfo info = new ProcessStartInfo("D:\\My\\notepad.exe");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
//info.UserName = dialog.User;
info.UserName = "xyz";
string pass = "xyz";
System.Security.SecureString secret = new System.Security.SecureString();
foreach (char c in pass)
secret.AppendChar(c);
info.Password = secret;
using (Process install = Process.Start(info))
{
string output = install.StandardOutput.ReadToEnd();
install.WaitForExit();
// Do something with you output data
Console.WriteLine(output);
}
Related
I need to implement the application that retrieve the list of commits from SVN repository and displays them on web page.
How can I do it ?
I'm not understand very good what should I use. It seems it can be done using some SVN api or library...
(The application in .NET)
Here's a nifty function that I use to execute SVN commands from a .NET environment:
// execute a SVN command and fetch the output as a string
private string ExecuteSVNCommandWithOutput(string SVNCommand)
{
string output = "";
try
{
using (Process p = new Process())
{
p.StartInfo.FileName = "cmd";
p.StartInfo.Arguments = "/c " + SVNCommand;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
}
// unexpected error
catch (Exception ex)
{
output = ex.ToString();
}
return output;
}
For your purposes, I would do the following to run an svn log:
ExecuteSVNCommandWithOutput(#"svn log C:\Repositories\YourRepositoryName");
You could then parse the string output into an Array or a List of some sort. Hope this helps!
You can call svn log (http://svnbook.red-bean.com/en/1.7/svn.ref.svn.c.log.html) from the command line (or using the Process class), redirect the output to a file and then open and parse the file.
Parsing the default text output is not hard, but with the --xml option, the file can be parsed more easily with any XML library.
On the server, I'm attempting to open the command prompt and call an executable which converts a file to PDF. For this I am using the PDFCreator open source program.
In C# I am calling with this code:
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
process.StandardInput.WriteLine(#"cd c:\program files (x86)\pdfcreator");
process.StandardInput.WriteLine(#"PDFCreator.exe /PF""c:\dwf\dwf.dwf""");
It runs with no error, yet yields no result. What this PDFCreator.exe does is call another program, Autodesk Design Review which opens, uses the PDF driver to print to PDF, and saves the file. The command you see works fine being running standalone by me.
From scouring other threads it seems security could be my issue. So I have gone to the PDFCreator and Design Review folders/executables and granted full access to NETWORK, NETWORK SERVICE, IIS_WPG, IIS_IUSRS, and ASP.NET Machine account (realize this is probably a security thread but will disable once i figure out source of the issue). This has not helped.
It should be noted than i can change directory using the first command above, and then create a "test123" folder in both PDFCreator and Design Review folders. Seems I am getting close here, any ideas?
SteveCalPoly and Val Akkapeddi comments are very interesting.
Anyway, I use the following methods to run executable with command prompt
/// <summary>
/// Executes a shell command synchronously.
/// </summary>
/// <param name="command">string command</param>
/// <returns>string, as output of the command.</returns>
public void ExecuteCommandSync(object command)
{
try
{
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows,
// and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
}
}
/// <summary>
/// Execute the command Asynchronously.
/// </summary>
/// <param name="command">string command.</param>
public void ExecuteCommandAsync(string command)
{
try
{
//Asynchronously start the Thread to process the Execute command request.
Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
//Make the thread as background thread.
objThread.IsBackground = true;
//Set the Priority of the thread.
objThread.Priority = ThreadPriority.AboveNormal;
//Start the thread.
objThread.Start(command);
}
catch (ThreadStartException objException)
{
// Log the exception
}
catch (ThreadAbortException objException)
{
// Log the exception
}
catch (Exception objException)
{
// Log the exception
}
}
The System.Diagnostics.Process class has a method called WaitForExit() which will wait for its launched process to exit before continuing and then will return its return code.
Try creating a batch file with your commands and then running the batch file via the Process class. What happens if you use Process.WaitForExit(); after you call Process.Start(processInfo); ? Is there a return code from process.WaitForExit() at all?
Perhaps the errors are going to the StandardError stream and so you never see them?
Also, why not call PDFCreator.exe directly instead of via cmd.exe?
Try something like this
ProcessStartInfo processStartInfo = new ProcessStartInfo(#"c:\program files (x86)\pdfcreator");
processStartInfo.Arguments = #"/PF""c:\dwf\dwf.dwf"""
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
string errors = p.StandardError.ReadToEnd();
Found out the issue over at serverfault. The app I was calling needs to open another app on the desktop and then print to PDF. IIS cannot open programs on the desktop unless set in the services --> service name --> log on tab.
Unfortunately, the app I am calling isn't in the services panel so I'm currently stuck again, but at least I know it's not a C# problem.
I'm trying to create a small program to run on a centralized device. This program will run
"psexec \server(s) netstat -na | findstr "LISTENING""
to collect netstat data from remote nodes (should redirect output to string), then parse the data and compare against a known list. I can run the psexec cmd above without any issues from the cmd line, but when I try to run the same command as a process within my C# program, no data is returned to be parsed. I can see that the netstat is being run (cmd window flashes with netstat results), but the process.standardoutput is not catching the stream. If I use ping or pretty much anything other than psexec as an argument, the stream is caught and the results are shown in my text box. I've also tried setting the filename to psexec.exe and specifying the arguments but I get the same results. Last but not least, if I run psexec without any arguments, I get the help kickback info returned in my textbox. This is true if I'm running psexec.exe as the filename OR if I run cmd.exe as filename with "/c psexec" specified as args.
I'm just trying to get psexec output to be caught when executing locally at this point. I'll worry about psexec to remote machines later. Any help would be MUCH appreciated.
Here's the code:
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.FileName = "cmd.exe";
pProcess.StartInfo.Arguments = "/c psexec netstat";
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.Start();
string strOutput = pProcess.StandardOutput.ReadToEnd();
pProcess.WaitForExit();
if (pProcess.HasExited)
{
textBox1.Text = strOutput;
}
else
{
textBox1.Text = "TIMEOUT FAIL";
}
I would recommend also capturing the standard error output in case anything is being reported there.
Also, you may have a disconnect between "bitness" of psexec and your application if you are running on a 64-bit OS. If this is the case, change the platform for the project to match that of psexec rather than building as Any CPU.
Came across a few things to be changed but your recommendation of capturing standard error output was dead on and a good start. Turns out some info was being sent to the error output (even though really wasn't error, just run status 0 from psexec) so I knew at that point psexec wasn't just eating ALL the output. Once I started trying to pass remote hosts as args, I started getting user/pass error data back. Also needed to catch standard input if I wanted to supply credentials for proc run. Threw in some str literals and credentials for the remote exec, works perfectly. Thanks for the help. Here is the updated code--
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.Domain = "domain";
pProcess.StartInfo.UserName = "user with priv";
pProcess.StartInfo.Password = new System.Security.SecureString();
char [] pass = textBox3.Text.ToArray();
for (int x = 0; x < pass.Length; ++x)
{
pProcess.StartInfo.Password.AppendChar(pass[x]);
}
pProcess.StartInfo.FileName = #"psexec.exe";
pProcess.StartInfo.Arguments = #"\\remoteHost netstat -ano";
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardInput = true;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.Start();
pProcess.WaitForExit(30000);
if (!pProcess.HasExited)
{
pProcess.Kill();
}
string strOutput = pProcess.StandardOutput.ReadToEnd();
string errOutput = pProcess.StandardError.ReadToEnd();
textBox1.Text = strOutput;
textBox2.Text = errOutput;
I have been trying to start an application from a C# application but it fails to start properly. From the cmd the application plus the arguments launch a small window showing the output then the application in minimized to the system tray.
Launching the application from the C# application using the code below results in the process appearing in the task manager but nothing else, no output window, no system tray icon. What could be the issue?
myProcess.StartInfo.FileName = ...;
myProcess.StartInfo.Arguments = ...;
myProcess.Start();
also tried passing the following
myProcess.StartInfo.RedirectStandardOutput = true; //tried both
myProcess.StartInfo.UseShellExecute = false; //tried both
myProcess.StartInfo.CreateNoWindow = false;
using
Process.Start(Filename, args)
also did not work. Would really appreciate any help on how to tackle this.
UPDATE:
I think the issue maybe the multiple arguments that are to be passed to the process
RunMode=Server;CompanyDataBase=dbname;UserName=user;PassWord=passwd;DbUserName=dbu;Server=localhost;LanguageCode=9
regards
I don't see any mistake in your code. I have written a little program that prints out its args to the console
static void Main (string[] args)
{
foreach (string s in args)
Console.WriteLine(s);
Console.Read(); // Just to see the output
}
and then I have put it in C:, being the name of the app "PrintingArgs.exe", so I have written another one that executes the first:
Process p = new Process();
p.StartInfo.FileName = "C:\\PrintingArgs.exe";
p.StartInfo.Arguments = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18";
p.Start();
this gives me the desired output of the list of numbers. The app that calls PrintingArgs exits as it reachs p.Start(), this could be avoided by using p.WaitForExit(); or just Console.Read();.
Also I have used both p.UseShellExecute and p.CreateNoWindow. Only in the case that
p.UseShellExecute = false;
p.CreateNoWindow = true;
makes the PrintingArgs app not to show a window (even if I put only p.CreateNoWindow = true it shows a window).
Now it comes to my mind that maybe your are passing the args in a wrong way and makes the other program to fail and close inmediately, or maybe you are not pointing to the right file. Check paths and names, in order to find any mistake you could omit.
Also, using
Process.Start(fileName, args);
does not uses the info you set up with StartInfo into your Process instance.
Hope this will help,
regards
Not sure if anyone is still following this but here is what I came up with.
string genArgs = arg1 + " " + arg2;
string pathToFile = "Your\Path";
Process runProg = new Process();
try
{
runProg.StartInfo.FileName = pathToFile;
runProg.StartInfo.Arguments = genArgs;
runProg.StartInfo.CreateNoWindow = true;
runProg.Start();
}
catch (Exception ex)
{
MessageBox.Show("Could not start program " + ex);
}
Adding a space in the string allowed two arguments to be passed into the program I wanted to run. The program ran without issue after executing the code.
Have u set your ProcessWindowStyle to Hidden?
This is my code, working fine:
Process p=new Process();
p.StartInfo.FileName = filePath;//filePath of the application
p.StartInfo.Arguments = launchArguments;
p.StartInfo.WindowStyle = (ProcessWindowStyle)ProcessStyle;//Set it to **Normal**
p.Start();
System.Diagnostics.Process.Start(FileName,args);
Eg
System.Diagnostics.Process.Start("iexplore.exe",Application.StartupPath+ "\\Test.xml");
I am writing a program that needs to run a java.jar server. I need to run the process directly so I can rewrite the output to a textbox and all-in-all have complete control of it. I tried just doing it through CMD.exe, but that wouldnt work because CMD.exe would just call a new process java.exe and I wouldn't have control of it. I need to call java.exe directly so I can have the control and get the output. Can any of you tell me how to convert this command so I could create a process in C# and call it?
I need this CMD command converted:
"java -Xmx1024m -cp ./../libs/*;l2jserver.jar net.sf.l2j.gameserver.GameServer"
into
a command line I can put into the Process.Arguments so I can call Java.exe directly.
I've tried to do it... and it just won't work.
I've been looking at this for hours and hours... please someone help!
Part of the problem might be that despite what the Framework documentation says using Process doesn't always resolve things against the PATH environment variable properly. If you know the name of the folder Java is in then use the full path to Java.exe, otherwise use a function like the following:
private void LocateJava()
{
String path = Environment.GetEnvironmentVariable("path");
String[] folders = path.Split(';');
foreach (String folder in folders)
{
if (File.Exists(folder + "java.exe"))
{
this._javadir = folder;
return;
}
else if (File.Exists(folder + "\\java.exe"))
{
this._javadir = folder + "\\";
return;
}
}
}
It's somewhat hacky but it will find java.exe provided the Java Runtime is installed and it's folder is in the windows PATH variable. Make a call to this function the first time your program needs to find Java and then subsequently start Java using the following:
//Prepare the Process
ProcessStartInfo start = new ProcessStartInfo();
if (!_javadir.Equals(String.Empty)) {
start.FileName = this._javadir + "java.exe";
} else {
start.FileName = "java.exe";
}
start.Arguments = "-Xmx1024m -cp ./../libs/*;l2jserver.jar net.sf.l2j.gameserver.GameServer";
start.UseShellExecute = false;
start.RedirectStandardInput = true;
start.RedirectStandardOutput = true;
//Start the Process
Process java = new Process();
java.StartInfo = start;
java.Start();
//Read/Write to/from Standard Input and Output as required using:
java.StandardInput;
java.StandardOutput;