I am working with the WMI API for c# in order to connect to a remote server and execute some commands. I have successfully established a connection. All I need now is to redirect the output of the remote CMD into a log file in my local machine.
Here is my code :
ConnectionOptions options = new ConnectionOptions();
options.Username = "login";
options.Password = "password";
ManagementScope scope = new ManagementScope("\\\\myserver\\root\\cimv2", options);
scope.Options.EnablePrivileges = true;
scope.Options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
try
{
scope.Connect();
System.Management.ManagementClass local_ClassInstance = new System.Management.ManagementClass(scope, new System.Management.ManagementPath("Win32_Process"), null);
Console.WriteLine("SUCCESS");
//execute the command
System.Management.ManagementBaseObject local_InParams = local_ClassInstance.GetMethodParameters("Create");
local_InParams["CommandLine"] = #"cmd.exe /C myCommand";
local_InParams["CurrentDirectory"] = #"mypath";
System.Management.ManagementBaseObject local_ManagementBaseObject = local_ClassInstance.InvokeMethod("Create", local_InParams, null);
}
catch (Exception e)
{
Console.WriteLine("FAILURE"+e.ToString());
}
Edit
I tried to accomplish this by using the '>' primitive :
local_InParams["CommandLine"] = "command > log.txt";
But the output file that I created doesn't contain anything.
I tried also to do this using a process
Process myProcess = new Process();
myProcess.StartInfo.FileName = "ipconfig";
myProcess.StartInfo.Arguments = "/all";
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.Start();
myProcess.WaitForExit();
string myResult = myProcess.StandardOutput.ReadToEnd();
Console.WriteLine(myResult);
myProcess.Close();
But the process does not return the information that I want because I want the output of cmd of the remote machine (Because I want the log of the behaviour of the server while running the command).
Any Help please ?
I too had an issue with capturing, and found ANOTHER redirect that works similar to what you have...
myProcess.StartInfo.RedirectStandardError = true;
// trap normal data received AND any ERROR data received too
myProcess.OutputDataReceived += DOSOutputResultsHandler;
myProcess.ErrorDataReceived += DOSOutputErrorsHandler;
I also have two string builder properties for capturing the output responses on my class that does the DOS Call process
StringBuilder DOSOutputResults = new StringBuilder();
StringBuilder DOSOutputErrors = new StringBuilder();
protected void DOSOutputResultsHandler(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (!string.IsNullOrEmpty(outLine.Data))
// track data into the NORMAL output string builder
DOSOutputResults.Append(Environment.NewLine + outLine.Data);
}
protected void DOSOutputErrorsHandler(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
// track data into the ERROR output string builder
DOSOutputErrors.Append(Environment.NewLine + outLine.Data);
}
Additionally, for using the primitive ">" redirection, there is also a "2>" redirection that handles errors not redirected to normal output. I found this out when dealing with DOS calls to Java.
Related
I am using this link => How to test the `Mosquitto` server? . for communicating data between two command prompt. it is worked perfectly.
Now I am using windows application for communication between device and server. i am using the reference https://gist.github.com/cwschroeder/7b5117dca561c01def041e7d4c6d2771
I am using the code in command prompt for subscribe is given below
mosquitto_sub -v -t 'test/topic'
Iam using the following code to publish(mqtt)
public Form1()
{
InitializeComponent();
// string BrokerAddress = "test.mosquitto.org";
string BrokerAddress = "localhost";
client = new MqttClient(BrokerAddress);
// register a callback-function (we have to implement, see below) which is called by the library when a message was received
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
// use a unique id as client id, each time we start the application
clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
}
private void btnPublish_Click(object sender, EventArgs e)
{
if (txtTopicPublish.Text != "")
{
// whole topic
string Topic = "/ElektorMyJourneyIoT/" + txtTopicPublish.Text + "/test";
MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, true);
// publish a message with QoS 2
client.Publish(Topic, Encoding.UTF8.GetBytes(txtPublish.Text), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, true);
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine("mosquitto_pub -t 'test/topic' -m 'xyz' ");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
//cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
//Console.ReadKey();
}
else
{
MessageBox.Show("You have to enter a topic to publish!");
}
}
From the above code, you can see manually written commands for passing commands to command prompt. which is cmd.StandardInput.WriteLine("mosquitto_pub -t 'test/topic' -m 'xyz' ");
I need to publish message without manual code. need to write publish through .net.
When users click on a button, I want it to run the logon script(launching from server), but each computer in different servers, so I get the server name. But the netlogon.StartInfo.Arguments = slnres + #"/c \netlogon\logon.cmd"; line is not working as it should be. It should run the logon.cmd on the PC(mapping network drivers, printers, etc), and then the CMD should close.
private void MapNetwork_Click(object sender, EventArgs e)
{
Process sln = new Process();
sln.StartInfo.UseShellExecute = false;
sln.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
sln.StartInfo.FileName = "cmd.exe";
sln.StartInfo.Arguments = "/c echo %logonserver%";
sln.StartInfo.RedirectStandardOutput = true;
sln.Start();
string slnres = sln.StandardOutput.ReadToEnd();
label1.Text = slnres;
Process netlogon = new Process();
netlogon.StartInfo.UseShellExecute = false;
netlogon.StartInfo.FileName = "cmd.exe";
netlogon.StartInfo.Arguments = slnres + #"/c \netlogon\logon.cmd";
netlogon.Start();
}
A couple things:
You don't need to run a command prompt to get an environment variable. You can use Environment.GetEnvironmentVariable.
Your Arguments property for your call to logon.cmd is being constructed into this:
\\myserver/c \netlogon\logon.cmd
When I think you want this:
/c \\myserver\netlogon\logon.cmd
So make sure you put slnres at the right place in your string. Your code should look like this:
private void MapNetwork_Click(object sender, EventArgs e)
{
string slnres = Environment.GetEnvironmentVariable("logonserver");
label1.Text = slnres;
Process netlogon = new Process();
netlogon.StartInfo.UseShellExecute = false;
netlogon.StartInfo.FileName = "cmd.exe";
netlogon.StartInfo.Arguments = "/c " + slnres + #"\netlogon\logon.cmd";
netlogon.Start();
}
i am a little confused about your question and i am not rly sure if i understand you correctly. some time ago i made a program where i had to run few powershell commands, so i made a class for it. redirected to your button it would look like that:
(and remember you need the fqdn to your file location => Reading File From Network Location)
using System.Diagnostics;
//class lvl scope vars
string output;
string ErrorOutput;
private void MapNetwork_Click(object sender, EventArgs e)
{
//define process arguments
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"cmd.exe";
startInfo.Arguments = #"FQDN path to your file on the server; exit";
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
//start process
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
//outpunt handling
if (string.IsNullOrEmpty(ErrorOutput))
{
return output;
}
else
{
return ErrorOutput;
}
}
first of all i would check if your application is able to open the file one the shared network location. (server available? access rights to server? serer mapped?)
after that you can check if he is able to start the file locally. (does it need admin rights to run the *.cmd, *.bat file)
now you can check if your application runs it correctly.
I want to create a desktop application like command prompt. in that application, I get input from a textbox and put the real-time output on rich-textbox.
but some of commands need to wait for complete execute like "composer install" (that will downloading required resources that's why taking long time and it's also displaying process status of downloading in percentage)
So my main question is how can i do something like command prompt that can give dynamic output with light weight no hanging if any other language instead of c# can do that then suggest me.
my desktop application look like this.
and c# "Run" button on click event method is as following.
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.Text = "";
if (textBox1.Text != null)
{
ProcessStartInfo info = new ProcessStartInfo("cmd", "/c " + textBox1.Text);
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.CreateNoWindow = true;
StringBuilder outputBuilder = new StringBuilder();
StringBuilder errorBuilder = new StringBuilder();
Process process = new Process();
process.StartInfo = info;
process.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler);
process.Start();
process.BeginErrorReadLine(); // do this after process.Start()
process.BeginOutputReadLine();
process.WaitForExit();
}
}
private void SortOutputHandler(object sendingProcess,DataReceivedEventArgs outLine)
{
StringBuilder sortOutput = new StringBuilder("");
if (richTextBox1.InvokeRequired) { richTextBox1.BeginInvoke(new DataReceivedEventHandler(SortOutputHandler), new[] { sendingProcess, outLine }); }
else
{
sortOutput.Append(Environment.NewLine + outLine.Data);
richTextBox1.AppendText(sortOutput.ToString());
richTextBox1.ScrollToCaret();
}
}
my code is completely works but application is hanging until command is executed completely while run dynamic commands like "composer install"
I'm trying to write a C# wrapper for Iperf server. After Iperf client is done with packet sending, the C# server application should dump the output data to the text file.
The problem is that this process (server) never exits, so it doesn't dump any data to the txt file. However, when I manually close the cmd window that runs iperf server, the text file is written with data (process exits). But this is clearly not the solution I'm looking for.
Any suggestions how can I write the data directly into the file, w/o need of manually closing the iperf server cmd window?
This is my code:
private void button1_Click(object sender, EventArgs e)
{
string commandline_server = " -s -u -i 1";
try
{
process = new Process();
process.StartInfo.FileName = "iperf.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
//process.StartInfo.RedirectStandardError = true;
process.StartInfo.Arguments = commandline_server;
process.StartInfo.CreateNoWindow = false;
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(process_Exited);
process.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
void process_Exited(object sender, EventArgs e)
{
//throw new NotImplementedException();
string outfile = process.StandardOutput.ReadToEnd();
System.IO.File.WriteAllText("test.txt", outfile);
}
Instead of shelling out to a terminal, have you considered using their API? iperf3 introduced "libiperf".
There are example C-programs in their source code tree.
I am trying to execute a process exactly as if it were executed on the window's command line but the process class won't allow the executable to create a file similar to what it would do if it were run from the command line. The Processes will when deployed run asynchronously on a server at timed intervals. The command line would calls would look like this:
curl.exe url -o data
wgrib2.exe data -csv output.csv
In the code below I found a workaround for curl.exe but when it is read as StandardOutput the file cuts off some of the critical stopping characters for this file type.
public static void httpQuery(string queryString)
{
Process myProcess = new Process();
try
{
string basepath = AppDomain.CurrentDomain.BaseDirectory;
myProcess.StartInfo.UseShellExecute = false; // allows us to redirect the output
myProcess.StartInfo.CreateNoWindow = true; // stop's command window from being made
myProcess.StartInfo.Verb = "runas";
myProcess.StartInfo.FileName = #"C:\Users\Ian's\Desktop\wgrib2\curl.exe";
myProcess.StartInfo.Arguments = queryString; // queryString is http://nomads.noaa.gov/....
myProcess.StartInfo.RedirectStandardError = true; // redirect error to stream reader
myProcess.StartInfo.RedirectStandardOutput = true; // redirect output to strem reader
myProcess.Start();
if (myProcess.WaitForExit(10000) == false)
{
myProcess.Kill();
}
using(StreamReader reader = myProcess.StandardError) // capture error output if any
{
string result = reader.ReadToEnd();
reader.Close();
StreamReader message = myProcess.StandardOutput;
string output = message.ReadToEnd();
StreamWriter writer = new StreamWriter(basepath + "wgrib2\\data");
writer.Write(output);
writer.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
myProcess.Close();
}
Additionally, I cannot seem to find a way to allow the second process to write a new file, or if it has been I cannot find the directory that it is writing to. I am working with VS2012 on the IIS development server. This is the second processes code.
public static void callWgrib2()
{
Process wgrib2 = new Process();
try
{
// call on command line: wgrib2.exe data -csv data.csv
string basepath = AppDomain.CurrentDomain.BaseDirectory; // path to project directory
string arg1 = basepath + "wgrib2\\data"; // filename of operate on
string arg2 =" -csv " + basepath + "wgrib2\\data.csv"; // filename to write to
wgrib2.StartInfo.UseShellExecute = false; // parameters
wgrib2.StartInfo.CreateNoWindow = true;
wgrib2.StartInfo.Verb = "runas";
wgrib2.StartInfo.FileName = #"C:\Users\Ian's\Desktop\wgrib2\wgrib2.exe";
wgrib2.StartInfo.Arguments = "\""+ arg1 + arg2 + "\"";
wgrib2.StartInfo.RedirectStandardError = true;
wgrib2.Start();
if (wgrib2.WaitForExit(10000) == false)
{
wgrib2.Kill();
}
using (StreamReader reader = wgrib2.StandardOutput)
{
string result = reader.ReadToEnd();
reader.Close();
StreamReader err = wgrib2.StandardError;
err.ReadToEnd();
err.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
wgrib2.Close();
}
Can someone point me in the write direction I have put considerable effort into this problem but I'm sure there exits a simple workaround I'm not aware of.
If you want to use the actual command line process, you can use cmd and pass the /c flag to it in the arguements
also, the line
wgrib2.StartInfo.Arguments = "\""+ arg1 + arg2 + "\"";
looks odd
do you really need all your arguments such as -csv to be in the same quotes block?
it's like calling on the command line
C:\Users\Ian's\Desktop\wgrib2\wgrib2.exe "c:\base\wgrib2\data -csv c:\base\wgrib2\data.csv"