System.Diagnostics.Process can't start process - c#

I'm creating a service on VS2010, using .net framework 4.0 Client Profile. The target machine is Windows Server 2003 64 bits. This service move some files and then executes a process with System.Diagnostics.Process. The trouble is that, even if the taskmanager shows a process as starting, the executable never do whats was made for. Example code:
private void imprimir(string nombreImpresora, int copias, string nombreArchivo)
{
try
{
string copiasSumatra = "1,";
for (int i = 1; i < copias; i++)
{
copiasSumatra += "1,";
}
string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string comando = String.Format("-print-to \"{0}\" \"{1}\" -print-settings \"{2}odd,fit\" -silent", nombreImpresora, nombreArchivo, copiasSumatra);
string filename = '"' + Path.Combine(path, "SumatraPDF.exe") + '"';
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.WorkingDirectory = path;
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = comando;
proc.StartInfo.RedirectStandardError = false;
proc.StartInfo.RedirectStandardOutput = false;
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.ErrorDialog = false;
proc.Start();
proc.WaitForExit();
lc.writeToLog("Instruction executed. Exit code: " + proc.ExitCode);
}
catch (Exception ex)
{
lc.writeToLog(ex.Message + " " + ex.StackTrace);
}
}
If I execute it on my dev machine (windows 8 pro) or in another test server (Windows Server 2003 32 bits) it makes whats expected. If I run it on the WS2003 64 bit server it does nothing.
I've debugged lots of times to see if it produces some error that I'm missing, but nothing happens. The "lc.writeToLog" method prints text to a file. I've used it to log every single line of the execution, but no error is thrown. Using that method I've concluded that it passes the "proc.WaitForExit()" instruction, so I think it's going to do what I've programmed, but nothing happens.
I have runned the same instruction but passing it a user, password and domain and the result was the same. Also tryed to capture standard error and output but it contained nothing.
What could be the trouble?

It was a server related issue. After deploying the application onto the production server the issue has disapeared.

Related

Run a batch file as admin in a different server

I am trying to run a batch file using my C# script which is placed on a different server. My C# script is on one production server X and the batch file is on another production server Y.
My C# script is placed on the task scheduler using a service account which I have added to the server Y as well as an admin and I have given the security rights to the batch file.
Is there anything I might be missing in my code below:
private static void runE(string file)//function to run the E as admin
{
Process proc = null;
try
{
string batDir = string.Format(#"\\ServerY_IP\d$\E\D\");
proc = new Process();
proc.StartInfo.WorkingDirectory = batDir;
proc.StartInfo.FileName = file;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.Verb = #"runas";
proc.StartInfo.Domain = "ServerY_IP";
proc.StartInfo.LoadUserProfile = true;
proc.Start();
Console.WriteLine(file + " is being executed");
WriteLog(file + " is being executed");
proc.WaitForExit(); //wait forever
Thread.Sleep(TimeSpan.FromMinutes(30));
Console.WriteLine(file + " file completed.");
WriteLog(file + " file completed.");
}
catch (Exception ex)
{
WriteLog("Process finished with Errors" + ex.Message);
}
}
I am passing the "kick.bat" file as argument value to this. This file is the one I need to run as admin.
To troubleshoot this I also created another batch file in the same folder and it runs but this "kick.bat" doesn't run.
I found the probable issue with it by running it in the test. After running the task in the test, I received the window pop up prompting me to say yes or no to run the file as admin. How do I embed the yes for the prompt in my C# script?

External tool fails to output in my app but outputs nicely in CMD screen

I am trying to use the GFIX tool that gets shipped with Firebird Database inside my C#/WPF Application to execute certain commands on the database.
Firebird http://www.firebirdsql.org/en/firebird-2-5-3-upd1/
Gfix http://www.firebirdsql.org/manual/gfix.html
To do this I use the following code:
public string RunExternalExe(string filename, string arguments = null)
{
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.Append(args.Data);
string stdError = null;
try
{
process.Start();
process.BeginOutputReadLine();
stdError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
catch (Exception e)
{
throw new Exception("OS error while executing " + Format(filename, arguments) + ": " + e.Message, e);
}
if (process.ExitCode == 0)
{
return stdOutput.ToString();
}
else
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message);
}
}
private string Format(string filename, string arguments)
{
return "'" + filename +
((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) +
"'";
}
Found there
How To: Execute command line in C#, get STD OUT results
also I tried every other approach that gets explained in that question, but it still doesn't get me any output.
I try to execute the following command
gfix.exe -user foo -pa foo -shut single -force 0 app1:\bar.fdb
What I see if I execute it in CMD is the following output
"Your user name and password are not defined. Ask your database administrator to set up a Firebird login."
That's an obvious error because user foo with password foo doesn't exist.
So my problem isn't the error itself, its just the fact that I do NOT get this output inside my C# application not matter what I tried so far.
Since I am seeing the error output in my CMD screen it should get output in my C# application or is there any possibility that the tool itself is blocking the output and I don't have a chance to get it?
What I tried so far:
Calling the gfix.exe itself with the arguments.
Calling a bat that contains the call to gfix.exe with its arguments.
Calling CMD with /c or /k that calls the gfix.exe with arguments.
Calling CMD with /c or /k that calls a bat that calls the gfix.exe.
I believe I tried all possible combinations of calling this tool but still I don't get an output.
Also I have tried both RedirectStandardError and RedirectStandardOutput, with async/sync approaches (Begin.. and ReadToEnd), also I tried to input the arguments with the help of RedirectStandardInput and wrote the lines exactly as I would type it with CMD, first a cd "C:\Test" and than the call to gfix.exe all in vain...
Further info the tool works fine if I input everything correctly its runs through and does exactly what it should do, but I would also like to catch when the tool fails and want to output the corresponding error.
Edit:
Notice that I tried the following now, without my C# app involved only doubleclick the bat or executing it in CMD.
I have modified my test bat file to this:
gfix.exe -user foo -pa foo -shut single -force 0 app1:/bar.fdb > Test.txt 2> error.txt
Which creates 2 Text files - both empty.
If I run this .bat in CMD no error is displayed, if I remove the 2> error.txt the error message again gets displayed in the CMD screen. So the redirect seems to "work" only that my txt files are empty... could the gfix tool block this?!?
This works for me:
using (var process = Process.Start(
new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardError = true,
UseShellExecute = false,
}))
{
process.WaitForExit();
if (process.ExitCode != 0)
{
var errorMessage = process.StandardError.ReadToEnd();
Assert.Fail(errorMessage);
}
}
Note the RedirectStandardError = true.
When error happens gfix outputs it not to stdout, but to stderr. This is obvious and std behavior.

C# run defrag.exe remotely

I am trying to create a utility to defrag all machine on my network. I have had success using WMI's Defrag and DefragAnalysis methods, however they are not compatible with Windows XP. This is a problem as we have some XP machines on the network.
I have been able to locally invoke the defrag.exe process on an XP machine to perform a defrag however I am having problem invoking it on remote machines. Below is my code which works locally, could someone please help me in making this work for remote machines on my network? I have tried using a bit of WMI to help out but as I am new to C# and WMI I haven't had success, thanks!
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "defrag";
info.Arguments = volume + " -f";
info.UseShellExecute = false;
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
Process defrag = Process.Start(info);
defrag.PriorityClass = ProcessPriorityClass.BelowNormal;
while (!defrag.HasExited)
{
System.Threading.Thread.Sleep(1000);
Process[] procs = Process.GetProcessesByName("dfrgntfs");
if (procs != null && procs.Length > 0)
{
procs[0].PriorityClass = ProcessPriorityClass.Idle;
defrag.WaitForExit();
}
result = null;
while(!defrag.StandardOutput.EndOfStream)
{
//get output and store results
}
Just to complete this thread I thought I would post the code that actually worked for me, for this code to work you must download PsTools and place it in the root...
Process psexec = new Process();
psexec.StartInfo.FileName = #"C:\PsExec.exe";
psexec.StartInfo.Arguments = #"-s \\" + machine + " defrag.exe " + volume + " -f";
psexec.StartInfo.UseShellExecute = false;
psexec.StartInfo.CreateNoWindow = true;
psexec.StartInfo.RedirectStandardOutput = true;
psexec.Start();
while (!psexec.HasExited)
{
System.Threading.Thread.Sleep(1000);
Process[] procs = Process.GetProcessesByName("dfrgntfs", #"\\" + machine);
if (procs != null && procs.Length > 0)
{
psexec.WaitForExit();
}
while (!psexec.StandardOutput.EndOfStream)
{
//get output and store results
}
I would probably just use PsExec to run the command remotely. This should work for pretty much any Windows (NT) version.

Catching a vbscript error from c# (the vbscriot executed from c#)

i'm trying to execute vbscript from c#, the vbscript runs always succesfully despite of the fact that i don't have permissions to run this script.
the code:
//nswp is the User's password
foreach (char c in uspw)
{
password.AppendChar(c);
}
Process scriptProc = new Process();
scriptProc.StartInfo.RedirectStandardOutput = true;
scriptProc.StartInfo.RedirectStandardError = true;
scriptProc.StartInfo.Domain = "moia.gov.il";
scriptProc.StartInfo.ErrorDialog = true;
scriptProc.StartInfo.UserName = Globals.CURRENT_USER.user_name;
scriptProc.StartInfo.Password = password;
scriptProc.StartInfo.UseShellExecute = false;
scriptProc.StartInfo.FileName = #"cscript";
scriptProc.StartInfo.Arguments = "//B //Nologo " + pathSave;
scriptProc.Start();
scriptProc.WaitForExit();
scriptProc.Close();
When i'm executing this vbscript manually (by double click on the file icon) i get a permissions error, as i should.
How can i catch this error in c# and throw exception respectively.
You don't have a lot of options when using a different process like you do here. This is about it:
scriptProc.WaitForExit();
if (scriptProc.ExitCode != 0) throw new Exception("Script failed");
You can get rich error info by executing the script in-process by using the COM scripting host. That could be overkill, hard to tell.

C# ProcessStartInfo and Process.Start cannot find programs in System32

I'm trying to run a shell command with elevated permisions in C#. However the following code returns:
The system cannot find the file specified.
string command = System.IO.Path.Combine(Environment.SystemDirectory, "wdsutil.exe");
string args = ""; //Appropriate arguments
ProcessStartInfo psInfo = new ProcessStartInfo(command);
psInfo.Arguments = args;
psInfo.Verb = "runas";
try
{
Process p = Process.Start(psInfo);
p.WaitForExit();
return "Try Done";
}
catch(Exception e)
{
return e.Message;
}
The error exists without the SystemDriectory prefixed as well.
However, the command does not return the error if I execute the command C:\wdsutil (or any other command in C:).
How do I get Process.Start to run these commands in System32
system32 is on newer systems (esp. 64 Bit windows 7 or 2008) not "real"... it is synthezied from some internal directories and when it is accessed it shows different apps (32 vs. 64) different content...
I test ran the code, changing the executable to one that I located in C:\Windows\System32 directory. It runs ok. (I am running Win 7 64 Bit)
Suggestion: Make sure that the exe is present in the
C:\Windows\System32, or wherever you are trying to run it from. Also, make sure it is unblocked if you'd downloaded it from the internet (Right click the exe > Properties > Unblock).
string command = System.IO.Path.Combine(Environment.SystemDirectory, "wscript.exe");
string args1 = ""; //Appropriate arguments
ProcessStartInfo psInfo = new ProcessStartInfo(command);
psInfo.Arguments = args1;
psInfo.Verb = "runas";
try
{
Process p = Process.Start(psInfo);
p.WaitForExit();
//return "Try Done";
}
catch (Exception e)
{
//return e.Message;
}

Categories

Resources