Getting the friendly name for a Process after starting it - c#

I'm coding a watchdog service for an embedded system that monitors some proprietary processes and restarts them if necessary. (Nothing to do with malware, before you ask. It's just a business requirement)
I need to retrieve the friendly name from a process I have just created, so that later I can retrieve that process using that name in order to monitor its health.
My problem is as follows:
If I try to read Process.ProcessName right after Process.Start(), I get an InvalidOperationException because it the process has not been fully created yet.
The same happens if I use Process.WaitForInputIdle(), but since this requires a message pump and many executables could be UI-less launchers for the actual application, this might not be an option.
I need to get the friendly name right after creating the process, before doing anything else.
Here's a code snippet:
var startInfo = new ProcessStartInfo { FileName = "notepad.exe" };
var process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForInputIdle();
var friendlyName = process.ProcessName;
This will throw an InvalidOperationException on the last line if the process being started is Firefox, for example.
So how would I do this? Is there a safer method?
EDIT: Added a code snippet for clarification.
EDIT2: Rephrased the whole question for clarification, left irrelevant stuff out.

Ok, so after a lot of research I had to resort to a somewhat hacky solution.
According to the Process.GetProcessesByName() documentation, "The process name is a friendly name for the process, such as Outlook, that does not include the .exe extension or the path.".
Considering this, I worked around the problem using this code:
var startInfo = new ProcessStartInfo { FileName = "notepad.exe" };
var process = new Process();
process.StartInfo = startInfo;
process.Start();
var friendlyName = Path.GetFileNameWithoutExtension(startInfo.FileName);
As I said, it still feels kinda hacky, but at least it got the job done and allowed me to move on.
Thanks for all your comments anyway!

You are missing some key things in your code and try something like this using NotePad.exe and you will see what I am talking about
var startInfo = new ProcessStartInfo { FileName = "notepad.exe" };
var process = new Process();
process.StartInfo = startInfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.Start();
process.WaitForInputIdle();
// this line below will always be false because `process.ProcessName will be
//notepad and process.StartInfo.FileName = notepade.exe
if (process.ProcessName.Equals(process.StartInfo.FileName) == false)
{
var theConfiguredProcessName = process.ProcessName;
}
Another option you could do either of the next 2 things below
Process[] processName = Process.GetProcessesByName("blah.exe");
or check all processes running and check for your running process
Process[] processlist = Process.GetProcesses();
foreach(Process process in processlist)
{
Console.WriteLine("Process: {0} ID: {1}", process.ProcessName, process.Id);
}

Related

How to restart a windows service on failure?

I came across this question, which looked like it would resolve what I'm trying to do, and I'm trying to use similar code where a Process() object is created and the "sc" command is called from code.
static void SetRecoveryOptions(string serviceName)
{
int exitCode;
using (var process = new Process())
{
var startInfo = process.StartInfo;
startInfo.FileName = "sc";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
// tell Windows that the service should restart if it fails
startInfo.Arguments = string.Format("failure \"{0}\" reset= 0 actions= restart/60000", serviceName);
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
}
if (exitCode != 0)
throw new InvalidOperationException();
}
I've tried calling that code from a few locations (such as the committed event handler for the service installer, OnStart of the service itself, etc) but every time I get an exception as soon as the Process() object is created. The exception is: "operation is not allowed due to the current state of the object".
Any ideas what I'm missing here?

Proccess info gives an error but a bat file does not

I try to start ilasm from C# using class ProcessInfo
string arguments = string.Format("\"{0}\" /exe /output:\"{1}\" /debug=IMPL", ilFullFileName, exeFileFullName);
ProcessStartInfo processStartInfo = new ProcessStartInfo(CILCompiler, arguments);
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = false;
processStartInfo.WorkingDirectory = #"c:\Windows\Microsoft.NET\Framework\v4.0.30319\";
using (Process process = Process.Start(processStartInfo))
{
process.WaitForExit();
}
the arguments are:
"path_to_il.il" /exe /output:"path_to_exe.exe" /debug=IMPL
and then it gives me the error:
The application was unable to start correctly (0xc0000007b). Click Ok to close the application.
The odd part of that is, when I do exactly the same actions manually using bat file
"c:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "path_to_il.il" /exe /output:"path_to_exe.exe" /debug=IMPL
pause
it does work.
What did I miss?
I think you need to set the file name as well:
processStartInfo.FileName = "ilasm.exe";

get when active directory was last backed up

Does any one knows how we can find
When active directory was last backed up using C#?
according to my knowledge when we run this command
repadmin /showbackup
its will shows us full detail. I tried to get value of dsa signature using C#, but even that value does not make much sense, and will help us to get correct information of.
Like from which domain controller backup was initiated and on when?
Anyone knows how to get this last backup detail of active directory using C#?
Thanks in advance
I have found many times that not all may be done with WMI, The below code should run the requisite command to show the information you requested and then redirect it to standard out.
System.Diagnostics.ProcessStartInfo PSI =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + "Repadmin.exe /showbackup");
PSI.RedirectStandardOutput = true;
PSI.UseShellExecute = false;
PSI.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = PSI;
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
Console.WriteLine(result);
}
catch (Exception e)
{
Messagebox.Show(e.InnerException);
}
}

Passing arguments to running process in C#

I've some troubles with running processes and passing args to them.
I know how to run process with some args
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c something");
Process p = Process.Start(psi)
The problem is that after script is executed process is terminated. That's why there is "/c"
But I'm running multiple scripts and I would like to run them in one process ("cmd.exe") not to start new process every time.
Is there some solutions for it ?
I hope somebody understand what I'm talking about ;)
I recommend you utilize a batch file to script the execution of your executables and call your batch file instead. Or, you can do this -
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = new StreamWriter(p.StandardInput))
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("mysql -u root -p");
sw.WriteLine("mypassword");
sw.WriteLine("use mydb;");
}
}
It sounds like you ought to investigate redirecting the standard input - be sure to also set psi.UseShellExecute to false. You'll probably also want to redirect standard output, so you can have some way of knowing what your child process is doing.
Read more about redirection here.

C#.Net: Why is my Process.Start() hanging?

I'm trying to run a batch file, as another user, from my web app. For some reason, the batch file hangs! I can see "cmd.exe" running in the task manager, but it just sits there forever, unable to be killed, and the batch file is not running. Here's my code:
SecureString password = new SecureString();
foreach (char c in "mypassword".ToCharArray())
password.AppendChar(c);
ProcessStartInfo psi = new ProcessStartInfo();
psi.WorkingDirectory = #"c:\build";
psi.FileName = Environment.SystemDirectory + #"\cmd.exe";
psi.Arguments = "/q /c build.cmd";
psi.UseShellExecute = false;
psi.UserName = "builder";
psi.Password = password;
Process.Start(psi);
If you didn't guess, this batch file builds my application (a different application than the one that is executing this command).
The Process.Start(psi); line returns immediately, as it should, but the batch file just seems to hang, without executing. Any ideas?
EDIT: See my answer below for the contents of the batch file.
The output.txt never gets created.
I added these lines:
psi.RedirectStandardOutput = true;
Process p = Process.Start(psi);
String outp = p.StandardOutput.ReadLine();
and stepped through them in debug mode. The code hangs on the ReadLine(). I'm stumped!
I believe I've found the answer. It seems that Microsoft, in all their infinite wisdom, has blocked batch files from being executed by IIS in Windows Server 2003. Brenden Tompkins has a work-around here:
http://codebetter.com/blogs/brendan.tompkins/archive/2004/05/13/13484.aspx
That won't work for me, because my batch file uses IF and GOTO, but it would definitely work for simple batch files.
Why not just do all the work in C# instead of using batch files?
I was bored so i wrote this real quick, it's just an outline of how I would do it since I don't know what the command line switches do or the file paths.
using System;
using System.IO;
using System.Text;
using System.Security;
using System.Diagnostics;
namespace asdf
{
class StackoverflowQuestion
{
private const string MSBUILD = #"path\to\msbuild.exe";
private const string BMAIL = #"path\to\bmail.exe";
private const string WORKING_DIR = #"path\to\working_directory";
private string stdout;
private Process p;
public void DoWork()
{
// build project
StartProcess(MSBUILD, "myproject.csproj /t:Build", true);
}
public void StartProcess(string file, string args, bool redirectStdout)
{
SecureString password = new SecureString();
foreach (char c in "mypassword".ToCharArray())
password.AppendChar(c);
ProcessStartInfo psi = new ProcessStartInfo();
p = new Process();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = WORKING_DIR;
psi.FileName = file;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = redirectStdout;
psi.UserName = "builder";
psi.Password = password;
p.StartInfo = psi;
p.EnableRaisingEvents = true;
p.Exited += new EventHandler(p_Exited);
p.Start();
if (redirectStdout)
{
stdout = p.StandardOutput.ReadToEnd();
}
}
void p_Exited(object sender, EventArgs e)
{
if (p.ExitCode != 0)
{
// failed
StringBuilder args = new StringBuilder();
args.Append("-s k2smtpout.secureserver.net ");
args.Append("-f build#example.com ");
args.Append("-t josh#example.com ");
args.Append("-a \"Build failed.\" ");
args.AppendFormat("-m {0} -h", stdout);
// send email
StartProcess(BMAIL, args.ToString(), false);
}
}
}
}
Without seeing the build.cmd it's hard to tell what is going on, however, you should build the path using Path.Combine(arg1, arg2); It's the correct way to build a path.
Path.Combine( Environment.SystemDirectory, "cmd.exe" );
I don't remember now but don't you have to set UseShellExecute = true ?
Another possibility to "debug" it is to use standardoutput and then read from it:
psi.RedirectStandardOutput = True;
Process proc = Process.Start(psi);
String whatever = proc.StandardOutput.ReadLine();
In order to "see" what's going on, I'd suggest you transform the process into something more interactive (turn off Echo off) and put some "prints" to see if anything is actually happening. What is in the output.txt file after you run this?
Does the bmail actually executes?
Put some prints after/before to see what's going on.
Also add "#" to the arguments, just in case:
psi.Arguments = #"/q /c build.cmd";
It has to be something very simple :)
My guess would be that the build.cmd is waiting for some sort of user-interaction/reply. If you log the output of the command with the "> logfile.txt" operator at the end, it might help you find the problem.
Here's the contents of build.cmd:
#echo off
set path=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;%path%
msbuild myproject.csproj /t:Build > output.txt
IF NOT ERRORLEVEL 1 goto :end
:error
bmail -s k2smtpout.secureserver.net -f build#example.com -t josh#example.com -a "Build failed." -m output.txt -h
:end
del output.txt
As you can see, I'm careful not to output anything. It all goes to a file that gets emailed to me if the build happens to fail. I've actually been running this file as a scheduled task nightly for quite a while now. I'm trying to build a web app that allows me to run it on demand.
Thanks for everyone's help so far! The Path.Combine tip was particularly useful.
I think cmd.exe hangs if the parameters are incorrect.
If the batch executes correctly then I would just shell execute it like this instead.
ProcessStartInfo psi = new ProcessStartInfo();
Process p = new Process();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = #"c:\build";
psi.FileName = #"C:\build\build.cmd";
psi.UseShellExecute = true;
psi.UserName = "builder";
psi.Password = password;
p.StartInfo = psi;
p.Start();
Also it could be that cmd.exe just can't find build.cmd so why not give the full path to the file?
What are the endlines of you batch? If the code hangs on ReadLine, then the problem might be that it's unable to read the batch fileā€¦

Categories

Resources