How to launch a process with sudo by ProcessStartInfo? - c#

I have a program in Debian which needs root privileges and myuser has to run it, but I have to do the call from a .NET application (C#) running in mono.
In /etc/sudoers, I have add the line:
myuser ALL = NOPASSWD: /myprogram
so sudo ./myprogram works for myuser.
In. NET I use in my code
string fileName = "/myprogram";
ProcessStartInfo info = new ProcessStartInfo (fileName);
...
How can I do the call "sudo fileName"? It doesn't work by the time...
thank you, Monique.

The following worked for me in a similar situation, and demonstrates passing in multiple arguments:
var psi = new ProcessStartInfo
{
FileName = "/bin/bash",
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = string.Format("-c \"sudo {0} {1} {2}\"", "/path/to/script", "arg1", arg2)
};
using (var p = Process.Start(psi))
{
if (p != null)
{
var strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
}

You just need to pass your program as the argument to the sudo command like this:
ProcessStartInfo info = new ProcessStartInfo("sudo", "/myprogram");
Process.Start(info);

Related

How can I interact with shell responses with .NET Core console app?

I am writing a CLI app to hide some of the details of running commands in the shell/terminal.
With the code below I can execute a single command ssh, for example:
var result = RunCommand("ssh", "100.100.109.86");
static string RunCommand(string command, string args)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = command,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
return string.IsNullOrEmpty(error) ? output : error;
}
My question is how can implement a loop so that I can output the result of the command to the user and enable them to execute another command (or more)?
For example, the response to the above ssh command might as the to ask them if they are sure they want to connect inviting them to respond with (yes/no/[fingerprint])

How to open and use Git Bash through c# code

I'm trying to include opening Git Bash, pushing and pulling in my c# code. Whilst opening Git Bash with Process.Start() is not the problem, I cannot manage to write commands into Git Bash.
I've tried including commands in ProcessStartInfo.Arguments, as well as redirecting the standard Output. Both has not worked at all. Down below you can see the different code snippets I tried.
private void Output()
{
//Try 1
processStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk";
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Argument = "git add *";
Process p = Process.Start(psi);
string strOutput = p.StandardOutput.ReadToEnd();
Console.WriteLine(strOutput);
//Try 2
ProcessStartInfo psi = new ProcessStartInfo(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk");
Process.Start(psi);
psi.Arguments = "git add *";
Process.Start(psi);
//Try 3
var escapedArgs = cmd.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk",
Arguments = "cd C:\\Users\\strit\\autocommittest2\\autocommittest2\n",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
Git Bash opens but nothing is written in the command line.
I know it is old question, still adding answer as few days ago I was also facing same issue.
I think what you are missing is -c parameter. I used below code and it solved this issue. -c tells git-bash to execute whatever follows, it is similar to -cmd parameter in command line.
In below mentioned function -
fileName = path of git-bash.exe.
command = git command which you want to execute.
workingDir = Local path of git repository.
public static void ExecuteGitBashCommand(string fileName, string command, string workingDir)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(fileName, "-c \" " + command + " \"")
{
WorkingDirectory = workingDir,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var process = Process.Start(processStartInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
var exitCode = process.ExitCode;
process.Close();
}
I hope it solves the issue.
I think you are on the right way. I would try to use the git in the path, but it should be possible to also use the git-bash.exe directly, at my machine it is located here: C:\Program Files\Git\git-bash.exe.
Process gitProcess = new Process();
gitInfo.Arguments = YOUR_GIT_COMMAND; // such as "fetch origin"
gitInfo.WorkingDirectory = YOUR_GIT_REPOSITORY_PATH;
gitInfo.UseShellExecute = false;
gitProcess.StartInfo = gitInfo;
gitProcess.Start();
string stderr_str = gitProcess.StandardError.ReadToEnd(); // pick up STDERR
string stdout_str = gitProcess.StandardOutput.ReadToEnd(); // pick up STDOUT
gitProcess.WaitForExit();
gitProcess.Close();
Like #S.Spieker already told you in it's good answer, no need to use git bash (it makes it harder to achieve and less performant), just call directly the git executable.
You could have a look to the GitExtensions code that is doing that: https://github.com/gitextensions/gitextensions/blob/027eabec3be497f8d780cc68ece268c64a43a7d5/GitExtensionsVSIX/Git/GitCommands.cs#L112
You could also achieve what you want using libgit2sharp (https://github.com/libgit2/libgit2sharp). That could be easier if you want to interpret the results of the command run.

C# Process is not stopping

I am using the below code C# Process instance to do a CSV import for PostgreSQL.
Process process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = #"cmd.exe",
Arguments = $"/c cat \"{filePath}\" | psql -h 127.0.0.1 -U {user} -d {dbname} -w -c \"copy data_temp from stdin csv header\" ",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Dispose();
It works but I look in task manager and after a while there is lot of PostgreSQL processes running and eventually the database gets locked.
Am I not closing the process down properly? How can I ensure it doesn't stay open?
Not to sure if this could help or not but here are two examples I have of killing processes via msiexec and Exe.
Uninstalling Msiexec.exe files…
Process x = new Process();
x.StartInfo.FileName = "msiexec.exe";
x.StartInfo.Arguments = "/qb /x {81681F4C-83F1-4F22-9AEB-C7DA7C372EA2}";[quiet uninstall]
x.Start();
x.WaitForExit();
and
Uninstalling exe (file path method, not msiexec)
Process a = new Process();
a.StartInfo.FileName = JPRO_8_5_0; //defined in a string before hand.
a.StartInfo.Arguments = "/uninstall /quiet";
a.Start();
a.WaitForExit();
You can try making the filename a string that is defined before instead of having it as #"cmd.exe", that might help!

How to run shell script with C# on OSX?

I'd like to use C# to execute a shell script.
Based on similar questions I came to a solution that looks like this.
System.Diagnostics.Process.Start("/Applications/Utilities/Terminal.app","sunflow/sunflow.sh");
It currently opens Terminal, then opens the shell file with the default application (Xcode in my case). Changing the default application is not an option, since this app will need to be installed for other users.
Ideally the solution will allow for arguments for the shell file.
I can't test with a Mac right now, but the following code works on Linux and should work on a Mac because Mono hews pretty closely to Microsoft's core .NET interfaces:
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "foo/bar.sh",
Arguments = "arg1 arg2 arg3",
};
Process proc = new Process()
{
StartInfo = startInfo,
};
proc.Start();
A few notes about my environment:
I created a test directory specifically to double-check this code.
I created a file bar.sh in subdirectory foo, with the following code:
#!/bin/sh
for arg in $*
do
echo $arg
done
I wrapped a Main method around the C# code above in Test.cs, and compiled with dmcs Test.cs, and executed with mono Test.exe.
The final output is "arg1 arg2 arg3", with the three tokens separated by newlines
Thanks Adam, it is good starting point for me. However, for some reason when I tried with above code (changed to my needs) I am getting below error
System.ComponentModel.Win32Exception: Exec format error
see below code that gives above error
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "/Users/devpc/mytest.sh",
Arguments = string.Format("{0} {1} {2} {3} {4}", "testarg1", "testarg2", "testarg3", "testarg3", "testarg4"),
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process proc = new Process()
{
StartInfo = startInfo,
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string result = proc.StandardOutput.ReadLine();
//do something here
}
and spent some time and come up with below and it is working in my case - just in case if anyone encounter this error try below
Working Solution:
var command = "sh";
var scriptFile = "/Users/devpc/mytest.sh";//Path to shell script file
var arguments = string.Format("{0} {1} {2} {3} {4}", "testarg1", "testarg2", "testarg3", "testarg3", "testarg4");
var processInfo = new ProcessStartInfo()
{
FileName = command,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process process = Process.Start(processInfo); // Start that process.
while (!process.StandardOutput.EndOfStream)
{
string result = process.StandardOutput.ReadLine();
// do something here
}
process.WaitForExit();

Issue with a Process using '&&'

I have an external app with a number of arguments I need to run programmatically. It's all working fine in a command prompt but when I try to launch the same arguments from a .Net app, it fails. I've now learned it's the use of '&&' that is making the mess at the moment that some of the arguments has.
To simplify my question, say I have something like this working in my command prompt:
"Notepad.exe C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt"
This works fine. My attempt to achieve the equivalent looks like this:
string app = "Notepad.exe";
string args = #"C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo(app, args)
{
UseShellExecute = false,
CreateNoWindow = false,
};
process.Start();
process.WaitForExit();
}
But this obviously does not work. Is my only option to split the arguments by '&&' and run them one by one or is there a way to make this work?
Try this:
string args = #"C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
The reason is that \ starts an escape sequence, meaning the text you pass as arguments is really this:
C: mp mp.txt && Notepad.exe c: mp mp2.txt
\t is the escape sequence for a tab.
The only difference between my code and your is the # in front of the string. This tells the compiler to interpret the string literally. If you need to know more, the name for this is "verbatim string".
UPDATE:
You can use this code:
string app = "cmd";
string args = #"/c Notepad.exe C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo(app, args)
{
UseShellExecute = false,
CreateNoWindow = true,
};
process.Start();
process.WaitForExit();
}
It will use cmd.exe to execute the compounded command. I changed CreateNoWindow to true to not show the command line window, but only the notepad windows.
Have a method:
private void RunAndWait(string app, params string[] args)
{
foreach (string arg in args)
{
Process proc = new Process
{
StartInfo = new ProcessStartInfo(app, arg)
{
UseShellExecute = false,
CreateNoWindow = true
}
};
proc.Start();
proc.WaitForExit();
}
}
And then the code very is simple:
string app = "Notepad.exe";
string args1 = #"C:\tmp\tmp.txt";
string args2 = #"C:\tmp\tmp2.txt";
RunAndWait(app, args1, args2);
And to generalize for more than two files (args):
string[] args = new string[] {#"C:\tmp\tmp.txt", #"C:\tmp\tmp2.txt", ...}
RunAndWait(app, args);

Categories

Resources