Running Batch File That Execute A GUI Related Task Via WindowService - c#

I know that a Windows service cant run a GUI-related task because it doesn't run on the operation system ui sesssion.
I have a batch file that execute a PowerShell script, this script opens the PowerShell console etc..
When i try to run the batch file using a windows service nothing happen. When I try to run this batch using an exe it works. How can I get the service to run such tasks?

To elaborate on #Henrik's suggestion, you can execute the commands in the batch file, straight from C# instead, which may work.
Process cmd = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
cmd.StartInfo = info;
cmd.Start();
using (StreamWriter sw = cmd.StandardInput)
{
sw.WriteLine("echo command1");
sw.WriteLine("echo command2");
sw.WriteLine("echo command3");
}

Related

Issue executing command line command in .NET c#

Attempting to run ntdsutil from a C# executable and encountering an error. In case anyone is wondering, this is for a automated auditing process as part of a managed service provider - not trying to create a trojan/malware.
The command is: ntdsutil "ac i ntds" "ifm" "create full c:\audit" q q
This is Windows server specific, am running on Windows 2016.
I am using System.Diagnostics.Process and have tried various combinations of properties but getting same result. The following is an example, there is a standard output redirect so can see results of execution:
Process process = new System.Diagnostics.Process();
ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = #"C:\Windows\System32\ntdsutil.exe";
startInfo.Arguments = "\"ac i ntds\" \"ifm\" \"create full c:\\audit\" q q";
//Set output of program to be written to process output stream
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError= true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
// Get program output
string strOutput = process.StandardOutput.ReadToEnd();
//Wait for process to finish
process.WaitForExit();
File.WriteAllText("out.txt", strOutput);
The output looks like this:
C:\Windows\System32\ntdsutil.exe: ifm
ifm: create full c:\audit
error 0x80042302(A Volume Shadow Copy Service component encountered an unexpected error. Check the Application event log for more information.)
ifm: q
C:\Windows\System32\ntdsutil.exe: q
Have checked event logs as mention (nothing obvious) and done various searches on error but nothing useful appears. Running the command on command line works fine.
It is running a Administrator level user. Is it possible related to app.manifest priveleges?
Any help is appreciated.

C# command line execute commands belongs to another executable

Below is the code where I'm trying to run one command with argument. (Call Tectia SFTP client profile & upload file)
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.Arguments = $"/c sftpg3 {profile}";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
using (StreamWriter sw = cmd.StandardInput){
if (sw.BaseStream.CanWrite)
sw.WriteLine($"/c sput {filename} {output}");
}
After the process started, it logins into the into the SFTP and stucked. It won't input the next command as it deemed as another program.
Would like to ask how does it execute the next command after login? I tried Calling CMD with && concatenating and it won't works too. We can only use SFTP via command line as client requested.
Launch sftpg3 with the -B - option to read from standard input.
Launch sftpg3 with the -B <filename> option to read from a batch
file of commands.
More details of command line arguments is available in the documentation.
Also, I don't think you want to write /c the second time around. /c is just something passed to cmd.exe. On that note, why are you calling cmd.exe instead of the binary directly?

Trigger a PS1 file from C# code. C# code has to be wrapped in exe

I have a powershell script which I want to trigger from an EXE.
Things already tried or cannot do:
Can't run powershell directly because process running it is expecting an exe and not a powershell.
Powershell script is pretty complex, so porting it to C# will not be trivial and will be very time consuming.
PS2EXE works, but cannot use because of security policy.
Tried to google on how to create an exe for a ps1 file, but couldn't find any solution (except ps2exe). So I decide to try to execute ps1 using C# and then create an exe. Then wrap both exe and powershell in same msi.
Tried by simply creating Process and starting it:
Process p = new Process();
p.StartInfo = new ProcessStartInfo("powershell.exe");
p.StartInfo.Arguments = #"-Executionpolicy unrestricted C:\script\ms.ps1";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
Above code is working, however it is flashing a black cmd windows for a millisecond or so.
Tried following code from source: https://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C
string scriptText = System.IO.File.ReadAllText(#"C:\script\ms.ps1");
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
pipeline.Commands.Add("Out-String");
pipeline.Invoke();
runspace.Close();
Same problem as above, flashing a black windows for few seconds.
Answer to any of following questions can solve my problem?
How can I create an exe for powershell without using PS2EXE?
How can I disable windows popup when invoking powershell from C# code?
Is there any other way I can solve my problem?
--
Thanks
Hello! You can select "Windows Application" in the project properties instead
of the console
Maybe it help you for this: /flashing a black cmd windows/
Also you can run commands whithout running the script (something like
this):
string MyCommand = "-Command &{ if (!(Test-Path 'c:\\test')) {md 'c:\\test'; get-process | Out-File c:\\test\\MyFile.txt}}";
ProcessStartInfo MyProcInfo = new ProcessStartInfo();
MyProcInfo.FileName = "powershell.exe";
MyProcInfo.Arguments = MyCommand;
Process MyProcess = new Process();
MyProcess.StartInfo = MyProcInfo;
MyProcess.Start();
MyProcess.WaitForExit();

write command to command prompt open via executing bash file

I am working on developing the visual studio plugin. As a part of it, I want to execute one bash file. This bash file opens the command prompt.
Once command prompt is open , we want to write / executes bunch of commands on it.
I have tried it like this:
System.Diagnostics.Process process = System.Diagnostics.Process.Start("MyBash.bat");
process.WaitForExit(5000);
process.StandardInput.WriteLine("echo %PATH%");
But I can see that, it open the command prompt but fail to write command on it.
It throws the exception at the line of writing the command to it. It seems like the command prompt open from this bash file has different process id.
Please help me to resolve it.
Try to execute directly in your batch file:
Insert this to your batch:
start cmd.exe /k "echo %PATH%"
You can also use
/c
if you want to close the cmd After Execution
EDIT:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.RedirectStandardInput = true;
info.UseShellExecute = false;
info.FileName = "mybash.bat";
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("mysql -u root -p");
sw.WriteLine("mypassword");
sw.WriteLine("use mydb;");
}
}

problems with stdout and psexec.exe from sysinternals

i have searched and read about issues with psexec.exe from sysinternals not working properly with c# and stdout. i am now trying to figure out how to just call a batch file that has the following instead of using System.Diagnostics.Process to call psexec:
test.bat contains the following line:
psexec.exe \\hostname -u user -p password ipconfig /all >c:\test.txt
test.txt will be saved on the host where i am running my c sharp app and executing psexec.
when i execute the following:
System.Diagnostics.Process psexec_run = new System.Diagnostics.Process();
psexec_run.StartInfo.FileName = "cmd.exe";
psexec_run.StartInfo.Arguments = #"/c """ + cur_dir + #"\test\test.bat""";
psexec_run.StartInfo.UseShellExecute = false;
psexec_run.Start();
psexec_run.WaitForExit();
i see the cmd window pop up and it runs something but not sure what and goes away.
if i execute the following:
System.Diagnostics.Process psexec_run = new System.Diagnostics.Process();
psexec_run.StartInfo.FileName = cur_dir + "\\test\\psexec.exe";
psexec_run.StartInfo.Arguments = #"\\hostname -u user -p password ipconfig /all";
psexec_run.StartInfo.UseShellExecute = false;
psexec_run.Start();
psexec_run.WaitForExit();
then i see the command window open and it runs psexec which takes quite a few secs and i quickly see my output i need, but i have no way of capturing the output or writing it to a file.
i guess my issue now is since psexec will not work with stdout how can i capture the output from the psexec command to write it to a file???
see the following link for the issues with psexec, the last reply on this url mentioned a way to write the process output to a file without using stdout, i'm newbie to c# i can't figure out how to write process output without use stdout :(
http://forum.sysinternals.com/psexec-fails-to-capture-stdout-when-launched-in-c_topic19333.html
based on response below i tried the following:
ProcessStartInfo psi = new ProcessStartInfo(cur_dir + "\\test\\psexec.exe", #"\\hostname -u user -p password ipconfig /all");
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process p = Process.Start(psi);
StreamReader myStreamReader = p.StandardOutput;
// Read the standard output of the spawned process.
string sOutput = myStreamReader.ReadToEnd();
i did ReadToEnd so i would make sure it got all the output, it DID NOT!! for some reason it only go the first line of ipconfig output that was it. Also the cmd window it opened up never closed for some reason. even with CreateNoWindow=true the code just hangs. so again something is wrong with psexec and stdout i think?? as i can run this code just fine using ipconfig /all command on the local host and not use psexec...
again i am looking to avoid stdout and somehow find a way to get the output from this command or unless there is something else i'm over looking? also, not to make more work for anyone, but if you d/l psexec.exe from sysinternals and test it with a command on a remote host you will see. i have spent 2 days on this one :( trying to figure out how to use psexec or find some other quick method to execute remote command on a host and get ouptput.
UPDATE:
i gave up on psexec in c# code, i saw many posts about psexec eating the output, having a child window process ,etcc
until my head hurt :) so i am trying to run a batch file and output to a file and it's not making sense...
i have a batch file test.bat with the following
psexec.exe \\\hostname -u name -p password ipconfig /all >c:\test.txt
when i run the following code:
ProcessStartInfo psi = new ProcessStartInfo(cur_dir + #"\test\test.bat");
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process p = Process.Start(psi);
p.WaitForExit();
the cmd windows comes and goes really quickly and the test.txt file is created but is 0 bytes no info in it.
so if i run the batch file in a windows cmd line with the psexec command it works perfectly fine!!???
so then to verify psexec was the issue i changed the batch file to:
ipconfig /all >c:\test.txt
i execute my code above and it works fine creates the output in the test.txt file..???!!!!
why is not working with psexec am i missing something? if it's psexec, does anyone have
any recommendations for how i can execute a command on a remote windows host and get me the
output???
I have an answer to this problem that has worked for me.
Hopefully someone else will find it useful.
I have literally just spent the last two hours tearing my hair out with this. The psexec tool runs completely fine using a normal command prompt but when attempting to redirect the streams it truncates the output and you only get half output back.
In the end how I fixed my issue was a little bit of a hack. I piped the output of the command to a text file and read it back in to return it from the function.
I also has to set UseShellExecute to true. Without this it still wouldn't work. This had the unfortunate side effect of showing the console window. To get around that I set the window style to be hidden and hey presto it works!!!
Heres my code:
string ExecutePSExec(string command)
{
string result = "";
try
{
string location = AppDomain.CurrentDomain.BaseDirectory;
// append output to file at the end of this string:
string cmdWithFileOutput = string.Format("{0} >{1}temp.log 2>&1", command,location );
// The flag /c tells "cmd" to execute what follows and exit
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + cmdWithFileOutput);
procStartInfo.UseShellExecute = true; // have to set shell execute to true to
procStartInfo.CreateNoWindow = true;
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden; // as a window will be created set the window style to be hiddem
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
// now read file back.
string filePath = string.Format("{0}temp.log", location);
result = System.IO.File.ReadAllText(filePath);
}
catch (Exception objException)
{
// Log the exception
}
return result;
}
and its usage:
string command = #"psexec.exe -l -u domain\username -p password /accepteula \\192.168.1.3 netstat -a -n";
ExecutePSExec(command);
I had exactly same problem. i was getting "Windows ip config. " as first line when i run with psexec. i tried with paexec it worked well. I used Marius's code.
Note: if you dont use first cmd / c in arguments command runs only on local computer even if you define target as \\remoteserver
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe");
psi.Arguments = #"cmd/c C:\paexec.exe \\\192.168.2.5 -s -u test.local\administrator -p Password1 cmd /c ipconfig";
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process p = Process.Start(psi);
System.IO.StreamReader myStreamReader1 = p.StandardOutput;
p.WaitForExit();
string sOutput = myStreamReader1.ReadToEnd();
Are you sure your sourcecode is correct? that link is quite a bit old.. maybe its fixed!
Heres an example how to redirect the standard-output and put whole output in a string via streamreader:
ProcessStartInfo psi = new ProcessStartInfo("tftp.exe");
// preferences for tftp process
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process p = Process.Start(psi);
StreamReader myStreamReader = p.StandardOutput;
p.WaitForExit();
// Read the standard output of the spawned process.
string sOutput = myStreamReader.ReadToEnd();
i found a solution. apparently psexec is NOT going to work in c sharp. so i came up with some wmi code to connect to a remote host and it's working PERFECTLY!!! :)
i used microsoft's WMICodeCreator.exe to create wmi code for C# for the process method on a remote host, wow that tool is amazing because wmi code is little confusing to me.
psexec's output goes to StandardError and not StandardOutput. I don't know why it is that way. Following code snippet access it.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.RedirectStandardError = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
errors = process.StandardError.ReadToEnd();
process.Close();

Categories