I'm trying to run Python from C# via a command line process.
System.Diagnostics.Process proc = new System.Diagnostics.Process {
StartInfo = new System.Diagnostics.ProcessStartInfo {
FileName = "/Users/username/.pyenv/shims/python",
Arguments = cmd+" "+args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
I derived the FileName from using which:
username$ which python
/Users/username/.pyenv/shims/python
However, running python --version from the terminal, and then again through the C# process, yield different results:
username$ python -V
Python 2.7.11
And C#:
Python 2.7.10
I understand the base problem - that it's calling another version of Python, probably the base one that came from Apple. But what I don't understand is why, because as I understand it I'm telling it to call python from pyenv directly. Is there a way to get C# to use the same python executable I'm using from the terminal?
My bet is that the python shim depends on something else in your environment, and you should probably figure out what it’s eventually running, then call that directly.
According to the pyenv documentation, it's probably at:
$(pyenv root)/versions/2.7.11/bin/python
You might also be able to find out by running the shim with set -x, and looking at the command trace:
(set -x; python --version)
Related
I'm writing an application, and at one point it launches win-acme and needs to pass some parametres to it. I'm successfully opening powershell and launching win-acme, but it doesn't pass arguments to it. So, I have this code:
Process wacsProcess = Process.Start(new ProcessStartInfo
{
FileName = #"C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe",
Arguments = (#"cd C:\inetpub\letsencrypt ; .\wacs.exe ; N"),
RedirectStandardOutput = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
});
File.WriteAllText(".\\OutPutAfterFirstLaunch.txt",
wacsProcess.StandardOutput.ReadToEnd());
It opens command-line utility, but doesn't give it the last parametr "N". I guess that is because I'm passing this parametr to the powershell, but it's still working with win-acme.
It looks like this:
Is there a way to pass an argument to the command line utility using C#?
This is how this application is designed. It is meant to be interactive for new certificates. Please see the documentation with all of the allowed command-line arguments: https://www.win-acme.com/reference/cli
Is there a particular reason that you must launch the process from powershell?
You should be able to read the stdout of the process if you launch it directly the same way as if you were reading the output from your powershell window (the output powershell displays is just the stdout of the process anyways.)
You can also try passing the N parameter with the executable,
Arguments = (#"cd C:\inetpub\letsencrypt ; .\wacs.exe N;"),
When I try to run cmd command 'efwmgr C: -commit' from C#, got empty log file without any information, and when check manually 'ewfmgr C:', got 'Boot Command NO_CMD', so commit not run.
Same code just changed Arguments = "/C chkdsk C:" it runs and works well, inserted whole output into my log.
Method which I used.
public static void StartProcess()
{
var procStartInfo = new ProcessStartInfo
{
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd",
Arguments = "/C ewfmgr C: -commit",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true
};
var process = new Process { StartInfo = procStartInfo, EnableRaisingEvents = true };
using (StreamWriter writer = new StreamWriter(#"D:\commitFile.txt"))
{
process.OutputDataReceived += (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
}
}
This is the nearly example I found on https://social.msdn.microsoft.com/Forums/vstudio/en-US/4e014365-8e8f-4f93-998a-156f2e55ebab/how-to-get-and-write-ewf-current-to-text-file-using-c?forum=csharpgeneral
You probably getting an error in process error output stream. Append your log in ErrorDataReceived event handler. And for the 'ewfmgr' is not recognized as an internal or external command you should edit process environment variable or specify full path to your application.
This is how you code should look like:
var procStartInfo = new ProcessStartInfo
{
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd",
//Append PATH environment variable bellow if you use this
Arguments = "/C ewfmgr C: -commit",
//Or use full path to application without changing environment variable
//Arguments = "/C c:\full\path\to\application\ewfmgr C: -commit",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true
};
procStartInfo.EnvironmentVariables["PATH"] += #";c:\full\path\to\application\";
var process = new Process { StartInfo = procStartInfo, EnableRaisingEvents = true };
using (StreamWriter writer = new StreamWriter(#"D:\commitFile.txt"))
{
process.OutputDataReceived += (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.ErrorDataReceived+= (sender, e) =>
{
writer.WriteLine(e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
Just wanted to point out an update regarding this issue for anyone that might encounter this, or any other file "missing" from Windows/System32 directory:
First things to check is your system architecture, and your process architecture:
There are several posts about this feature (although I prefer to call it issue), I can safely say that this one explains it correclty, and that ewfmgr.exe works just fine if you set your architecture correclty.
In order not to rely on another post/link, I'll rewrite/copy the answer from David there:
There is one explanation that makes sense:
You are executing the program on a 64 bit machine.
Your C# program is built as x86.
The bcdedit.exe file exists in C:\Windows\System32.
Although C:\Windows\System32 is on your system path, in an x86 process you are subject to the File System Redirector. Which means that C:\Windows\System32 actually resolves to C:\Windows\SysWOW64.
There is no 32 bit version of bcdedit.exe in C:\Windows\SysWOW64.
The solution is to change your C# program to target AnyCPU or x64.
As a side note I'd like to also add that by default, VS projects for C# are set as "Any CPU" configuration, however there's checkbox ticked in project properties on the build tab, that says "Prefer 32-bit": This needs to be unchecked/disabled, or "Any cpu" build will result in 32 bit application as well.
Other than that, I've successfully implemented fully working EWF manager into our service application. Unfortunatelly I haven't had any luck using pInvoke and ewfapi dll, since it didn't seem to return correct results. I'm not sure yet whether there was an issue in implementation, or whether the EWF api itself is broken (to be honest, its really buggy and unreliable. For us specifically, the "Disable" command does nothing - after reboot, ewf is still enabled. The only way to disable it is to Disable and Commit, or use CommitAndDisableLive, which both unfortunatelly commit current state onto the drive, so I had to use fallback and reboot the machine before disabling protection, to be sure its in clean state), so I went the route to call it using command line, and parse response parameters to control it. Unfortunatelly it was time critical and I needed production ready solution, so I had to make a workaround, but I'll post a separate question about the pInvoke, and then put on GitHub altogether as a final solution.
I'll come back and edit this post to include the GitHub link once I have the time to upload it. Should someone need it right away, I'm happy to send it over as-is.
Hope it helps.
I need to run an elevated command in my c# application and get the output.
I'm creating a new System.Diagnostics.Process instance, coupled with a new System.Diagnostics.ProcessStartInfo instance.
The command is being sent to cmd.exe, and unfortunately may require elevated user access (meaning UseShellExecute = true and Verb = "runas" must be present).
As a result of using UseShellExecute = true, RedirectStandardOutput will not work.
It's important I record the output of the command, but the only way I can see of getting this is adding something like > output.txt to the argument list, then calling System.IO.File.ReadAllText to read the result.
Can anyone think of less hacky way?
I am trying to pass parameters to Powershell script from a C# class. I am running the script using Process.Start.
string powerShellLocation = #"C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe";
ProcessStartInfo psi = new ProcessStartInfo(powerShellLocation);
psi.Arguments = String.Format("{0} {1}", scriptPath, "some_parameter");
The above does not work. Can someone please tell me how to achieve this?
You need to set the parameter name. Something like this should work:
string parameters = string.Format("-FILE {0} -parameter1 \"{1}\"", psFilePath, parameter1Value);
Process powershell = new Process()
{
StartInfo = new ProcessStartInfo("powershell.exe", parameters)
{
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
What you have would work. You have not mentioned what you meant by above does not work and what your script is.
I tried the C# code with the Powershell script:
param([string]$a)
write-host "test"
write-host $a
and it gave the output:
test
some_parameter
as expected. There is no need to specify -File and -paramter1 like the other answer mentions, but will depend on what your script does.
Did you set the execution policy to unrestricted or to something that allows you to execute the script. By default Powershell sets scripts to be unrestricted to prevent malicious scripts from running.
Run this command as an administrator when powershell is running:
Get-ExecutionPolicy
just downloaded ActivePerl. I want to embed the perl interpreter in a C# application (or at least call the perl interpreter from C#). I need to be able to send send out data to Perl from C#, then receive the output back into C#.
I just installed ActivePerl, and added MS Script Control 1.0 as a reference. I found this code on the internet, but am having trouble getting it to work.
MSScriptControl.ScriptControlClass Interpreter = new MSScriptControl.ScriptControlClass();
Interpreter.Language = #"ActivePerl";
string Program = #"reverse 'abcde'";
string Results = (string)Interpreter.Eval(Program);
return Results;
Originally, it had 'PerlScript' instead of 'ActivePerl', but neither work for me. I'm not entirely sure what Interpreter.Language expects. Does it require the path to the interpreter?
Solved... I'm not sure how, but when I changed it back to PerlScript it works now. Still, I would like to know if MSScript Control is using ActivePerl or another interpreter.
You can run an external program as Maxwell suggests, in which case the external program can be Perl or anything else. It might be easier to use temp files to send the input data and get the output, but that depends on how the external program expects to get its data.
The alternative, which is what I think you're looking for, is to use the PerlNET compiler that comes with ActiveState's Perl Dev Kit. It lets you add a class wrapper around the Perl code so you can expose it to C# just like any C# class. It's fairly simple to use; you add POD comments to your Perl code to specify the method names and signatures to expose, including type information, then you compile your Perl module into a DLL .NET assembly. Once that's done you can reference the assembly from any .NET program, construct an object from your Perl class, and call its methods.
I am not sure about the script control but I have done a similar thing where I had to 'embed' spamassasin (which is a Perl program). I basically used the Process to do the job. Something along the lines of:
var proc = new Process
{
StartInfo =
{
FileName = "perl",
WorkingDirectory = HttpRuntime.AppDomainAppPath,
Arguments = " myscript.pl arg1 arg2",
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false
}
};
proc.Start();
proc.StandardInput.BaseStream.Write... // feed STDIN
proc.StandardOutput.Read... // Read program output
var procStdErr = proc.StandardError.ReadToEnd(); // errors
proc.StandardError.Close();
proc.StandardOutput.Close();
proc.WaitForExit(3000);
int exitCode = proc.ExitCode;
proc.Close();
This obviously not just Perl specific and it has the process creation overhead, so if you are running your script too often probably you need to think of a different solution.