When i try to run this function it keep crashing when the process starts.
public static void MapDestinationToSource (string destination, string source)
{
System.Diagnostics.Process proc = new System.Diagnostics.Process ();
// set the file to execute
proc.StartInfo.FileName = "mklink";
proc.StartInfo.Arguments = $"/D \"{source}\" \"{destination}\"";
// Redirect the output stream of the child process.
proc.StartInfo.UseShellExecute = true;
//proc.StartInfo.RedirectStandardOutput = true;
// start the process
proc.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 = proc.StandardOutput.ReadToEnd ();
proc.WaitForExit ();
}
Exception:
System.ComponentModel.Win32Exception occurred
HResult=0x80004005
Message=The system cannot find the file specified
Source=System
StackTrace:
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at GameCloud.StorageLibrary.MapDestinationToSource(String destination, String source) in D:\Development\code\sample\server\ClientAgent\ClientAgent\StorageLibrary.cs:line 130
at GameCloud.Program.Main(String[] args) in D:\Development\code\sample\server\ClientAgent\ClientAgent\Program.cs:line 135
When i execute the command on command line, it works. But it does not when in the code. I already set the security policies to allow the current user to execute the mklink command without elevated access.
If you are trying to execute executable programs (bob.exe) check out my striked out answer below.
Since you are trying to run mklink which is built-in to cmd then you need to use:
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = $"/C mklink /D \"{source}\" \"{destination}\"";
The docs state:
When UseShellExecute is true, the WorkingDirectory property specifies
the location of the executable. If WorkingDirectory is an empty
string, it is assumed that the current directory contains the
executable.
and then:
When UseShellExecute is false, the FileName property can be either a
fully qualified path to the executable, or a simple executable name
that the system will attempt to find within folders specified by the
PATH environment variable.
As such, you need to either set UseShellExecute to false (so that your PATH is used to find the executable) or set WorkingDirectory to the folder that contains the executable.
Related
I need to let a .reg file and a .msi file execute automatically using whatever executables these two file types associated with on user's Windows.
.NET Core 2.0 Process.Start(string fileName) docs says:
"the file name does not need to represent an executable file. It can be of any file type for which the extension has been associated with an application installed on the system."
However
using(var proc = Process.Start(#"C:\Users\user2\Desktop\XXXX.reg")) { } //.msi also
gives me
System.ComponentModel.Win32Exception (0x80004005): The specified executable is not a valid application for this OS platform.
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(String fileName)
with ErrorCode and HResult -2147467259, and NativeErrorCode 193.
The same code did work in .Net Framework 3.5 or 4 console app.
I can't specify exact exe file paths as the method's parameter since users' environments are variant (including Windows versions) and out of my control. That's also why I need to port the program to .Net Core, trying to make it work as SCD console app so that installation of specific .Net Framework or .NET Core version is not required.
The exception is thrown both in Visual Studio debugging run and when published as win-x86 SCD. My PC is Win7 64bit and I'm sure .reg and .msi are associated with regular programs as usual Windows PC does.
Is there solution for this? Any help is appreciated.
You can also set the UseShellExecute property of ProcessStartInfo to true
var p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\Users\user2\Desktop\XXXX.reg")
{
UseShellExecute = true
};
p.Start();
Seems to be a change in .net Core, as documented here.
See also breaking changes.
You can set UseShellExecute to true and include this and your path in a ProcessStartInfo object:
Process.Start(new ProcessStartInfo(#"C:\Users\user2\Desktop\XXXX.reg") { UseShellExecute = true });
In case this bothers you as well:
For those of us that are used to simply calling Process.Start(fileName); the above syntax may give us anxiety... So may I add that you can write it in a single line of code?
new Process { StartInfo = new ProcessStartInfo(fileName) { UseShellExecute = true } }.Start();
You have to execute cmd.exe
var proc = Process.Start(#"cmd.exe ",#"/c C:\Users\user2\Desktop\XXXX.reg")
don't forget the /c
use this to open a file
new ProcessStartInfo(#"C:\Temp\1.txt").StartProcess();
need this extension method
public static class UT
{
public static Process StartProcess(this ProcessStartInfo psi, bool useShellExecute = true)
{
psi.UseShellExecute = useShellExecute;
return Process.Start(psi);
}
}
string itemseleccionado = lbdatos.SelectedItem.ToString();
var p = new Process();
p.StartInfo = new ProcessStartInfo(itemseleccionado)
{
UseShellExecute = true
};
p.Start();
I am trying to run logman.exe for a elevated CMD, for this below code I tried,
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\Windows\System32\cmd.exe",
Arguments = "cmd /k logman.exe PerfCounterCustom | findstr \"Root\"",
Verb = "runas",
UseShellExecute = true,
}
};
try
{
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
}
Console.WriteLine("Successfully elevated!");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
And it's giving error output like,
System.InvalidOperationException: StandardOut has not been redirected or the process hasn't started yet.
at System.Diagnostics.Process.get_StandardOutput()
2 Questions,
when I am running application exe, it's showing 2 CMD window, the 1st one showing error and 2nd one showing result for argument "cmd /k logman.exe PerfCounterCustom | findstr \"Root\"" [Root Path]
how to disable showing both window?
Why I am getting this error?
To your 1st Question: In the ProcessStartInfo set WindowStyle to ProcessWindowStyle.Hidden
An alternative solution to read the output of the command is to write the output to a text file. Therefore you have to add >> "[Name or Path of file].txt" to the end of your command. Then just read the file from C# e.g. with File.ReadAllLines.
Two things to consider here:
If you do that often at Runtime and the command delivers huge amounts of text don't write it to an SSD.
Please check that the file is empty / not existing before, because Windows just appends the output to the end of the file. If you run that in multiple threads use a thread identifier in the file name.
You have to set RedirectStandardOutput of the ProcessStartInfo to true and you have to run proc.WaitForExit() before reading the output.
Please note that this solution causes incompatibilities with running the process as administrator via runas.
Am a Newbie in C# and I have 3 commands(command2, command3 and command4) I need to execute in the elevated command prompt and I will also like to view the execution process as it happens. Currently, the problem is that the code below just opens the elevated command prompt and without executing the commands. I also seek better interpretations of the lines if wrong.
My code and Interpretation/Understanding of each line based on reviews of similar cases: ConsoleApp1
class Program
{
static void Main(string[] args)
{
string command2 = #"netsh wlan";
string command3 = #" set hostednetwork mode=true ssid=egghead key=beanhead keyusage=persistent";
string command4 = #" start hostednetwork";
string maincomm = command2.Replace(#"\", #"\\") + " " + command3.Replace(#"\", #"\\") ; //I merged commands 2 and 3
ProcessStartInfo newstartInfo = new ProcessStartInfo();
newstartInfo.FileName = "cmd"; //Intend to open cmd. without this the newProcess hits an error saying - Cannot run process without a filename.
newstartInfo.Verb = "runas"; //Opens cmd in elevated mode
newstartInfo.Arguments = maincomm; //I intend to pass in the merged commands.
newstartInfo.UseShellExecute = true; //
newstartInfo.CreateNoWindow = true; // I intend to see the cmd window
Process newProcess = new Process(); //
newProcess.StartInfo = newstartInfo; //Assigns my newstartInfo to the process object that will execute
newProcess.Start(); // Begin process and Execute newstartInfo
newProcess.StartInfo.Arguments = command4; //I intend to overwrite the initial command argument hereby passing the another command to execute.
newProcess.WaitForExit(); //
}
}
This is what I did to overcome the challenge and It gave me exactly what I wanted. I modified my code to use the System.IO to write directly to the elevated command prompt.
ProcessStartInfo newstartInfo = new ProcessStartInfo();
newstartInfo.FileName = "cmd";
newstartInfo.Verb = "runas";
newstartInfo.RedirectStandardInput = true;
newstartInfo.UseShellExecute = false; //The Process object must have the UseShellExecute property set to false in order to redirect IO streams.
Process newProcess = new Process();
newProcess.StartInfo = newstartInfo;
newProcess.Start();
StreamWriter write = newProcess.StandardInput ; //Using the Streamwriter to write to the elevated command prompt.
write.WriteLine(maincomm); //First command executes in elevated command prompt
write.WriteLine(command4); //Second command executes and Everything works fine
newProcess.WaitForExit();
Referrence: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardinput(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx
I think an understanding of some properties of the ProcessStartInfo might clear things.
The verb - Gets or sets the verb to use when opening the application or document specified by the FileName property.,
+The UseShellExecute - Gets or sets a value indicating whether to use the operating system shell to start the process.
+The FileName - Gets or sets the application or document to start MSDN Docs
When you use the operating system shell to start processes, you can start any document (which is any registered file type associated with an executable that has a default open action) and perform operations on the file, such as printing, by using the Process object. When UseShellExecute is false, you can start only executables by using the Process object Documentation from MSDN.
In my case, cmd is an executable. the verb property is some thing that answers the question "How should my I run my FileName(for executables e.g cmd or any application)?" for which I answered - "runas" i.e run as administrator. When the FileName is a document (e.g `someFile.txt), the verb answers the question "What should I do with the file for which answer(verb) could be -"Edit","print" etc. also?"
use true if the shell should be used when starting the process; false if the process should be created directly from the executable file. The default is true MSDN Docs - UserShellInfo.
Another thing worth noting is knowing what you are trying to achieve. In my case, I want to be able to run commands via an executable(cmd prompt) with the same process - i.e starting the cmd as a process I can keep track of.
I am using the following code within a program that does not have elevated privileges
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = fileToExcecute;
pInfo.UseShellExecute = false;
pInfo.RedirectStandardOutput = false;
pInfo.RedirectStandardError = false;
pInfo.CreateNoWindow = true;
if (runAsAdministrator)
pInfo.Verb = "runas";
Process p = Process.Start(pInfo);
The end user is asked to select whether they wish to run the program in elevated mode or not. The above however is not starting the program 'As Administrator' when runAsAdministrator is true. I have ran the 'fileToExcute' manually 'As Administrator' and it prompts to make changes to the computer.
I then added a manifest to the 'fileToExecute' to run with elevated privileges every time and when running that program directly I am properly prompted to confirm permission to make changes to the computer. When I run the above program that uses the above code, I get:
System.ComponentModel.Win32Exception (0x80004005):
The requested operation requires elevation at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start() at System.Diagnostics.Process.Start(ProcessStartInfo startInfo) at
#HLg.#ic.#zNg(String #ANg) in #pOg:line 135
I really want the first option to work. I've tried everything and can't work out why the first option is not working.
You can't combine the Verb property with UseShellExecute = false, since verbs rely on that functionality. Set UseShellExecute to true and it should work.
I changed my code and did not use the pInfo configuration options. I just changed everything to p.verb = "runas" etc and it is now working.
I have a .bat file to be executed.
Inside that .bat file, at its end is that code
START _file_creator.bat %some_arg_name%
ENDLOCAL
EXIT
I don't want to show the window during the execution and also I must wait until the operation doing by this .bat file is completed and then terminate the execution (at the end of the operation I see the standard text "Press any key to continue"). I need also to check the output and errors by that file, so I'm trying to use that code:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = #"C:\m_f\_config.bat";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
output1 = proc.StandardError.ReadToEnd();
proc.WaitForExit();
output2 = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
But all I get is the error
Windows can not find file "_file_creator.bat".
Make sure you typed the name correctly and try again.
of course if I run that .bat file with the proc.StartInfo.UseShellExecute = true it works fine, but in that case I can't set RedirectStandardError = true and RedirectStandardOutput = true
How to fix it ?
Edit
using that code it works now
proc.StartInfo.FileName = #"C:\m_f\_config.bat";
proc.StartInfo.WorkingDirectory = #"C:\m_f\";
Try setting the working directory correctly or make sure that _file_creator.bat is somewhere in the PATH. See the documentation about the working directory in conjunction with UseShellExecute:
The WorkingDirectory property behaves differently depending on the value of the UseShellExecute property. When UseShellExecute is true, the WorkingDirectory property specifies the location of the executable. If WorkingDirectory is an empty string, it is assumed that the current directory contains the executable.
When UseShellExecute is false, the WorkingDirectory property is not used to find the executable. Instead, it is used only by the process that is started and has meaning only within the context of the new process. When UseShellExecute is false, the FileName property must be a fully qualified path to the executable.