Process myProcess = new Process();
ProcessStartInfo remoteAdmin =
new ProcessStartInfo(Environment.GetFolderPath(Environment.SpecialFolder.System) + #"\iisreset.exe /restart");
remoteAdmin.UserName = username;
remoteAdmin.Password = pwd;
remoteAdmin.Domain = domain;
myProcess.StartInfo = remoteAdmin;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.Start(); --- ERROR HERE
Can not find the file specified.
But when I try to run iisreset on the local machine by cmd it's working.
Unless I'm missing something, (Environment.GetFolderPath(Environment.SpecialFolder.System) will get back the local machine (Where the code is running) special folder. So it's expecting the file C:\Windows\System\iisreset.exe to be located on your machine. The only method I could see to get around this, is to drop the C:\ and instead add in the device's name \\DeviceName\C$\ and then the filepath. This is assuming the special folder system is located in the same place on your machine and the remote machine.
The only other method, to get the remote machines system directory is to get it via WMI or via a reg entry reading.
So if using WMI:
"SELECT * FROM Win32_OperatingSystem"
Once done, you would then need to build the folder string yourself from that.
There is no file called C:\Windows\System\iisreset.exe /restart (assuming that Environment.GetFolderPath(Environment.SpecialFolder.System) returns C:\Windows\System\
So you would want
ProcessStartInfo remoteAdmin =
new ProcessStartInfo(Environment.GetFolderPath(Environment.SpecialFolder.System) + "iisreset.exe");
remoteAdmin.Arguments = "/restart";
But Environment.GetFolderPath(Environment.SpecialFolder.System) probably returns something like C:\Windows\System (note no trailing slash), and there is definitely no file called c:\windows\systemiisreset.exe
So you would actually want
ProcessStartInfo remoteAdmin =
new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "iisreset.exe"));
remoteAdmin.Arguments = "/restart";
iisreset.exe supports remote calls, so instead of using WMI to get remote directory you can actually just do:
iisreset {servername}
Related
So been searching or the web but can't seem to find an answer that has helped me. I have been looking for almost a week now.
I created a program in vs, alongside with some batch files. The Batch files run great by themselves and through the debug/release when including them in the folder with the .exe.
My problem is I want to be able to ONLY have the .exe file from my release and it still work.
Is there a way i can build these files inside the .exe? I have tried using c# to write my console commands instead of including seperate batch files. But im pretty new to c# and i get nothing but errors with the commands i want to run/if i run to many lines.
I would much rather have just c# instead of including the batch files but that I can't seem to figure out a solution to either.
Any help would be appreciated.
This is me currently calling batch files which works just fine. Again, if there is a way to just write this in c# instead of calling a batch file I would be happy to learn.
Process process = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.CreateNoWindow = false;
psi.Verb = "runas";
psi.FileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"/" + "undo.bat";
psi.UseShellExecute = true;
process.StartInfo = psi;
_ = process.Start();
process.WaitForExit();
I'm starting CyberSecurity soon and am playing around with some Security stuff on my computer. Below is a sample code from my batch file to enable Security Protocols. If anything how would i write this in c#?
echo ...
echo Enabling Windows Firewall
netsh advfirewall set allprofiles state on
echo Enalbing HyperVisor
bcdedit /set hypervisorlaunchtype auto
echo Enabling UAC
%windir%\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /t REG_DWORD /d 1 /f
echo.
echo.
echo Your Computer will now be restarting for changes to take effect!
timeout 10
shutdown /r /t 001
What you can do is include the batchfiles as embedded resources in your project. Then read them and then execute them.
to include them as embedded resources example...
add them to your project.
right click and go to properties
select embedded resource
then to extract...
Write file from assembly resource stream to disk
you can then write the file to disk and create process on it. or there is a way to execute cmd.exe without writing the file to disk but this is a little complicated so the best way is to just write to disk.
Execute BATCH script in a programs memory
I followed the guide given above and a few others to get my solution to work. Embed the resource that's in your solution, then I used the following code to pretty much create the functions of being able to write it.
private static void Extract(string nameSpace, string outDirectory, string internalFilePath, string resourceName)
{
Assembly assembly = Assembly.GetCallingAssembly();
using (Stream s = assembly.GetManifestResourceStream(nameSpace + "." + (internalFilePath == "" ? "" : internalFilePath + ".") + resourceName))
using (BinaryReader r = new BinaryReader(s))
using (FileStream fs = new FileStream(outDirectory + "//" + resourceName, FileMode.OpenOrCreate))
using (BinaryWriter w = new BinaryWriter(fs))
w.Write(r.ReadBytes((int)s.Length));
}
Here is what I used to save, execute then delete the file.
Extract("nameSpace", "outDirectory", "internalFilePath", "resourceName");
Process process = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.CreateNoWindow = false;
psi.Verb = "runas";
psi.FileName = #"C:/" + "resourceName";
psi.UseShellExecute = true;
process.StartInfo = psi;
_ = process.Start();
process.WaitForExit();
System.Threading.Thread.Sleep(10);
if ((System.IO.File.Exists(psi.FileName)))
{
System.IO.File.Delete(psi.FileName);
}
Keep in mind im new when it comes to this so im sure there is a better way of writing it, but this worked for me!
This code used to work below on the C Drive where it was installed. We moved it to a UNC path \share and now it doesnt seem to reload the config file. There are no errors, and Filezilla works fine as I can connect and transfer files over on this UNC Share, but from code I cant get this to actually do what it's suppose to anymore. Do I need to do anything special credential wise? My user account for the app pool of the site is the same as the share.
Process.Start("CMD.exe", "/C \"\\filezilla\\FileZilla Server.exe\" /reload-config");
Update
I ran this line from the command prompt on the actual computer and it does what it's suppose to.
Another Update
var path = string.Format("/C \"{0}FileZilla Server.exe\" /reload-config", Config.Paths.FileZillaPath); // \\filezilla\
Process.Start("CMD.exe", path);
Logger.Debug("Path: " + path); // Path: /C "\\filezilla\FileZilla Server.exe" /reload-config
Your first pair of backslashes in the UNC path aren't escaped properly and will result in a single backslash. Try
Process.Start("CMD.exe", "/C \"\\\\filezilla\\FileZilla Server.exe\" /reload-config");
You can see an example at MSDN
string g = "\\\\server\\share\\file.txt"; // \\server\share\file.txt
string h = #"\\server\share\file.txt"; // \\server\share\file.txt
I've done something similar but like this...
Process reloadConfig = new Process();
reloadConfig.StartInfo.FileName = #"\\MachineName\FileZilla Server\FileZilla Server.exe\";
reloadConfig.StartInfo.Arguments = #"/reload-config";
reloadConfig.Start();
and that works for me.
I have a C# program that is running and I want to launch another executable in different directory.
I have this code on event:
string path = "Y:\Program\test.exe";
Process.Start(path);
Problem is that in order for program to work right it need to take information from settings.ini where the exe file is located but it takes settings.ini from program folder with which I am trying to launch second program. test.exe is working fine when I am opening it from its folder by double click. What could be the problem?
You need to tell the process what the working directory is via ProcessStartInfo.WorkingDirectory:
var processStartInfo = new ProcessStartInfo
{
WorkingDirectory = #"Y:\Program",
FileName = #"Y:\Program\test.exe",
};
Process.Start(processStartInfo);
Edit:
In order to get the directory from the user, you can use DirectoryInfo.FullName:
var userFileInfo = new FileInfo(userInsertedVariableHere);
var parentDirectory = userFileInfo.Directory.FullName;
I am trying to create an app that can kill a user's session on a terminal server.
I have written the following code:
string host = "terminalServer";
string user = "domain\criso";
string sid = "4";
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.FileName = #"logoff.exe";
startInfo.Arguments = #"/SERVER:" + host + " " + sid;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
proc.StartInfo = startInfo;
proc.Start();
proc.WaitForExit();
// Catch error
if (proc.ExitCode != 0)
{
StreamReader reader = proc.StandardError;
string errorMessage = reader.ReadToEnd();
MessageBox.Show(#"ERROR " + proc.ExitCode.ToString() + ": " + errorMessage);
}
else
StatusLabel.Text = user + #"'s Session terminated";
The code above returned error "Couldn't find the file specified" message when executed. I have tried the combination of path to go to C:\windows\system32\logoff.exe but still get the same error message.
I have also tried to invoke cmd.exe process with following argument:
#"/C logoff /SERVER:" + host + " " + sid
it returned with "'logoff' is unrecognized as internal or external command, opreable program or batch file." and still no luck.
Anyone has ever solved this problem before?
For extra information, I am using windows 7 and the terminal server is windows server 2003 & 2008 r2 (there are multiple servers).
And if I run 'logoff' command directly from command prompt, it works fine killing my session.
I found the solution by including 'logoff.exe' into the project and set 'Copy to output directory' property of 'logoff.exe' to yes or copy if newer, which then I don't need to specify the full path on my Process.Start calling.
What's odd is that when I tried to include 'logoff.exe' into my project, VS file explorer didn't list the 'logoff.exe' under 'C:\windows\system32\' directory, but the executable is there if i get into the directory by windows' regular file explorer.
UPDATE
As pointed out in the comment, it looks like that when the app is trying to look into the system32 folder, it is interrupted by syswow64 layer somehow. Based on the comment I found a switch in the project settings to build the app as 32-bit, I turned it off and the app can now call 'logoff.exe' without any issue. But when I try to add existing file from VS file explorer, it still wouldn't list the complete content of the system32 folder (as it was looking into syswow64 folder instead).
I've been searching and experimenting for a while with this, but I have had no luck.
I am trying to make a console program to automate some tasks that I couldn't quite do with a BAT file. I want to call "signcode.exe" from the Windows SDK, the bin folder with all the tools in my system PATH, and I can call "signcode" from anywhere, but Process.Start is ignoring the path.
Current code:
System.Diagnostics.Process sign = new System.Diagnostics.Process();
sign.StartInfo.FileName = signCommand.Substring(0, signCommand.IndexOf(' ')); // signtool.exe
sign.StartInfo.Arguments = signCommand.Substring(signCommand.IndexOf(' ') + 1); // /sign /a file1 file2
// sign.StartInfo.EnvironmentVariables["Path"] = Environment.GetEnvironmentVariable("PATH"); // This doesn't work either
sign.StartInfo.UseShellExecute = false;
sign.StartInfo.RedirectStandardOutput = true;
sign.StartInfo.RedirectStandardError = true;
sign.Start(); // Throws Win32Exception - The system cannot find the file specified
I've confirmed that StartInfo.EnvironmentVariables["Path"] matches my system path, and contains the Windows SDK folder. Setting it manually doesn't work either.
I've even tried setting TempPath as shown on the MSDN page for EnvironmentVariables Property, but that didn't work either. I wonder why you would be able to set this if it has no effect.
If System.Diagnostics.Process cannot use the path, are there any other functions I could use? I'd like to see the output of the command in my console application as well.
Here is some additional debug values:
Console.WriteLine("Sign Filename = '{0}'", sign.StartInfo.FileName);
Sign Filename = 'signtool.exe'
Console.WriteLine("Sign Arguments = '{0}'", sign.StartInfo.Arguments);
Sign Arguments = '/sign /f C:\Visual Studio\Projects\MGInsight\MGInsight\APPARENTINC.pfx /t http://timestamp.comodoca.com/authenticode "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\MGInsight.exe" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\XPXScanner.dll" "C:\Visual Studio\Projects\MGInsight\MGInsight\Publish\Application Files\\MGInsight_0_9_1_85\NetworkCalculations.dll"'
Console.WriteLine("Sign Path = '{0}'", sign.StartInfo.EnvironmentVariables["Path"]);
Sign Path = 'C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;"C:\Program Files\Intel\WiFi\bin\";"C:\Program Files\Common Files\Intel\WirelessCommon\";"C:\Program Files (x86)\cwRsync\bin";"C:\Program Files (x86)\Git\cmd";"C:\Program Files (x86)\Git\bin";"C:\Program Files (x86)\Zend\ZendServer\bin";"C:\Program Files (x86)\Zend\ZendServer\share\ZendFramework\bin";"C:\Program Files\Java\jre6\bin";"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\";"C:\Program Files\Microsoft Windows Performance Toolkit\";C:\MinGW\bin;"C:\Program Files (x86)\Microsoft\ILMerge";"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin";C:\Program Files (x86)\Nmap'
The path "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin" is where signtool.exe is, and I can run it from a command prompt by simply typing signtool, but if I run this application from the same prompt, it doesn't register that path.
Adding to mhutch's answer: It does indeed take PATH into consideration, but I have noticed you actually need to restart Visual Studio to pick up any path changes. It is kind of sneaky.
I'm pretty sure Process.Start does respect PATH.
Are you sure your signCommand value is correct?
Is the directory value in PATH specified using quotes? The docs mention that such values will not be respected.
Note that FileName can also be a full path to the executable.
If you updated PATH recently, be sure to restart Visual Studio. Environment variables are loaded at the launch of Visual Studio. Note that this applies to DEBUG mode execution.
Well, I guess the problem was related to what mhutch said, from the MSDN docs:
If you have a path variable declared in your system using quotes,
you must fully qualify that path when starting any process found
in that location. Otherwise, the system will not find the path. For
example, if c:\mypath is not in your path, and you add it using
quotation marks: path = %path%;"c:\mypath", you must fully qualify
any process in c:\mypath when starting it.
I saw that initially, but it seemed strange so I disregard it. Not sure why that's the case but it seems to be.
I tried copying signtool.exe to C:\sign\tool\bin and added that to my path, and then my code worked, so I guess because I have quotes in that path due to the spaces, I am SOL and will have to manually search the path for the windows SDK path unless there is some way to add something with spaces to the path without using quotes.
I believe you're looking for the ProcessStartInfo.WorkingDirectory property.
The StartInfo filename is actually the full path to the executable
For example, on a wrapper I have for x264, it looks like this:
x264Start.FileName = Directory.GetCurrentDirectory() + #"\Tools\x264\x264x86-r1995.exe";
I'd sense-check the code by adding a try {}, catch {} in there and writing the actual filename you are trying to call into the debug if you have an error.
Otherwise add something like the below:
if (File.exists(sign.FileName))
{
sign.Start();
}
else
{
Console.WriteLine("Can't find {0}", sign.FileName);
throw new Exception("File doesn't exist");
}
EDIT: Added a full example - this searches for CCleaner and then runs it with the "/AUTO" switch. Just tested and works fine.
// detect if 64-bit system
string programFiles = "";
if (Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE").Contains("64"))
{
Console.WriteLine("#info# x64 detected");
programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
}
else
{
Console.WriteLine("#info# x86 detected");
programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
}
// search
string[] dirs = Directory.GetDirectories(programFiles, "CCleaner", SearchOption.AllDirectories);
string[] exes = Directory.GetFiles(programFiles, "CCleaner64.exe", SearchOption.AllDirectories);
//debug only
foreach (string s in dirs)
{
Console.WriteLine(s);
}
foreach (string s in exes)
{
Console.WriteLine(s);
}
// access directly
ProcessStartInfo CCleaner = new ProcessStartInfo(exes[0], "/AUTO");
Process.Start(CCleaner);
Your code does seem to take the path into account for me.
It's hard to say what might be wrong in your case, but you might try running your command through cmd.exe:
sign.StartInfo.FileName = "cmd";
sign.StartInfo.Arguments = "/c signtool.exe ...";