Ensuring Process.Start() runs under the logged in user - c#

I'm running a batch file from some ASP.NET/C# code on a web server. Basically the batch file performs some test automation tasks on a VM using tools like psloggedon and pexec.
If I run the batch file manually when I'm logged into the server under an administrative account, it works fine.
My problem comes when I run it from my code (below), it seems to run under the 'SYSTEM' account, and psloggedon etc. don't seem to work correctly.
Code
Process p = new Process();
p.StartInfo.FileName = "C:\SetupVM.bat";
p.Start();
p.WaitForExit();
I've got this in my web.config, it doesn't seem to make any differance?
<identity impersonate="true" userName="Administrator" password="myadminpassword"/>
Is there anyway I can ensure the batch file runs under the 'Administrator' account?
UPDATED CODE
Process p = new Process();
p.StartInfo.FileName = "C:\\SetupVM.bat";
p.StartInfo.UserName = "Administrator";
p.StartInfo.UseShellExecute = false;
p.StartInfo.WorkingDirectory = "C:\\";
string prePassword = "myadminpassword";
SecureString passwordSecure = new SecureString();
char[] passwordChars = prePassword.ToCharArray();
foreach (char c in passwordChars)
{
passwordSecure.AppendChar(c);
}
p.StartInfo.Password = passwordSecure;
p.Start();
p.WaitForExit();
From MSDN:
When UseShellExecute is false, you can start only executables with the Process component.
Maybe this is the issue as I'm trying to run a .bat file?
Thanks.

You can provide the username and password to the StartInfo:
Process p = new Process();
p.StartInfo.FileName = "C:\SetupVM.bat";
p.StartInfo.UserName = "Administrator";
p.StartInfo.Password = "AdminPassword";
p.Start();
p.WaitForExit();
See the documentation for ProcessStartInfo.

Related

ASP.Net run exe on server from an API call

I have a WebAPI that works great but need to add the ability to call to an EXE on the server to run some tasks with Video, the server is our machine and running IIS to host the WebAPI.
I have tried it working with Process() and the calls make it to the cmd.exe file I have written but the issue is that the user is IUSER and this won't work as the Video processing needs to use system hardware so needs to be the current logged in Windows User.
I don't want to give the IUSER this privilege for obvious security reasons so I am looking for another way to call and pass data to the an EXE or background task (Short running <3seconds) and for that process to reply with the results.
It's all on the server which we have full control over.
Current Code:
string exeLoc = Environment.ExpandEnvironmentVariables(baseEXELocation);
using var process = new Process();
process.StartInfo.FileName = exeLoc;
process.StartInfo.Arguments = $"{command}";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, data) =>
{
if (!String.IsNullOrEmpty(data.Data))
{
Console.WriteLine(data.Data);
consoleData += data.Data;
}
};
process.Start();
process.BeginOutputReadLine();
var exited = process.WaitForExit(1000 * 10); // (optional) wait up to 10 seconds
Thanks
You could try to use the impersonation in iis:
<identity impersonate="true" />
https://support.microsoft.com/en-us/help/306158/how-to-implement-impersonation-in-an-asp-net-application
or assign the administrator permission to the application pool by using application pool advance setting -> identity to the custom account.
or You can try using the verb runas in Process.Start to execute the exe file as an Administrator.
ProcessStartInfo proc = new ProcessStartInfo();
proc.WindowStyle = ProcessWindowStyle.Normal;
proc.FileName = myExePath;
proc.CreateNoWindow = false;
proc.UseShellExecute = false;
proc.Verb = "runas"; //this is how you pass this verb

Why does Kaspersky anti-virus prevent my program from capturing the output of its child process?

I have a C# program that launches a child process and captures its output in a string. This works on most Windows machines (Windows 7 and newer), but when Kaspersky anti-virus is present, Process.StandardOutput.ReadToEnd() returns null. There is no error code or exception. The child process is a trusted console application. The process takes 5 or 6 seconds to run.
The code for launching the child process is as follows:
ProcessStartInfo psi = new ProcessStartInfo();
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.FileName = "icao.exe";
psi.Arguments = im_path + "image.jpg";
Process p = new Process();
p.StartInfo = psi;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
MessageBox.Show(error);
p.WaitForExit();
int exitCode = p.ExitCode;
MessageBox.Show(exitCode+"");
Why does output end up being null when Kaspersky is present?
My guess is that Kaspersky's heuristics are seeing that your program wants to execute another exe. Because nothing is telling Kaspersky that this is ok, it flags your program as possible malware, because it wants to interface with other programs that are developed by other companies. If you are able to I would try white listing your program with Kaspersky and see if that solves your issue.

Passing arguments one by one one in console exe by c# code

I want to run an exe file by my c# code. The exe file is a console application written in c#.
The console application performs some actions which includes writing content in database and writing some files to directory.
The console application (exe file) expects some inputs from user.
Like it first asks , 'Do you want to reset database ?' y for yes and n for no.
again if user makes a choice then application again asks , 'do you want to reset files ?'
y for yes and n for no.
If user makes some choice the console application starts to get executed.
Now I want to run this exe console application by my c# code. I am trying like this
string strExePath = "exe path";
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = strExePath;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
I want to know how can I provide user inputs to the console application by my c# code?
Please help me out in this. Thanks in advance.
You can redirect input and output streams from your exe file.
See redirectstandardoutput
and redirectstandardinput for examples.
For reading:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
For writing:
...
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.Start();
StreamWriter myStreamWriter = myProcess.StandardInput;
myStreamWriter.WriteLine("y");
...
myStreamWriter.Close();
ProcessStartInfo has a constructor that you can pass arguments to:
public ProcessStartInfo(string fileName, string arguments);
Alternatively, you can set it on it's property:
ProcessStartInfo p = new ProcessStartInfo();
p.Arguments = "some argument";
Here is a sample of how to pass arguments to the *.exe file:
Process p = new Process();
// Redirect the error stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.FileName = #"\filepath.exe";
p.StartInfo.Arguments = "{insert arguments here}";
p.Start();
error += (p.StandardError.ReadToEnd());
p.WaitForExit();

Run new process as admin and read standard output

I want to allow users to run a command line utility as administrator from within my non-admin program and for my program to get the output. The utility is third-party but is distributed with my programme.
I can redirect the output of a program and I can run a program as administrator but I can't do both at the same time.
The only thing that I can get to work at the moment is using cmd.exe to redirect the output to a file, e.g.:
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Reflection;
string appDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string utilityPath = Path.Combine(appDirectory, "tools", "utility.exe");
string tempFile = Path.GetTempFileName();
Process p = new Process();
// hide the command window
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.FileName = "cmd.exe";
// run the tool, redirect the output to the temp file and then close.
p.StartInfo.Arguments = " /C \"\"" + utilityPath + "\" > \"" + tempFile + "\"\"";
p.StartInfo.Verb = "runas"; // run as administrator
p.Start();
p.WaitForExit();
// get the output, delete the file and show the output to the user
string output = File.ReadAllText(tempFile);
File.Delete(tempFile);
MessageBox.Show(output);
This has two problems: 1) it uses a temporary file and 2) the UAC is for cmd.exe rather then utility.exe. There must surely be a better way to do this?
Instead of executing through a new cmd, try executing the utility directly. And instead of redirecting to a file, redirect the standard output to read it from your program.
In order to run as admin, you'll need to use the admin username and password (taken from here). You'll need to set your method as unsafe:
unsafe public static void Main(string[] args){
Process p = new Process();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
// set admin user and password
p.StartInfo.UserName = "adminusername";
char[] chArray = "adminpassword".ToCharArray();
System.Security.SecureString str;
fixed (char* chRef = chArray) {
str = new System.Security.SecureString(chRef, chArray.Length);
}
p.StartInfo.Password = str;
// run and redirect as usual
p.StartInfo.FileName = utilityPath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
Console.WriteLine(output);
p.WaitForExit();
}
This does the magic, although I haven't tested it.
It's written in C++, but a wrapper API can easily be created to be called from C# by using DllImport.

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