Invoking a program from command shell from SQL CLR - c#

I'm invoking a CLR from SQL to prepare data for ingestion via BULK INSERT. One of the things I need to be able to do is unzip a file. First, I'm just trying simple stuff ... copying a file. Can't even get that to work.
For example:
string command = "/C COPY /Y err.txt y.txt";
System.Diagnostics.Process.Start("cmd.exe", command);
returns error "System.Security.SecurityException: Request failed."
So that's a little too complicated, I guess. So I try this:
System.Diagnostics.Process process = new System.Diagnostics.Process();
I get the same error message, even though I haven't done anything yet, except create a process that I'm even invoking. I have the assembly set to EXTERNAL_ACCESS on the SQL side.
What am I missing?

Related

Executing a batch file from .net application fails in a certain circumstance

This ticket is not a duplicate of this popular question since the solution there does not fix the problem. Rather I think it has to do with calling a file that's residing in the %WINDIR%\System32 directory, because calling a batch file with anything else seems to work.
I have a batch file with the the following contents:
telnet 10.147.36.20 11211
pause
I kick it off by executing the following code:
var psi = new ProcessStartInfo(entry.ExecutablePath);
Process.Start(psi);
I get the following:
'telnet' is not recognized as an internal or external command,
operable program or batch file.
even though if I execute telnet 10.147.36.20 11211 from the command line, it works perfectly fine.
I've tried telnet.exe, c:\windows\system32\telnet.exe, start telnet.exe and other variations, but nothing seems to work.
What am I missing?
When you are calling:
ProcessStartInfo(entry.ExecutablePath);
it looks wrong. You're passing in a path without the executable name.
Try:
FileInfo oFileInfo = new FileInfo(entry);
ProcessStartInfo psi = new ProcessStartInfo(oFileInfo.FullName);

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.

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 ...

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.

Run a DOS command in .NET

I have a set of commands like:
C:
cd Project
testproj.exe
My system gets these commands one by one from a remote system.
I need to execute each command in cmd.exe on receiving the command from the remote system. How to execute these using .NET?
I also need to return the result of testproj.exe to the remote machine. How to take the result after running command?
Process.Start cmd.exe, and hook StandardIn, StandardOut, and StandardError. Then, when a command comes in, just write it to StandardIn and read StandardOut/Error for the return. The whole thing shouldn't be more than 15 LOC.
That being said, just installing the Telnet Server would probably be easier - as it sounds like that's what you're essentially replicating....
var process = System.Diagnostics.Process.Start( "testproj.exe" );
process.WaitForExit();
var result = process.ExitCode;
This won't really honor things like "C:" or "CD path". Instead you'd want to create a batch file in a temporary folder then call the batch file.
Take a look at System.Diagnostics.Process. You can redirect stdout/stderr somewhere to get the output.
The C: and cd Project operations can be done inside the lanching application using the Directory class using the SetCurrentDirectory method.
Then just use the Process class to launch the testproj.exe executable.
Instead of trying to support all the commands of DOS, just have a small subset implemented which will guarantee nothing can go wrong. Like Don't allow DELETE, RD, FORMAT etc.
So, basically you would only have a subset of DOS commands. Once you have the command set, you can code for those specific commands using a extension mechanisms or as pluggable modules.
This will also helps you safe guard your machine from malicious attacks and worst to happen is there could be data sent out but from machine, the data / system can never be harmed.
UPDATE: The implementaion of specific commands is left to you. You could use .NET API or have System.Diagnostics.Process

Categories

Resources