C# Run command prompt from resources - c#

I have a file that i need to run by creating a command prompt.
Basically this is how it goes:
The file's name is UArtCMD.exe, i use it by opening a command prompt in it's directory and run commands that are programmed into it, for example "uartcmd a". What i'm trying to do is add a gui to this software externally, and when, let's say, a button is pressed on the gui, it will run a command using the command prompt.
I've managed to make it run off my computer without any hitches, but the problems occur occur when i install the software on a different computer. Because the UArtCMD is an external software, it wont be on every computer, so what i tried doing is adding it to the resources of the project and run it from there, the problem is i have no idea how to do so.
This is my code for running the command prompt on the computer which has the UArtCMD
public static string executeLine(string command)
{
string result;
try
{
Process process = Process.Start(new ProcessStartInfo("cmd.exe", "/c " + command)
{
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = "C:\\UArtCMD",
RedirectStandardError = true,
RedirectStandardOutput = true
});
process.WaitForExit();
string text = process.StandardOutput.ReadToEnd();
process.Close();
MainWindow.log(text);
result = text;
}
catch (Exception ex)
{
result = ex.StackTrace;
}
return result;
}
Thanks in advance!
If you need me to add any info or expand more on the question do let me know i will gladly do so.

Include a reference to the file UArtCMD.exe in your solution (can be anywhere in the solution structure).
Set its "Copy to Output Directory" property to "Always".
Set your process' "WorkingDirectory" property to
"Environment.CurrentDirectory".
Now UArtCMD.exe should always find it's way into the bin directory (even if it's built by a build agent into a strange output directory) and the code will know to look for it in the same directory as the code is running from.
Edit: The comment about removing the "WorkingDirectory" property from your process object is valid, you can do that instead of setting it to "Environment.CurrentDirectory", they both do the same thing.

Related

Cmd Command (ewfmgr C: -commit) not executed when start it from C# Process

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.

How do I force standard output on a C# Process when UseShellExecute == false?

I am running processes from C# using the following code;
private static void ExecuteShellCMD(string workingDir, string commandWithArgs, bool bWait = true)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "runas";
info.FileName = "cmd.exe";
info.WorkingDirectory = workingDir;
info.Arguments = "/C " + commandWithArgs;
info.UseShellExecute = false;
using (Process myProcess = Process.Start(info))
{
if (bWait)
{
myProcess.WaitForExit();
}
int ExitCode = myProcess.ExitCode;
//Log exit code here.
}
}
It loads an elevated command window and executes the code/bat file I pass it, but without logging anything to the console. This doesn't appear to be consistent on other machines, and has worked in the past on my machine, and I wondered if anyone had any ideas about how I can consistently make this Process just print logs into the command window the process makes.
I can see logs if I set UseShellExecute = true but then can't use Verb without accepting the elevation prompt which is undesirable.
I have tried looking for solutions around the web, and I am aware that I can redirect the output using other settings. Most of the questions and tutorials on this subject seem to deal with redirecting the ouput to somewhere else but I want to be able to keep track of the progress in the command window itself.
Perhaps I have missed an command line argument or similar?
Turns out this was actually a bug in Unity Hub. The process and output were working fine, however when ran from a Unity instance that was launched from Unity Hub it took control of the output and didn't release it. This was solved by just launching Unity directly and a bug report has been filed against Unity hub.

File copy started from aspnet webforms and implemented using batch, pstools and robocopy doesn't work

I have 4 independent servers (not in domain):
IIS, SQL1, SQL2, SQL3
I want to copy a database backup from SQL1 to SQL2 or SQL3 (depending on parameters) by button click on webpage hosted on IIS
I wrote a button click method for that, which is calling batch file located in inetpub folder on IIS
Batch is using pstools to run robocopy on SQL1 which should copy required file to destination server (SQL2 or SQL3)
This solution works if I execute batch directly on IIS (cmd as Administrator) or when I debug it on my local machine, but it doesn't if it is called from the running site.
It even doesn't spend any time between the following lines:
batchProcess.Start();
batchProcess.WaitForExit();
Here is my copy method:
private bool ProcessCopy(string file, string destinationIp)
{
SecureString password = ConvertToSecureString("myPassword");
try
{
string batchPath = Server.MapPath(".") + "\\CopyFile.bat";
string cmd = #"c:\Windows\System32\cmd.exe";
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = cmd,
UseShellExecute = false
};
Process batchProcess = new Process {StartInfo = processInfo};
batchProcess.StartInfo.Arguments = $"/C {batchPath} {file} {destinationIp}";
batchProcess.StartInfo.Domain = "";
batchProcess.StartInfo.UserName = "Administrator";
batchProcess.StartInfo.Password = password;
batchProcess.StartInfo.RedirectStandardOutput = true;
batchProcess.StartInfo.RedirectStandardError = true;
batchProcess.StartInfo.CreateNoWindow = true;
batchProcess.Start();
batchProcess.WaitForExit();
string response = batchProcess.StandardOutput.ReadToEnd();
response += batchProcess.StandardError.ReadToEnd();
statusStringAppend($"response: {response}");
return true;
}
catch (Exception ex)
{
statusStringAppend($"Failed: {ex.Message}. {ex.StackTrace}");
}
return false;
}
Batch body is:
#echo off
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
My questions are:
1. Why the file was not copied?
2. Is there any better way to get it copied?
CODE UPDATED ACCORDING TO SUGGESTIONS BELOW
My guess is that you never executed pstools as the user that your IIS service is running as before, so the EULA dialog is blocking your execution.
If you remember, you always got a window and needed to press the accept button when running any sysinternals tool like pstools the first time.
I guess this should work for you:
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
[EDIT]
You would most likely have hit this problem later on, anyway it did not work for you, so i have to list what else could be wrong with your code:
starting a .bat file needs cmd.exe as mother process, you cannot just start a .bat file as process directly. Instead you can for example use another method than ProcessStartInfo that spawns the system default script interpreter automatically: Executing Batch File in C#
the process for executing batch files is "cmd.exe", first parameter "/C", second parameter the batch file you are executing
when executing typical commandline tools, you might consider reading the SDTOUT (standard output) of the process you are executing, like this: Capturing console output from a .NET application (C#)

clear icon cache in win 7 programmatically - execute ie4uinit.exe-ClearIconCache using C# or Visual Basic

We changed the logo-icon of our WPF application, and then the icon of the main executable. On my PC with Win 7, there is a problem with the refresh of the icon cache: the desktop shortcut to the main executable, and the preview of the icon of the executable, in Windows Explorer still shows the old icon.
Even restarting the system the problem persists.
I found that running this command solves the problem:
ie4uinit.exe-ClearIconCache
My problem is that I can't run it from code. I made two attempts.
First:
Dim si As New ProcessStartInfo()
si.CreateNoWindow = False
si.UseShellExecute = False
si.FileName = "ie4uinit.exe"
si.WindowStyle = ProcessWindowStyle.Hidden
si.Arguments = "-ClearIconCache"
Dim p As Process = Process.Start(si)
error: "Could not find the specified file" - I tried to input the full path but it still doesn't find the file
Second:
I put the command in a batch file
Dim si As New ProcessStartInfo("C:\test.bat")
si.UseShellExecute = False
si.RedirectStandardError = True
si.RedirectStandardInput = True
si.RedirectStandardOutput = True
si.CreateNoWindow = True
si.ErrorDialog = False
si.WindowStyle = ProcessWindowStyle.Hidden
Dim p As Process = Process.Start(si)
This time I get no errors, but not even the desired effect. If I double-click on the batch file instead, everything is working fine.
I'd like to adjust one of these procedure otherwise finding a new one to clear the windows icon cache. C# or Visual Basic is not important...
Pileggi
maybe it doesn't search for it in the path try using:
as the path "%WINDIR%\System32\ie4uinit.exe",
if this doesnt work try "C:\Windows\System32\ie4uinit.exe"
I found the solution: I had to build the executable that runs the batch file for "Any CPU", otherwise it has not sufficient permissions to run ie4unit.
Before I was trying building for "x86" and I was running the process on a Win7 64 bit...
I had a similar issue, trying to call ie4uinit from an Inno installer. The PATH did include the right system directories; however, doing a "dir" did not show that the file exists. In fact, there were over 100 *.exe files that could not be found from whatever shell was executing the command. Opening Explorer or a command window reveals the file is there (which of course we know). I think it is a permissions or access issue. I didn't have the patience to trace it further, but just copied ie4uinit.exe to a local directory and had my installer execute it there.
Enables or disables file system redirection for the calling thread.
[DllImport("Kernel32.dll")]
private static extern bool Wow64EnableWow64FsRedirection(bool Wow64FsEnableRedirection);
//.....
Wow64EnableWow64FsRedirection(false);
Dim p As Process = Process.Start(si)
Wow64EnableWow64FsRedirection(true);
You can try this:
Dim objProcess As System.Diagnostics.Process
objProcess = New System.Diagnostics.Process()
objProcess.StartInfo.FileName = "ie4uinit.exe"
objProcess.StartInfo.Arguments = "-ClearIconCache"
objProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
objProcess.Start()
objProcess.WaitForExit()
objProcess.Close()

get git command line return value using c#

I want to run git commands from c#. below is the coded I had written and it does execute the git command but I am not able to capture the return value. When I manually run it from command line this is the output I get.
When I run from the program the only thing I get is
Cloning into 'testrep'...
Rest of the info is not capture, but the command is executed successfully.
class Program
{
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo("git.exe");
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = #"D:\testrep";
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = "clone http://tk1:tk1#localhost/testrep.git";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
List<string> output = new List<string>();
string lineVal = process.StandardOutput.ReadLine();
while (lineVal != null)
{
output.Add(lineVal);
lineVal = process.StandardOutput.ReadLine();
}
int val = output.Count();
process.WaitForExit();
}
}
From the manual page for git clone:
--progress
Progress status is reported on the standard error stream by default when it is attached to
a terminal, unless -q is specified. This flag forces progress status even if the standard
error stream is not directed to a terminal.
The last three lines in the output when running git clone interactively are sent to standard error, not standard output. They won't show up there when you run the command from your program, however, since it's not an interactive terminal. You could force them to appear, but the output isn't going to be anything usable for a program to parse (lots of \rs to update the progress values).
You are better off not parsing the string output at all, but looking at the integer return value of git clone. If it's nonzero, you had an error (and there will probably be something in standard error that you can show to your user).
Have you tried libgit2sharp? The documentation is not complete, but it is pretty easy to use and there's a nuget package for it. You can always look at the test code to see about usage as well. A simple clone would be like this:
string URL = "http://tk1:tk1#localhost/testrep.git";
string PATH = #"D:\testrep";
Repository.Clone(URL, PATH);
Fetching changes is easy as well:
using (Repository r = new Repository(PATH))
{
Remote remote = r.Network.Remotes["origin"];
r.Network.Fetch(remote, new FetchOptions());
}
Once you call process.WaitForExit() and the process has terminated, you can simply use process.ExitCode which will get you the value that you want.
Your code Looks OK.
this is git problem.
git clone git://git.savannah.gnu.org/wget.git 2> stderr.txt 1> stdout.txt
stderr.txt is empty
stdout.txt:
Cloning into 'wget'...
It looks like git not uses standard console.write() like output you can see it when it writes percentage it's all in one line not like:
10%
25%
60%
100%
process.StandardError.ReadToEnd() + "\n" + process.StandardOutput.ReadToEnd();

Categories

Resources