I have the following code for converting xml to csv by using perl script. When I run the perl script through c# but there is no files are created and string output become empty.
What is the problem?
I have the perl script with .txt extention, Is this ok or not?
string filePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/Files/SAVVIS_CDR_1806012231.XML";
if (Path.GetExtension(filePath) != "csv")
{
ProcessStartInfo perlStartInfo = new ProcessStartInfo(#"C:\Strawberry\perl\bin\perl.exe");
string perlScriptFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/formatter_savvis.pl.txt";
string csvFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/";
perlStartInfo.Arguments = perlScriptFilePath + " " + filePath + " " + csvFilePath;
perlStartInfo.UseShellExecute = false;
perlStartInfo.RedirectStandardOutput = true;
perlStartInfo.RedirectStandardError = true;
perlStartInfo.CreateNoWindow = false;
Process perl = new Process();
perl.StartInfo = perlStartInfo;
perl.Start();
perl.WaitForExit();
string output = perl.StandardOutput.ReadToEnd();
}
Could you please anyone help me to solve this problem?
Thanks in advance.
First, to find out what went wrong:
string error = perl.StandardError.ReadToEnd();
Also, make sure you have necessary permissions to create files in the output directory. You may try to run your process with Admin privileges to find out if it's a permission issue:
perlStartInfo.Verb = "runas";
You may want to run your entire host process with elevated permissions for this.
(This is only to figure out if it's a permission issue! If it's the case, grant the output directory the necessary permissions, and if possible don't automatically run scripts with admin privileges in production environment)
There also may be errors in the perl script itself.
Related
Plan
The plan is to disable and subsequently enable a device from inside a windows forms application. To test the first building block of my plan, I open cmd with admin privileges and the following works perfectly:
> devcon hwids =ports
> devcon hwids *VID_10C4*
> devcon disable *VID_10C4*
> devcon enable *VID_10C4*
I can see the device being disabled and enabled again in device manager.
I can also achieve all of this by putting the commands into a batch file and running it from cmd with admin privileges. The above tells me that my plan is essentially good.
Application
However, what I actually want to do is achieve the same thing from inside a windows forms application:
I've set the following in the app manifest:
requestedExecutionLevel level="requireAdministrator" uiAccess="false"
For the sake of baby steps, I have checked this, just to ensure that there are no stupid mistakes in paths and whatnot. And it works just fine. The log file shows me the expected output from the dir command.
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && dir " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
However, this does not work. It always returns an empty log file and does not change the device as expected:
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && devcon hwids =ports " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
Error from cmd window is :
'devcon' is not recognized as an internal or external command,
operable program or batch file.
What's going on?
The above has me stumped. I've proved the commands work. I've proved my C# code works. But when I join the 2 together, it doesn't work...
NB: My C# program is running on my D: drive, if that makes any difference...
Updates Based on Comments
#Compo
Using your code, it does exactly the same as with mine. I see an empty log file & no changes made to the device. I've altered the /c to /k so I can see what going on the cmd terminal and I see this:
I've even tried your code C:\\Windows\\System32\\devcon hwids =usb pointing directly at devcon. Also tried \devcon.exe for completeness. The inexplicable error is :
I can see the flipping devcon.exe file sitting right there in the folder! Is there any reason it would not recognise it?
Also, with the command as you wrote it, the log file name is actually named logFileEnablePrt.txt'. I agree that your command looks right, so don't ask me why this happens!
#Panagiotis Kanavos
using your code, I get the following error:
This is at the line p.Start();. I tried putting in devcon.exe, and even the whole path (I checked the folder was in my PATH, and it is). Can't get past this. I actually stumbled on that answer you shared and arrived at this brick wall already.
Here is the code works for me, I don't have ports devices so I change it to usb.
public static void Main()
{
string prodPath = #"c:\devcon\x64";
// Build String
string strCmdText =
"/c \"cd /d " + prodPath +
" && devcon hwids =usb " +
" > log.txt \"";
// Run command
var p = new Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
}
Worked through a few steps and think I may have an answer...
Just specifying devcon fails as expected...windows cant find the exe as the folder it is in is not in the %PATH% variable in windows..
IF I specify the full path however it works...
It wasnt clear from your original code but if your copy of devcon is sitting in either System32 or Syswow directories you may be hitting an emulation issue as well...see here....
EDIT1:: A way to prove this would be to do Direcory.GetFiles(directory containing devcon) and see if the results line up with what you expect
As for passing arguments through to devcon I'd try something like this as opposed to trying to concatenate one giant cmd line..
A similar example but with netstat:
EDIT 2::Another example but with devcon:
The target platform here for the build was x64
EDIT3::
With my application build set to x86:
After working through the answers and comments above, I seem to have something that reliably works, which obviously I'd like to share back for scrutiny and future use.
So, my function ended up looking like this:
private int enablePort(string action)
{
while (true)
{
// Command Arg
string devconPath = #"c:\Windows\SysNative";
string strCmdText =
"'/c \"cd /d \"" +
devconPath +
"\" && c:\\Windows\\SysNative\\devcon " + action + " *VID_10C4* " +
"> \"" + prodPath + "\\logs\\logFileEnablePrt.txt\"\"";
// Process
var p = new Process();
var psi = new ProcessStartInfo()
{
Arguments = strCmdText,
Verb = "runas",
FileName = "CMD.exe",
UseShellExecute = true
};
p.StartInfo = psi;
p.Start();
p.WaitForExit();
// Grab log output
string logPath = prodPath + "\\logs\\logFileEnablePrt.txt";
Console.WriteLine("logPath = " + logPath);
string tempFile = System.IO.File.ReadAllText(logPath);
System.Console.WriteLine("Contents of WriteText.txt = \n{0}", tempFile);
// Check if it worked
var success = false;
if (tempFile.Contains(action))
{
success = true;
return 0;
}
// Error -> Allow user to try again!
if (MessageBox.Show("Was unable to " + action + " Test Jig COM port. Unlug & Replug USB. Check COM port is enabled if not working.", "COM Port Problem", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return -1;
}
}
}
And the calling code was:
this.enablePort("disable");
int milliseconds = 3000;
await Task.Delay(milliseconds);
this.enablePort("enable");
As you can see in the code above, I've logged everything to see what was going on... Stepping through with the debugger, I can now see after the disable:
USB\VID_10C4&PID_EA60\0001 : Disabled
1 device(s) disabled.
And then after the enable:
USB\VID_10C4&PID_EA60\0001 : Enabled
1 device(s) are enabled.
The one extra thing I need to stress is that during testing, I thought I could hook a serial peripheral onto the port and determine whether it could disable and enable successfully by checking the connection. THIS DOES NOT WORK. The above code only works when the port is idle. Perhaps someone who understands the underlying software could hazard an explanation of why this is.
Im making an application which needs to monitor the filesystem using FileSystemWatcher, to detect how an installation affects the filesystem.
To get rid of noise i want to filter the events that are created by their creating user, and that code is working with the //BUILTIN //Administrator user, which is used by default when doing an installation. But still there are quite a bit of noise. Then i got the idea of creating a specific user that i can use for running the installation file, and filter on that specific user, and thereby getting rid of allmost all the noise.
this is my code for the process creation and start
private void executeInnoInstaller(string path, string fileName)
{
// Use ProcessStartInfo class
ProcessStartInfo installerProces = new ProcessStartInfo();
installerProces.CreateNoWindow = true;
installerProces.UseShellExecute = false;
installerProces.FileName = path + "\"" + fileName + "\"";
installerProces.WindowStyle = ProcessWindowStyle.Normal;
installerProces.UserName = "test";
System.Security.SecureString encPassword = new System.Security.SecureString();
foreach (System.Char c in "test")
{
encPassword.AppendChar(c);
}
encPassword.MakeReadOnly();
installerProces.Password = encPassword;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(installerProces))
{
exeProcess.WaitForExit();
//int exitCode = exeProcess.ExitCode;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
this code exits with a access denied.
OS=Windows
Ive already tried to run the installer.exe from the OS filehandler with SHIFT - Rightclick using the specified user, and it works.
VisualStudio is run as administrator.
Ive tried to run the build project exe file as administrator, but it does not work.
Without the user credentials, the code works and uses the //BUILTIN //Administrator account
Does anybody have any idea ?
Thank you beforehand for your time and effort.
This code works if i turn down the UAC securitylevel to the lowest.
I know that you can get the path to a mapped drive (e.g. Find UNC path of a network drive?), but what if the only thing I have is just the path to the shared folder?
For example, let's say I have a friend who is sharing the folder C:\MyDocs\PublicDoc over the network. I can access it under the path \\danas-pc\PublicDoc. Is there any way that I could, being on another computer, determine that \\danas-pc\PublicDoc actually maps to \\danas-pc\c$\MyDocs\PublicDoc?
I ask because I am given a path to a log file that has the path (e.g. \danas-pc\c$\MyDocs\PublicDoc\mylog.log )and I need to check if it matches the same path that is set in another location. The other location has the "short path" (e.g. \\danas-pc\PublicDoc\mylog.log ), and thus, even though the log paths lead to the same location, the program determines that they are different. I wanted to see if there's a way to figure out that they are pointing to the same location.
I can't imagine why you might need this since for the remote instance's full path is \danas-pc\PublicDoc but if you let your imagination thrive I'd suggest something like this:
(1) on the remote computer inside the share folder you can drop a small script that if executed return the full path. You have to search for appropriate coding for windows or linux environment also you need to have execution privilege or rights on it. for example on windows you can have a vbscrit or cscript and a .sh script in linux.
Also please note that seeing it from the remote host, in terms of the remote host the full path is \NAME-OR-IP\Path\to\Folder\or\File etc. For you on the remote connection that is the full path ;)
UPDATE:
as per the comment below, this is a full script that does the following
creates a vbscript with code in it to retrieve the current full path
copies the files into the network desired path
executes the vbscript and reads the result back
deletes the vbscript
Assuming: you have the read/write access on the network folder
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace GetNetworkFullPath
{
class Program
{
static void Main(string[] args)
{
var networkFolder = "\\\\REMOTE-PC-NAME\\SharedFolder";
var nameOfVBScript = "capturepath.vbs";
var vbsOutput = "";
//Get the name of the current directory
var currentDirectory = Directory.GetCurrentDirectory();
Console.WriteLine("Current Dir: " + currentDirectory);
//1. CREATE A VBSCRIPT TO OUTPUT THE PATH WHERE IT IS PRESENT
//Ref. https://stackoverflow.com/questions/2129327/how-to-get-the-fully-qualified-path-for-a-file-in-vbscript
var vbscriptToExecute = "Dim folderName \n" +
"folderName = \"\" \n" +
"Dim fso \n" +
"Set fso = CreateObject(\"Scripting.FileSystemObject\") \n" +
"Dim fullpath \n" +
"fullpath = fso.GetAbsolutePathName(folderName) \n" +
"WScript.Echo fullpath \n";
//Write that script into a file into the current directory
System.IO.File.WriteAllText(#""+ nameOfVBScript + "", vbscriptToExecute);
//2. COPY THE CREATED SCRIPT INTO THE NETWORK PATH
//Ref. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-copy-delete-and-move-files-and-folders
string sourceFile = System.IO.Path.Combine(currentDirectory, nameOfVBScript);
string destFile = System.IO.Path.Combine(networkFolder, nameOfVBScript);
System.IO.File.Copy(sourceFile, destFile, true);
//3. EXECUTE THAT SCRIPT AND READ THE OUTPUT
//Ref. https://stackoverflow.com/questions/27050195/how-do-i-get-the-output-from-my-vbscript-console-using-c
Process scriptProc = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = #"" + networkFolder + "";
info.FileName = "Cscript.exe";
info.Arguments = nameOfVBScript;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
scriptProc.StartInfo = info;
scriptProc.Start();
scriptProc.WaitForExit();
bool exit = false;
while (!scriptProc.StandardOutput.EndOfStream)
{
vbsOutput = scriptProc.StandardOutput.ReadLine();
}
Console.WriteLine("vbscript says: " + vbsOutput);
//4. DELETE THE FILE YOU JUST COPIED THERE
System.IO.File.Delete(#"" + networkFolder + "\\" + nameOfVBScript);
}
}
}
Unfortunately when executed remotely the script replies with the Network Path :( so disappointed...really sorry! As long as execution is happening from a user outside the remote system it will reply with the absolute path related to that instance. I think an internal process/user should execute the file and reply back with the answer to the application.
I'll try to think something more tomorrow and maybe reply back if I'm lucky.
I have an application that dumps a lot of files to a directory. I want to copy these files to a Hadoop cluster using the hadoop command. I use the following code to run the command.
System.Diagnostics.ProcessStartInfo export = new System.Diagnostics.ProcessStartInfo();
export.RedirectStandardOutput = false;
export.RedirectStandardError = false;
export.UseShellExecute = false;
export.WorkingDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
export.FileName = "hadoop";
export.Arguments = "fs -copyFromLocal " + Path.Combine(dumpDirectory, "*.txt") + " " + hadoopPath));
Console.WriteLine("Copying data: hadoop " + export.Arguments);
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(export);
proc.WaitForExit();
if (proc.ExitCode == 0)
{
IEnumerable<string> files = Directory.EnumerateFiles(dumpDirectory);
foreach (string file in files)
File.Delete(file);
}
else
Console.WriteLine("Error copying to Hadoop: " + proc.ExitCode);
The program writes the following message:
Copying data: hadoop fs -copyFromLocal local/directory/*.txt /user/remote/directory/
copyFromLocal: `local/directory/*.txt': No such file or directory
Error copying to Hadoop: 1
Interestingly, when I run the command manually, the files copy without error.
Also, if the program runs the command without using *.txt and instead calls the command for each file individually, the command succeeds.
Can anyone shed some light on this?
I partially resolved the problem by creating a bash script containing the given command. I ran the bash script programmatically and it worked.
However, I still do not know why the original did not work.
I have a jar file which I want to run from within C#.
Here's what I have so far:
clientProcess.StartInfo.FileName = #"java -jar C:\Users\Owner\Desktop\myJarFile.jar";
clientProcess.StartInfo.Arguments = "[Something]";
clientProcess.Start();
clientProcess.WaitForExit();
int exitCode = clientProcess.ExitCode;
Unfortunatly I get "System could not find specified file", which makes sense since its not a file its a command.
I've seen code online which tells you to use:
System.Diagnostics.Process.Start("java -jar myprog.jar");
However I need the return codes AND I need to wait for it to exit.
Thanks.
Finally solved it. The filename has to be java and the arguments has to contain the location of the jar file (and anything arguments you want to pass that)
System.Diagnostics.Process clientProcess = new Process();
clientProcess.StartInfo.FileName = "java";
clientProcess.StartInfo.Arguments = #"-jar "+ jarPath +" " + argumentsFortheJarFile;
clientProcess.Start();
clientProcess.WaitForExit();
int code = clientProcess.ExitCode;
You need to set environment variable Path of java.exe executable or specify the full path of java.exe.
ProcessStartInfo ps = new ProcessStartInfo(#"c:\Program Files\java\jdk1.7.0\bin\java.exe",#"-jar C:\Users\Owner\Desktop\myJarFile.jar");
Process.Start(ps);