C# ProcessStartInfo and Process.Start cannot find programs in System32 - c#

I'm trying to run a shell command with elevated permisions in C#. However the following code returns:
The system cannot find the file specified.
string command = System.IO.Path.Combine(Environment.SystemDirectory, "wdsutil.exe");
string args = ""; //Appropriate arguments
ProcessStartInfo psInfo = new ProcessStartInfo(command);
psInfo.Arguments = args;
psInfo.Verb = "runas";
try
{
Process p = Process.Start(psInfo);
p.WaitForExit();
return "Try Done";
}
catch(Exception e)
{
return e.Message;
}
The error exists without the SystemDriectory prefixed as well.
However, the command does not return the error if I execute the command C:\wdsutil (or any other command in C:).
How do I get Process.Start to run these commands in System32

system32 is on newer systems (esp. 64 Bit windows 7 or 2008) not "real"... it is synthezied from some internal directories and when it is accessed it shows different apps (32 vs. 64) different content...

I test ran the code, changing the executable to one that I located in C:\Windows\System32 directory. It runs ok. (I am running Win 7 64 Bit)
Suggestion: Make sure that the exe is present in the
C:\Windows\System32, or wherever you are trying to run it from. Also, make sure it is unblocked if you'd downloaded it from the internet (Right click the exe > Properties > Unblock).
string command = System.IO.Path.Combine(Environment.SystemDirectory, "wscript.exe");
string args1 = ""; //Appropriate arguments
ProcessStartInfo psInfo = new ProcessStartInfo(command);
psInfo.Arguments = args1;
psInfo.Verb = "runas";
try
{
Process p = Process.Start(psInfo);
p.WaitForExit();
//return "Try Done";
}
catch (Exception e)
{
//return e.Message;
}

Related

open restore point dialog c#

I am trying to open the restore point dialog from C# like
I'm using the following code:
Process.Start("SystemPropertiesProtection");
and from cmd:
public static string ExecuteCMD(IEnumerable<string> commands,
bool inBackground,
bool runAsAdministrator ,
bool WaitProcessForExit)
{
try
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
if (commands.Any())
{
p.StartInfo.Arguments = #" /C " + string.Join("&&", commands);
}
if (runAsAdministrator)
{
p.StartInfo.Verb = "runas";
}
if (inBackground)
{
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
else
{
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
}
p.OutputDataReceived += (sender, e) => { MessageBox.Show(e.Data); };
p.ErrorDataReceived += (sender, e) => { MessageBox.Show(e.Data); };
p.Start();
if (WaitProcessForExit)
{
p.WaitForExit();
}
return "";// p.StandardOutput.ReadToEnd();
}
catch (Exception ex)
{
FRM_MSG f = new FRM_MSG();
f.ShowDLG(" ",
ex.Message + "\n" + ex.StackTrace.ToString(),
FRM_MSG.MSGIcon.Error,
FRM_MSG.BTNS.One,
new string[] { "Ok" });
throw ex;
}
}
Executor.ExecuteCMD(new string[] { "SystemPropertiesProtection" }, true, false, false);
and even create shortcut to create restore point like this:
and open this shortcut with:
Process.Start(RestorePointShortcutFilePath);
but they always open three tabs and don't open the restore point tab
How do I open restore point dialog like shown on first image which has 5 tabs and not 3 tabs, my OS is Windows 7 64 bit? Thanks.
The issue that you're seeing is because of the File System Redirector which is occurring because you're running your program as 32-bit on your 64-bit OS. Therefore, you're executing %windir%\SysWOW64\SystemPropertiesProtection.exe (ex: C:\Windows\SysWOW64\SystemPropertiesProtection.exe).
There are a few ways to avoid this issue. Uncheck "Prefer 32-bit" (Project => <project name> Properties => Build => uncheck 'Prefer 32-bit'). Compile as x64, or check if your application is running as 32-bit on a 64-bit OS. If so, set the appropriate fully-qualified filename.
The documentation states:
32-bit applications can access the native system directory by
substituting %windir%\Sysnative for %windir%\System32. WOW64
recognizes Sysnative as a special alias used to indicate that the file
system should not redirect the access. This mechanism is flexible and
easy to use, therefore, it is the recommended mechanism to bypass file
system redirection. Note that 64-bit applications cannot use the
Sysnative alias as it is a virtual directory not a real one.
Try the following:
Create a new Windows Forms App (.NET Framework)
Add an Application Manifest to your project
Note: This is used to prompt the user to execute the program as Administrator.
In VS menu, click Project
Select Add New Item...
Select Application Manifest File (Windows only)
Click Add
In app.manifest, replace
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
with
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Add the following using directives:
using System.IO;
using System.Diagnostics;
private void OpenSystemPropertiesProtection()
{
string filename = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "System32", "SystemPropertiesProtection.exe");
//environment variable windir has the same value as SystemRoot
//use 'Sysnative' to access 64-bit files (in System32) if program is running as 32-bit process
//use 'SysWow64' to access 32-bit files on 64-bit OS
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
filename = System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "SysNative", "SystemPropertiesProtection.exe");
Debug.WriteLine($"filename: {filename}");
ProcessStartInfo startInfo = new ProcessStartInfo(filename);
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(filename);
Process.Start(startInfo);
}
Resources:
File System Redirector
Running 32-bit Applications
Use ShellExecute to execute the command.
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "SystemPropertiesProtection";
info.UseShellExecute = true;
Process.Start(info);
I have tested this on Windows 11, but it will probably also work on Windows 7. Be aware that Windows 7 has reached end-of-life back in 2020. It shouldn't be used anymore.

Sending multiple arguments to cmd C#

I currently have a piece of code that opens a cmd prompt using admin rights. What I can't seem to manage is to send a couple of commands to be carried out. I currently have the following code:
var proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = #"C:\Windows\System32";
proc.FileName = #"C:\Windows\System32\cmd.exe";
proc.Verb = "runas";
try
{
Process.Start(proc);
Console.WriteLine("Successfully elevated!");
}
catch (Exception)
{
Console.WriteLine("Failed to elevate.");
}
How would I go about adding a few commands for example what if I wanted to change dir then run an exe file? I am sure it is something very simple I have missed. I have tried giving arguements like so:
proc.Arguments = "cd \\temp";
You can call a .exe from a given filepath using a process.
Like the answer in this: Can you execute another EXE file from within a C# console application?
EDIT:
If you want the directory the program is running from with temp at the end you can do:
string filepath = Directory.GetCurrentDirectory() + #"\temp\programToRun.exe";

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.

Executing System.Diagnostics.Process cmd.exe only opens command prompt, doesn't execute arguments

Where am I going wrong with this? It's like the arguments are not even getting executed, it just opens the command prompt, and that's it. The "results" (StandardOutput) is exactly what shows up when you just open a new command prompt....says Microsoft Windows [Version 6.1.7600] Copyright...blah then the path where the command prompt is starting from.
Anyway, here's the code that I have:
private static void ExecuteProcess(string processFile, string processArguments)
{
ProcessStartInfo psi = new ProcessStartInfo(processFile, processArguments);
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
//psi.CreateNoWindow = true;
Process p = new Process();
p.StartInfo = psi;
try
{
Cursor.Current = Cursors.WaitCursor;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Cursor.Current = Cursors.Default;
if (p.ExitCode == 0)
MessageBox.Show(output, "Results");
else
throw new Exception(p.StandardError.ReadToEnd());
}
catch (Exception ex)
{
Cursor.Current = Cursors.Default;
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
p.Dispose();
}
}
processFile is equal to "cmd.exe"
processArguments is equal to:
csvde -s {servername} -f {filename} -d OU=MyOU,DC=dmz,DC=lan -r "(objectClass=organizationalUnit)" -n
Any help as to why the "arguments" aren't getting executed would be great!
Edit:
One thing I've found so far, Chris's suggestion about the permissions is true, I needed to set:
psi.Verb = "runas";
But when executing the process it didn't look like there was a username associated with the process, so I added this line as well:
psi.UserName = Environment.UserName;
Now I'm getting "the stub received bad data"...
From the docs:
Cmd
Starts a new instance of the command interpreter, Cmd.exe. Used
without parameters, cmd displays Windows XP version and copyright
information.
Syntax cmd [[{/c|/k}] [/s] [/q] [/d] [{/a|/u}] [/t:fg]
[/e:{on|off}] [/f:{on|off}] [/v:{on|off}] string] Top of page
Parameters
/c : Carries out the command specified by string and then
stops.
So you need to:
Pass the full path to the EXE or
Set the working directory to the directory containing the exe
then
Make processFile == "[]csvde.exe", and remove it from processArguments, or
Prepent "/c \"" and append "\"" to processArguments.
I finally got back to working on this and figured out how to get this to work.
I had to specifically set the Username, Password, and Domain of the Process.ProcessStartInfo in order for the process to execute.

Detect 32-bit or 64-bit

I want to launch a program from inside my program, now I can do this relatively easy, and it works using:
protected void butVNC_ItemClick(object sender, EventArgs e)
{
string str = #"C:\Program Files\RealVNC\VNC4\vncviewer.exe";
Process process = new Process();
process.StartInfo.FileName = str;
process.Start();
}
But my problem is, if my program is installed on a 64-bit operating system, that file path is not right, as it is Program Files(x86) so is there a way to detect and run different code or anything.
From .NET 4.0, you can use Environment.Is64BitProcess.
Example:
if (Environment.Is64BitProcess)
{
// Do 64 bit thing
}
else
{
// Do 32 bit thing
}
You can use the %ProgramFiles% enviroment variable to point to the correct Program Files directory. It should point properly to the correct path.
An example : C# - How to get Program Files (x86) on Windows 64 bit
I ended up using this, and works well, and is really simple:
if (IntPtr.Size == 8)
{
string str = #"C:\Program Files(x86)\RealVNC\VNC4\vncviewer.exe";
Process process = new Process();
process.StartInfo.FileName = str;
process.Start();
}
else if (IntPtr.Size == 4)
{
string str = #"C:\Program Files\RealVNC\VNC4\vncviewer.exe";
Process process = new Process();
process.StartInfo.FileName = str;
process.Start();
}
Thank you for your help though :)

Categories

Resources