psexec via Process gives different exitcode than psexec via cmd - c#

I'm currently working on an application that checks whether a APP with a certain name exist on an IIS server. I use PsExec to execute this command.
While I was testing this through the command line, I noticed that when an APP does not exist the appcmd exits with ExitCode 1. Likewise it exits with 0 when an APP does exist.
I wanted to use this behavior too so I don't need to do output redirection. I only care about whether the APP exists or not. PsExec uses the exitcode of the command it calls as its own exitcode. I tried this with the command line and checked the result with echo %errorlevel% and it works just fine.
But I run into a problem with the following code.
Process process = new Process();
process.StartInfo.FileName = #"psexec";
string appcmd = #"C:\windows\system32\inetsrv\appcmd";
process.StartInfo.Arguments = String.Format(#"{0} -u {1} -p {2} -S {3} LIST APP ""{4}""",
ip, username, password, appcmd, appname);
process.Start();
process.WaitForExit();
Console.WriteLine(process.ExitCode);
This executes just fine. But it does not return the exitcode that PsExec (should?) gives. It always returns 0. So now I can't use the trick I found earlier to check whether an APP exists or not.
I there a known solution for this? Is there a similar solution? Or should I go with output redirection?

Not really a solution to the problem. But because web applications in IIS must have a unique name, creating an application that already exists will result in an error but nothing will have changed.
This means that it works perfectly fine if I always try to create a new APP. If it doesn't exist it will be made, if it already exists nothing will happen.

Related

C#0 net use connection

So I am having issues with the "net use" command in C#. Basically, I am using the code written here. The code works great, however I have multiple ids that need to be used sequentially. Unfortunately, when trying to connect to another ID, the connection remains in "net use " in Windows, so this exception is thrown:
Win32Exception: Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed.
Now to me, the obvious thing would be to execute the command prompt programmatically to delete the connection when I am done using it. Here is the code that I am running to delete the connection:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/K net use delete \\IPAddrofserver";
process.StartInfo = startInfo;
process.Start();
I only use /k so I can see if the command works. After this code executes, it says "The network connection cannot be found." However, if I manually open the start menu, and type net use, I can see and delete the connection. I think this may be related to the fact that when running the command prompt programmatically, I notice its being given administrative privilege as opposed to running it under my user token, but I cannot be sure. Any help regarding this would be greatly appreciated.
EDIT: Adding in the command prompt deletion code during the WnetCancelConnection2 actually operates correctly, and deletes the connection from net use. However, checking net use manually outside of the program reveals that the history of the connection still exists and is open. Whoami command reveals the same user. Any reason why there is a discrepancy between what happens programmatically and what happens when I check manually?
You probably need to start your process with elevated privileges. See the accepted answer here for how to do this. You could also choose to call the relevant Windows API directly, to avoid spawning other processes and dealing with those complications.

Scheduler - C# App - Batch - FTP - Works Manually But Not In Schedulers

I have a C# app which executes a batch script, which writes ftp commands to a text file and then executes the text file. It works when executed manually, but not when executed from schedulers such as Windows Task Scheduler (not the one I'll ultimately be using but am using for debugging purposes).
Specifically, when run from the scheduler, the script executes, but the parameters don't get passed, and the ftp script file is not overwritten before it is called, so it only executes whatever script was left from the previous job. It does, however, overwrite the .txt reports that record the ftp session, as intended. Again, when run manually, it all works.
Security policies prevent much tinkering with permissions, but I gave the job account full permissions on all affected folders, and added "log on as batch file" rights to the job account. No parameters need to be passed to the C# application. Any suggestions would be appreciated.
C# Code:
ProcessStartInfo psi = new ProcessStartInfo(scriptFile, paramList);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
Process p = Process.Start(psi);
//etc...
Batch Script:
Set DIR=%~1
Set SUBDIR=%~2
Set SWITCH=%~3
cd "%DIR%Scripts\
ECHO USER user>FtpScript.txt
ECHO pass>>FtpScript.txt
ECHO lcd "%DIR%FilesToFtp\%SUBDIR%\%SWITCH%">>FtpScript.txt
ECHO lcd "%DIR%FilesToFtp\%SUBDIR%\%SWITCH%"\>>FtpScript.txt
IF "%SWITCH%"=="ONE" ECHO QUOTE SITE LRECL=100 RECFM=FB>>FtpScript.txt
IF "%SWITCH%"=="TWO" ECHO QUOTE SITE LRECL=200 RECFM=FB>>FtpScript.txt
IF "%SWITCH%"=="THREE" ECHO QUOTE SITE LRECL=300 RECFM=FB>>FtpScript.txt
ECHO MPUT "*.*">>FtpScript.txt
ECHO(>>FtpScript.txt
REM other commands, etc...
FTP -d -n -s:"%DIR%Scripts\FtpScript.txt" server > "%FPATH%Reports\%SUBDIR%_%SWITCH%_log.txt"
EXIT 0
Thanks in advance.

Running Bash Commands from C#

I am trying to figure out how to run a bash command from C# running on IIS 7/.Net 4.5.
I've been searching the web and a lot of answers presume you have certain things installed/in place.
I already have Git 1.9.4.msysgit.2 installed with Git Bash and Git Giu. I'm looking for some help as to what else I need installed to run even the simplest of bash commands. And how to run it.
I've looked at posts like bash pipes - I am trying to call script from c# but that uses cygwin. Can I do the same without it and if so, how do I go about it?
Goal
If what I'm asking above doesn't make sense or seems to ask separate questions, here my ultimate goal. I'm trying to write my own server-side git hook. When a developer pushes their commits to our GitHub repo, I want GitHub to call our callback url. I want my callback url to run a git pull command to update our staging server with what was just pushed.
I got to this question based on a previous question I asked at GitHub - setup auto deployment with remote server. based on answers there I'm trying to run a simple command, either but hard coding the command, or putting it in a script and running it, e.g.: cd $REPO_DIR && git pull origin $branch_name.
I am aware of Jenkins and other software, but I want to perform these commands myself vs. installing another software.
If further information is needed please feel free to ask.
Update 1
So based on a few answers below I've come up with the following
using System.Diagnostics;
Process process = new Process();
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.FileName = #"C:\Program Files (x86)\Git\bin\bash.exe";
processStartInfo.WorkingDirectory = #"C:\myrepo\mysite";
processStartInfo.Arguments = "git status";
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
process.StartInfo = processStartInfo;
process.Start();
String error = process.StandardError.ReadToEnd();
String output = process.StandardOutput.ReadToEnd();
ViewBag.Error = error;
ViewBag.Ouput = output;
With the code above I am getting "C:/Program Files (x86)/Git/bin/bash.exe": git: No such file or directory. I know the exe is there. What's am I doing wrong?
Update 2
As per #SurgeonofDeath comment I followed this post http://blog.countableset.ch/2012/06/07/adding-git-to-windows-7-path/ and added the paths of Git to my environmental variables. However I still am getting the same issues. Any ideas?
Thanks.
Instead of calling the bash.exe, simply call git and pass the status as argument:
processStartInfo.FileName = "git";
processStartInfo.Arguments = "status";
perhaps i misunderstood your question but what about execve?
here is an excerpt of it's man page.
NAME
execve - execute program
SYNOPSIS
#include <unistd.h>
int execve(const char *filename, char *const argv[],
char *const envp[]);
DESCRIPTION
execve() executes the program pointed to by filename. filename must > be
either a binary executable, or a script starting with a line of > the
form:
#! interpreter [optional-arg]
Check your PATH environment variable and update it
C:/Program Files (x86)/Git/bin/bash.exe": git: No such file or directory
means that it's git which is not found by bash.
1. Check the PATH environment variable in bash (which is and should remain different from Windows one)
Adjust this
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
to make the terminal visible.
In the terminal you will create with the Process.Start()
Type:
echo ${PATH}
2. Update your path
You could update the global path of windows (which requires a restart)
You could update the user path of windows (which should require a logoff, but I'm not sure).
You just set Path to what you like with System.Environment.SetEnvironmentVariable before starting the Process
Additional note:
If you have like me several versions of bash, command interpreters, git and so on, it could be really messy if you try to concatenate all the paths and hope to find the ideal order. You could see some weird behavior of you beloved commands until you realize it's not the one you intend to run ... think of FIND.exe... And I didn't even think of the user-friendly interface of windows to edit environment variables ...

Capturing Plink output in C#

I am trying to use Plink to access information on a machine. I followed this tutorial:
http://www.mindfiresolutions.com/Creating-a-SSH-connection-using-plink-PuTTY-via-C-application-1760.ph
So far I am only using my program to just open up Plink, and I will be adding in the login information and such once I can at least get Plink to be openable in my program. I have this based on the tutorial:
ProcessStartInfo psi = new ProcessStartInfo(#"C:\Windows\System32\cmd");
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
psi.CreateNoWindow = false;
Process process = Process.Start(psi);
Thread.Sleep(3000);
string cmdForTunnel = "plink";
process.StandardInput.WriteLine(cmdForTunnel);
process.WaitForExit();
Thread.Sleep(10000);
//DoBusinessLogic();
process.StandardInput.WriteLine("logout");
Thread.Sleep(10000);
if (process.HasExited)
{
process.Close();
process.Dispose();
}
But nothing is displayed, which bothers me. The command plink is supposed to display the help information on how to use the program (I will be replacing the command with something more useful later), but the command prompt remains empty. I also experimented by replacing plink with ipconfig, which also displayed nothing.
I know how to open up cmd myself and type in plink to access it. I want to replicate this action in my program.
You have many faults in your code:
You are redirecting an output, and you are not reading/processing/printing it (that's why "nothing is displayed")
Running plink by "typing" plink to cmd.exe is insane. You can run plink directly, avoiding cmd.exe completely (and even if you needed to use the cmd.exe, you should pass plink.exe to it on a command-line: /c path\plink.exe). And no, running it directly would not cause Plink to close instantly.
Calling WaitForExit() without reading the redirected output will deadlock your code once an output buffer fills. See Remarks section for ProcessStartInfo.RedirectStandardOutput. Alternatively, use process.StandardOutput.ReadToEnd() (it's like WaitForExit, but also reads the output). It's actually what the MSDN recommends in the previous link.
If you are going to execute one command only, using Plink, it's also better to pass the command on Plink command-line, rather than "typing" it to its (redirected) input:
plink.exe -ssh user#host command
See also answer to Testing using Plink.exe to connect to SSH in C#

Process.Start() does nothing

I have to start a VPN connection (Fortinet) by code.
I have a cmd file that establish the connection.
If I call the cmd file on the shell it works pretty fine.
When I call it via Process.Start it does nothing.
It doesn't throw any exception, it seems to execute but VPN does not connect.
On the standard output I can read the echo I put on the cmd file (so it is executing the right file).
I launched a ping -d to see when the vpn goes up, when I call it via shell it goes up in a few seconds, via C# it is not.
I also tried a sleep(30000) but nothing.
My cmd (ConnectFile.cmd):
#echo off
#echo Connecting to VPN
"C:\Program Files (x86)\Fortinet\SslvpnClient\FortiSSLVPNclient.exe" connect -s "vpn myvpn"
My code (connectFile and disconnectFile are strings that contain the full path of the cmd files):
try
{
var startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = connectFile;
startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(connectFile) ?? "";
System.Diagnostics.Process process = System.Diagnostics.Process.Start(startInfo);
System.Threading.Thread.Sleep(30000);
base.GetFiles(folder);
}
finally
{
System.Diagnostics.Process.Start(disconnectFile);
}
You have to separate the parameters. FileName is for the exe file, not the whole shell command (you're explicitly saying not to use the shell). So put the parameters to the Arguments property in ProcessStartInfo.
In your case, the parameters should be:
FileName - C:\Program Files (x86)\Fortinet\SslvpnClient\FortiSSLVPNclient.exe (no quotes)
Arguments - connect -s "vpn myvpn" (again, no quoting)
Second, you have to read the standard output if you capture it. If the output buffer gets full before you read it, the called process will stop working - it has to wait for the buffer to be emptied. If you're sure the application will actually finish at some point, simply remove the Thread.Sleep and call ReadToEnd right away. Otherwise, use eg. asynchronous reading to get the data.
Also, it's usually a good idea to set WorkingDirectory. Even if the application doesn't need any data from the working directory, it's safer, since only admins can change Program Files - this helps against DLL inject hacks.

Categories

Resources