Fail to execute a specific cmd batch file in C# - c#

I'm using Process to execute a batch file which will generate certificate file.
The code works great when I execute other file (which contains openssl command). But when I execute a file which contains keytool command, it executed, but no file was generated.
I've:
Set UseShellExecute true.
Set WaitForExit(-1) and find the return was true, so it did executed.
I clicked that batch file manually, and the file generates right away, so the command was fine :(
BTW I'm using .Net Core MVC.
I can't find any error code anywhere, so I'm at my wits' end now.
Does anyone has a clue? Any help would be very appriciated!
success code(openssl):
I generate a p12 file (a certificate format) in that folder first, and it works fine.
private string Gen_P12(string domain, string pwd)
{
//generate folder
string folder = #"D:\Temp\";
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
//generate bat(p12)
string bat = "openssl.exe pkcs12 -export -inkey " + domain + ".key -in " + domain + ".cer -out " + domain + ".p12 -password pass:" + pwd +"\r\n";
//download in folder
var path = Path.Combine(folder, domain + "_P12.bat");
using (FileStream fs = System.IO.File.Create(path))
{
byte[] content = new UTF8Encoding(true).GetBytes(bat);
fs.Write(content, 0, content.Length);
}
Thread.Sleep(500);
//execute
ProcessStartInfo myBat = new ProcessStartInfo();
string name = domain + "_P12.bat";
myBat.FileName = name;
myBat.WorkingDirectory = folder;
myBat.UseShellExecute = true;
//Process.Start(myBat);
Process p = Process.Start(myBat);
p.WaitForExit(-1);
return folder;
}
fail code(keytool):
Trying to use that P12 file and keytool command to generate a keystore (also a certificate format) but fail.
private string Gen_KS(string domain, string folder, string CA_domain, byte[] cer, string pwd)
{
//generate bat
string bat = "keytool -importkeystore -srckeystore " + domain + ".p12 -srcstoretype PKCS12 -srcstorepass " + pwd + " -destkeystore " + domain + ".keystore -storepass " + pwd + "\r\n";
var path = Path.Combine(folder, domain + "_KS.bat");
using (FileStream fs = System.IO.File.Create(path))
{
byte[] content = new UTF8Encoding(true).GetBytes(bat);
fs.Write(content, 0, content.Length);
}
Thread.Sleep(700);
//execute
ProcessStartInfo myBat = new ProcessStartInfo();
myBat.WorkingDirectory = folder;
string name = domain + "_KS.bat";
myBat.FileName = name;
myBat.UseShellExecute = true;
Process p = Process.Start(myBat);
var a = p.WaitForExit(-1);
string route = folder + domain + ".keystore";
return route;
}
Thanks!

Thanks to #user9938, I solved the problem!
1. Brief conclusion:
I need to process the bat as administrator.
(And I still don't get why only do the keytool command needs administrator rights)
2. Find the errors: (How to apply StanderError when UseShellExecute=true)
In fact we don't have to set it true to execute commands.
Try this (replace execute section):
Process process = new Process();
try
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = "cmd.exe";
process.Start();
process.StandardInput.WriteLine(bat); //command string, not the bat file
process.StandardInput.AutoFlush = true;
process.StandardInput.WriteLine("exit");
StreamReader reader = process.StandardError;
string curLine = reader.ReadLine();
reader.Close();
process.WaitForExit();
process.Close();
}catch (Exception e){}
Check the value of curLine through Breakpoints, the error message was: "'keytool' is not recognized as an internal or external command, operable program or batch file".
3. How to solve it:
Just set the Verb attribute as "runas".
//execute
ProcessStartInfo myBat = new ProcessStartInfo();
myBat.WorkingDirectory = folder;
string name = domain + "_KS.bat";
myBat.Verb = "runas";
myBat.FileName = name;
myBat.UseShellExecute = true;
Process p = Process.Start(myBat);
var a = p.WaitForExit(-1);
Done! Thank you user9938<3

Related

Converting XSD into .cs class

I know this may seem to be a duplicated question but I highly doubt it.
I am currently making a Windows Form application where the user can select an XSD file using the OpenFileDialog
Once the XSD is uploaded/selected I want it to create a .cs file from it using the default developer XSD tool.
But for some reason, it just opens the selected XSD file in notepad(?)
I've tried to comment the code to give it some sense.
//Filter only .xsd files
ofd.Filter = "XSD|*.xsd";
if (ofd.ShowDialog() == DialogResult.OK)
{
//Read file name
string File = ofd.FileName;
string z = ofd.InitialDirectory;
//Start making commands for in the CMD
//Change directory to the folder where the Dev Command prompt is located
string changeDirectory = #"cd C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\";
//Open the Dev CMD
string bat = "VsDevCmd";
//Change folder to our test folder
string cd = #"cd C:\Users\Pierre\Desktop\testxsd";
//execute xsd /c *selected file* /c is used to create the .cs file.
string command = #"xsd /c " + File;
//Combine the commands into 1 line.
string x = cd + "&" + command;
string xyz = changeDirectory + "&" + bat + "&" + x;
//print the outcome -> When I copy paste this into CMD the .cs file is generated
Console.WriteLine(xyz);
ProcessStartInfo oInfo = new ProcessStartInfo(Environment.ExpandEnvironmentVariables(#"C:\WINDOWS\system32\cmd.exe"), xyz);
oInfo.UseShellExecute = false;
oInfo.ErrorDialog = false;
oInfo.CreateNoWindow = true;
oInfo.RedirectStandardOutput = true;
try
{
Process p = System.Diagnostics.Process.Start(oInfo);
System.IO.StreamReader oReader2 = p.StandardOutput;
string sRes = oReader2.ReadToEnd();
oReader2.Close();
// sRes now contains the output from xsd.exe
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
So, as you can see in the comments, when I copy paste the console.writeline(xyz) into CMD it got properly executed and the .cs file is generated as it should.
However, when I just launch this code it opens the selected xsd in notepad.
Literally no idea what could be wrong
You are kind of taking the very long panoramic route when there is actually a very quick one... As #PatrickHofman stated in the comments use xsd directly...
To do this, open the Visual Studio command prompt, and write where xsd to find exact path of xsd executable.
Then start a process using xsd from the path you found and the various options ie. /c and filename.
using System.Diagnostics;
...
FileInfo fi = new FileInfo(ofd.FileName);
Process process = new Process();
process.StartInfo.FileName = xsdPath;
process.StartInfo.Arguments = "/c " + fi.FullName;
process.StartInfo.WorkingDirectory = fi.DirectoryName;
process.Start();
//wait for exit if needed...
process.WaitForExit();
If for some reason this is not working, capture the output from the command by doing this before process.Start():
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived +=
(sender, args) => Console.WriteLine("received output: {0}", args.Data);
process.BeginOutputReadLine();
I think you should use the XmlSchemaClassGenerator package for this (Nuget). That way you wont have to do all the process juggling yourself.
Example from GitHub readme:
var generator = new Generator
{
OutputFolder = outputFolder,
Log = s => Console.Out.WriteLine(s),
GenerateNullables = true,
NamespaceProvider = new Dictionary<NamespaceKey, string>
{
{ new NamespaceKey("http://wadl.dev.java.net/2009/02"), "Wadl" }
}
.ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "Wadl" }.NamespaceProvider.GenerateNamespace)
};
generator.Generate(files);

Create pdf from html using wkhtmltopdf

i am genrating pdf from html code.Here i find code for generating using wkhtmltopdf
private void WritePDF(string HTML)
{
string inFileName,
outFileName,
tempPath;
Process p;
System.IO.StreamWriter stdin;
ProcessStartInfo psi = new ProcessStartInfo();
tempPath = Request.PhysicalApplicationPath + "ExcelFiles\\";
inFileName = Session.SessionID + ".htm";
outFileName = Session.SessionID + ".pdf";
// run the conversion utility
psi.UseShellExecute = false;
psi.FileName = "E:\\wkhtmltopdf";
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// note that we tell wkhtmltopdf to be quiet and not run scripts
// NOTE: I couldn't figure out a way to get both stdin and stdout redirected so we have to write to a file and then clean up afterwards
psi.Arguments = "-q -n - " + tempPath + outFileName;
p = Process.Start(psi);
try
{
stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(HTML);
stdin.Close();
if (p.WaitForExit(15000))
{
// NOTE: the application hangs when we use WriteFile (due to the Delete below?); this works
Response.BinaryWrite(System.IO.File.ReadAllBytes(tempPath + outFileName));
//Response.WriteFile(tempPath + outFileName);
}
}
finally
{
p.Close();
p.Dispose();
}
// delete the pdf
System.IO.File.Delete(tempPath + outFileName);
}
I found this answer from here
how to pass html as a string using wkhtmltopdf?
Here i get error Could not find file on
if (p.WaitForExit(15000))
{
// NOTE: the application hangs when we use WriteFile (due to the Delete below?); this works
Response.BinaryWrite(System.IO.File.ReadAllBytes(tempPath + outFileName));
//Response.WriteFile(tempPath + outFileName);
}
how i can create file for this now?
It gets Created on stdin.Close();
Please check if the html in stdin.Write(HTML); has some content in it

How to create a RAM Disk with imdisk and C#?

I'm trying to create a RAM Directory via imdisk in C#. Since the cmd command is something like: imdisk -a -s 512M -m X: -p "/fs:ntfs /q /y"
I looked up how to process cmd commands with C# and found several hints regarding ProcessStartInfo(). This class works almost the way I intend it to, but since imdisk needs administrator priviliges I'm kinda stuck. Even though the code block is executed without exceptions, I don't see any new devices within the Windows Explorer.
try
{
string initializeDisk = "imdisk -a ";
string imdiskSize = "-s 1024M ";
string mountPoint = "-m "+ MountPoint + " ";
string formatHdd = "-p '/fs:ntfs /q /y' ";
SecureString password = new SecureString();
password.AppendChar('0');
password.AppendChar('8');
password.AppendChar('1');
password.AppendChar('5');
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.FileName = "cmd";
procStartInfo.Verb = "runas";
procStartInfo.UserName = "Admin";
procStartInfo.Password = password;
procStartInfo.Arguments = initializeDisk + imdiskSize + mountPoint + formatHdd;
Process.Start(procStartInfo);
catch (Exception objException)
{
Console.WriteLine(objException);
}
I hope someone can give me a little hint, right now I'm out of ideas.
Well I solved my problem in a different way. Somehow it seems that imdisk didn't format the new RamDisk the way it should and therefor no disk were created. As soon as I deleted the formatting option the disk is created and needs to be formatted. Therefore I started another process and used the cmd command "format Drive:"
For anyone who is interested, my solution is as follows:
class RamDisk
{
public const string MountPoint = "X:";
public void createRamDisk()
{
try
{
string initializeDisk = "imdisk -a ";
string imdiskSize = "-s 1024M ";
string mountPoint = "-m "+ MountPoint + " ";
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
procStartInfo.FileName = "cmd";
procStartInfo.Arguments = "/C " + initializeDisk + imdiskSize + mountPoint;
Process.Start(procStartInfo);
formatRAMDisk();
}
catch (Exception objException)
{
Console.WriteLine("There was an Error, while trying to create a ramdisk! Do you have imdisk installed?");
Console.WriteLine(objException);
}
}
/**
* since the format option with imdisk doesn't seem to work
* use the fomat X: command via cmd
*
* as I would say in german:
* "Von hinten durch die Brust ins Auge"
* **/
private void formatRAMDisk(){
string cmdFormatHDD = "format " + MountPoint + "/Q /FS:NTFS";
SecureString password = new SecureString();
password.AppendChar('0');
password.AppendChar('8');
password.AppendChar('1');
password.AppendChar('5');
ProcessStartInfo formatRAMDiskProcess = new ProcessStartInfo();
formatRAMDiskProcess.UseShellExecute = false;
formatRAMDiskProcess.CreateNoWindow = true;
formatRAMDiskProcess.RedirectStandardInput = true;
formatRAMDiskProcess.FileName = "cmd";
formatRAMDiskProcess.Verb = "runas";
formatRAMDiskProcess.UserName = "Administrator";
formatRAMDiskProcess.Password = password;
formatRAMDiskProcess.Arguments = "/C " + cmdFormatHDD;
Process process = Process.Start(formatRAMDiskProcess);
sendCMDInput(process);
}
private void sendCMDInput(Process process)
{
StreamWriter inputWriter = process.StandardInput;
inputWriter.WriteLine("J");
inputWriter.Flush();
inputWriter.WriteLine("RAMDisk for valueable data");
inputWriter.Flush();
}
public string getMountPoint()
{
return MountPoint;
}
}
Doesn't cmd.exe need to have the /C command line option passed through to run a command passed through as an argument? May well be that cmd.exe is just ignoring what you're passing through in procStartInfo.Arguments because you haven't prepended "/C " onto the front of the Arguments.

How to uninstall Software using c# by calling Software UninstallString Listed in Registry file of that Software But the Process Is Not Working

I am developing a software that will list all the software install
in Computer
now i want to Uninstall it using my Program In C# by
calling the Uninstall Key of that software in
Registry Key
My Program Is
Like That But the Process Is Not Working
var UninstallDir = "MsiExec.exe /I{F98C2FAC-6DFB-43AB-8B99-8F6907589021}";
string _path = "";
string _args = "";
Process _Process = new Process();
if (UninstallDir != null && UninstallDir != "")
{
if (UninstallDir.StartsWith("rundll32.exe"))
{
_args = ConstructPath(UninstallDir);
_Process.StartInfo.FileName = Environment.SystemDirectory.ToString() + "\\explorer.exe";
_Process.StartInfo.Arguments = Environment.SystemDirectory.ToString() + "\\" + UninstallDir;
_Process.Start();
}
else if (UninstallDir.StartsWith("MsiExec.exe"))
{
_args = ConstructPath(UninstallDir);
_Process.StartInfo.FileName = Environment.SystemDirectory.ToString() + "\\cmd.exe";
_Process.StartInfo.Arguments = Environment.SystemDirectory.ToString() + "\\" + UninstallDir;
_Process.Start();
}
else
{
//string Path = ConstructPath(UninstallDir);
_path = ConstructPath(UninstallDir);
if (_path.Length > 0)
{
_Process.StartInfo.FileName = _path;
_Process.StartInfo.UseShellExecute = false;
_Process.Start();
}
}
Try this approach:
Process p = new Process();
p.StartInfo.FileName = "msiexec.exe";
p.StartInfo.Arguments = "/x {F98C2FAC-6DFB-43AB-8B99-8F6907589021}/qn";
p.Start();
Refer to this link: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/msiexec.mspx?mfr=true
HTH.
The problem with your misexec.exe code is that running cmd.exe someprogram.exe doesn't start the program because cmd.exe doesn't execute arguments passed to it. But, you can tell it to by using the /C switch as seen here. In your case this should work:
_Process.StartInfo.FileName = Environment.SystemDirectory.ToString() + "\\cmd.exe";
_Process.StartInfo.Arguments = "/C " + Environment.SystemDirectory.ToString() + "\\" + UninstallDir;
Where all I did was add /C (with a space after) to the beginning of the arguments. I don't know how to get your rundll32.exe code to work, however.
Your solution looks good, but keep a space before \qn:
p.StartInfo.Arguments = "/x {F98C2FAC-6DFB-43AB-8B99-8F6907589021} /qn";
Otherwise it wont work in silent mode.

How to call ffmpeg.exe to convert audio files on Windows Azure?

I run a Web Role on Windows Azure to receive AAC audio files (uploaded by base64 string) and store them into blob. it works fine by now.
Next, I also have to convert them into MP3 and store the MP3s into blob too. I decided to use something like ffmpeg.exe -i path.aac path.mp3.
The problems are that:
How to call external ffmpeg.exe inside a web service of a web role?
what would be the path?
Please help me if you know. Thank you in advance.
I suggest that you use a Local Storage Resource for your webrole where you can download the AAC files from the blob storage, and have them converted to MP3. Then upload back to blob storage.
Side note is that you can also use the Path.GetTempFileName() to get a temporary file name for your AAC / MP3 files, but I don't encourage to do so (even if I've done it before).
As for the actuall ffmpeg running, you might want to browse the code for AzureVideoConv, which I've built some time ago. You will find a lot of useful code there.
Here is a sample of the actual ffmpeg call (note that I download the exe from a blob storage, to avoid bloating my azure package with external exe files, and to easily update the ffmpeg.exe when required):
internal void ConvertFile(string inputFileName, Guid taskID)
{
string tmpName = string.Format(
"{0}\\{1}.flv",
Path.GetTempPath(), inputFileName.Substring(inputFileName.LastIndexOf("\\")+1));
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = this._processorExecutable;
psi.Arguments = string.Format(#"-i ""{0}"" -y ""{1}""", inputFileName, tmpName);
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(psi))
{
exeProcess.PriorityClass = ProcessPriorityClass.High;
string outString = string.Empty;
// use ansynchronous reading for at least one of the streams
// to avoid deadlock
exeProcess.OutputDataReceived += (s, e) => {
outString += e.Data;
};
exeProcess.BeginOutputReadLine();
// now read the StandardError stream to the end
// this will cause our main thread to wait for the
// stream to close (which is when ffmpeg quits)
string errString = exeProcess.StandardError.ReadToEnd();
Trace.WriteLine(outString);
Trace.TraceError(errString);
byte[] fileBytes = File.ReadAllBytes(tmpName);
if (fileBytes.Length > 0)
{
this._sSystem.SaveOutputFile(
fileBytes,
tmpName.Substring(tmpName.LastIndexOf("\\")+1),
taskID
);
}
}
}
catch (Exception e)
{
Trace.TraceError(e.Message);
}
}
NOTE the last check in of the project is using Windows Azure SDK 1.3
Thank you a lot #astaykov. You did a good job. Though It's not specific for my case(I need a specific piece of code instead of a whole large project), but it really inspired me. For specifying into my case, I am going to answer this question by my own - note that I did this based on #astaykov's code with somewhere directly copy&paste.
Firstly, configure the role with a Local Storage Resource. Then get its path by these code:
LocalResource converter_path =
RoleEnvironment.GetLocalResource("AudioConvertSpace");
string rootPathName = converter_path.RootPath;
get the path of ffmpeg.exe, xxx.aac and xxx.mp3 in the local storage:
string aac_path = rootPathName + "\\" + "fmwa-" + guidguid + ".aac";
string mp3_path = rootPathName + "\\" + "fmwa-" + guidguid + ".mp3";
string exe_path = rootPathName + "\\" + "ffmpeg.exe";
write the .aac file to local storage:
System.IO.File.WriteAllBytes(aac_path, decoded_audio_byte_array);
keep in mind that the local storage is not guaranteed to be stable or durable, so check the existence of the ffmpeg.exe -- if it doesn't exist, download it from blob.
if (System.IO.File.Exists(exe_path) == false)
{
var exeblob = _BlobContainer.GetBlobReference("ffmpeg.exe");
exeblob.DownloadToFile(exe_path, null);
}
initial and run the ffmpeg.exe process:
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = exe_path;
psi.Arguments = string.Format(#"-i ""{0}"" -y ""{1}""",
aac_path, mp3_path);
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
Process exeProcess = Process.Start(psi);
exeProcess.PriorityClass = ProcessPriorityClass.High;
string outString = string.Empty;
exeProcess.OutputDataReceived += (s, e) => {
outString += e.Data;
};
exeProcess.BeginOutputReadLine();
string errString = exeProcess.StandardError.ReadToEnd();
Trace.WriteLine(outString);
Trace.TraceError(errString);
exeProcess.WaitForExit();
upload the output of ffmpeg.exe into the blob storage:
byte[] mp3_audio_byte_array = System.IO.File.ReadAllBytes(mp3_path);
var mp3blob = _BlobContainer.GetBlobReference("fmwa-"+guidguid+".mp3");
mp3blob.Properties.ContentType = "audio/mp3";
mp3blob.UploadByteArray(mp3_audio_byte_array);
clean the temp files:
System.IO.File.Delete(aac_path);
System.IO.File.Delete(mp3_path);

Categories