Run a batch file as admin in a different server - c#

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?

Related

.NET: C# System.Diagnostics.Process fails to access Shared drive images if being launch as Service, but works correctly launched as a normal.exe

1-) I create a Python .exe which includes this code:
def main():
args = parse_arguments()
result = []
paths = args.files
regions = args.regions
oddplate = args.oddplate
result = []
#print ("Input args ")
#print (args)
#print ("\n")
if not args.sdk_url and not args.api_key:
raise Exception('api-key is required')
if len(paths) == 0:
print('File {} does not exist.'.format(args.FILE))
return
elif args.blur_dir and not os.path.exists(args.blur_dir):
print('{} does not exist'.format(args.blur_dir))
return
....
print(result)
return result
2-) Then, i create a c# function from .net (lets call it ProcessFunc), which includes this code
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo();
// make sure we can read the output from stdout and that window is not shown
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.CreateNoWindow = true;
myProcessStartInfo.FileName = dir_app;
// start python app with 9 arguments
myProcessStartInfo.Arguments = " " + Iapi_key + " " + Isdk_url + " " + Iregions + " " + Iblur_amount + " " + Ioddplate + " " + Iblur_dir;
Process myProcess = new Process();
// assign start information to the process
myProcess.StartInfo = myProcessStartInfo;
// start the process
myProcess.Start();
// Read the standard output of the app we called.
// in order to avoid deadlock we will read output first
// and then wait for process terminate:
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadLine();
/*if you need to read multiple lines, you might use:
string myString = myStreamReader.ReadToEnd() */
// wait exit signal from the app we called and then close it.
myProcess.WaitForExit();
myProcess.Close();
// write the output we got from python app
//Console.WriteLine("Value received from script: " + myString);
return myString;
3-) I have 3 drives, C,N(local machine) and Z (net shared drive)
Having c# code compiled (which generates a .exe) i called the python generated .exe 2 ways:
Double clicking the c# .exe after introducing that code in a main program (lets call it MyCProgramMain)
static void Main()
{
ProcessFunc();
}
This works correctly (Iblur_dir parameter path is accepted)
Generating a service:
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentCulture = new
System.Globalization.CultureInfo("es-ES");
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
Which will create a Thead:
public MyService()
{
InitializeComponent();
HEjecucion = new Thread(classEjecucion.ProcessFunc);
HEjecucion.Start();
Afterwards i will start the generated Service.
When doing it this way, i will get this message in my log (for example):
Z:\2021-08-18\14 does not exist
This will only happen with paths in Z:\ drive, N:\ and C:\ will be accepted.
So, when calling the Python.exe through a Main program focused generated c# .exe
*os.path.exists(args.blur_dir)* understands the path exists
but if i call that same Python.exe through a Service generated with C#, it is unable to access args.blur_dir path
I have tried:
Creating a app.manifest in c#project which includes
(perhaps it was related to priviliges)
Playing around with myProcessStartInfo parameters to see if something could make
I have spent lot of time trying multiple things related to C# Process() parameters, but nothing seems to work in order to make the Service 'reach' the dir_blur path. ¿What else could i try?
You are alright guys! Problem was i was working on a remote desktop in where i was login with an specific user.
Service was automatically installed as 'Local system', and all i had to do was go to Services, in my service "properties" and in 'login' tab introduce credentials i use for remote desktop access.

How do i execute an external exe using a specific user

Im making an application which needs to monitor the filesystem using FileSystemWatcher, to detect how an installation affects the filesystem.
To get rid of noise i want to filter the events that are created by their creating user, and that code is working with the //BUILTIN //Administrator user, which is used by default when doing an installation. But still there are quite a bit of noise. Then i got the idea of creating a specific user that i can use for running the installation file, and filter on that specific user, and thereby getting rid of allmost all the noise.
this is my code for the process creation and start
private void executeInnoInstaller(string path, string fileName)
{
// Use ProcessStartInfo class
ProcessStartInfo installerProces = new ProcessStartInfo();
installerProces.CreateNoWindow = true;
installerProces.UseShellExecute = false;
installerProces.FileName = path + "\"" + fileName + "\"";
installerProces.WindowStyle = ProcessWindowStyle.Normal;
installerProces.UserName = "test";
System.Security.SecureString encPassword = new System.Security.SecureString();
foreach (System.Char c in "test")
{
encPassword.AppendChar(c);
}
encPassword.MakeReadOnly();
installerProces.Password = encPassword;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(installerProces))
{
exeProcess.WaitForExit();
//int exitCode = exeProcess.ExitCode;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
this code exits with a access denied.
OS=Windows
Ive already tried to run the installer.exe from the OS filehandler with SHIFT - Rightclick using the specified user, and it works.
VisualStudio is run as administrator.
Ive tried to run the build project exe file as administrator, but it does not work.
Without the user credentials, the code works and uses the //BUILTIN //Administrator account
Does anybody have any idea ?
Thank you beforehand for your time and effort.
This code works if i turn down the UAC securitylevel to the lowest.

'No such file or directory' if process is run programmatically (from C#)

I have an application that dumps a lot of files to a directory. I want to copy these files to a Hadoop cluster using the hadoop command. I use the following code to run the command.
System.Diagnostics.ProcessStartInfo export = new System.Diagnostics.ProcessStartInfo();
export.RedirectStandardOutput = false;
export.RedirectStandardError = false;
export.UseShellExecute = false;
export.WorkingDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
export.FileName = "hadoop";
export.Arguments = "fs -copyFromLocal " + Path.Combine(dumpDirectory, "*.txt") + " " + hadoopPath));
Console.WriteLine("Copying data: hadoop " + export.Arguments);
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(export);
proc.WaitForExit();
if (proc.ExitCode == 0)
{
IEnumerable<string> files = Directory.EnumerateFiles(dumpDirectory);
foreach (string file in files)
File.Delete(file);
}
else
Console.WriteLine("Error copying to Hadoop: " + proc.ExitCode);
The program writes the following message:
Copying data: hadoop fs -copyFromLocal local/directory/*.txt /user/remote/directory/
copyFromLocal: `local/directory/*.txt': No such file or directory
Error copying to Hadoop: 1
Interestingly, when I run the command manually, the files copy without error.
Also, if the program runs the command without using *.txt and instead calls the command for each file individually, the command succeeds.
Can anyone shed some light on this?
I partially resolved the problem by creating a bash script containing the given command. I ran the bash script programmatically and it worked.
However, I still do not know why the original did not work.

How to open and detect closing of an exe in c#

I am developing a Windows Forms application in which I need to edit certain config files. Now when the user clicks on the edit option, I want to launch these config files in a simple notepad editor. Once launched I want to stall my application. Only when the user closes the notepad editor, I want to un-stall my application. How can this be done ?
I have seen these questions, but the answers have many issues. (I read the comments given there.)
Q1Q2
You can use the Exited-Event:
try
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = "notepad.exe";
myProcess.StartInfo.Arguments = #"C:\PathToYourFile";
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(myProcess_Exited);
myProcess.Start();
}
catch (Exception ex)
{
//Handle ERROR
return;
}
// Handle Exited event and display process information.
private void myProcess_Exited(object sender, System.EventArgs e)
{
eventHandled = true;
Console.WriteLine("Exit time: {0}\r\n" +
"Exit code: {1}\r\nElapsed time: {2}", myProcess.ExitTime, myProcess.ExitCode, elapsedTime);
}
var process = System.Diagnostics.Process.Start("yourfile.txt");
process.WaitForExit();
This will open your file. However, sometimes the process will be null and you will not be able to wait for exit. Why?
Process.Start Method
Return Value Type: System.Diagnostics.Process
A new Process component
that is associated with the process resource, or null if no process
resource is started (for example, if an existing process is reused).
http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
You can initiate a Process and WaitForExit:
Process pr = Process.Start("Notepad");
pr.WaitForExit();

System.Diagnostics.Process can't start process

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.

Categories

Resources