C# implicitly calls the CMD command Attrib with administrator privileges - c#

Use C# to copy WINDOWS log files to other disks. The main problem is that the CMD command with administrator privileges will not be called, and some of the things mentioned on the Internet will not work.
private Process proc = null;
public Command()
{
proc = new Process();
}
public void RunCmd(string cmd)
{
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "C:\Windows\System32\cmd.exe";
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Verb = "RunAs";
proc.Start();
proc.StandardInput.WriteLine(cmd);
proc.Close();
}
public void ChangeFile(string path1,string path2)
{
Command cmd = new Command();
cmd.RunCmd("attrib -s" + " " + path1);
Directory.CreateDirectory(path2);
cmd.RunCmd("Xcopy" + " " + path1 + " " + path2);
}
Hope someone can tell me how to fix it.

You can restart a process as an administrator like this:
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\cmd.exe");
info.UseShellExecute = true;
info.Verb = "runas";
Process.Start(info);
For details, please refer to Run process as administrator from a non-admin application

Related

Setup project creating database

I am not sure but i think i have problems with some permissions...
I have this method:
static void ExecuteCommand(string _Command)
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + _Command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = false;
//procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
procStartInfo.Verb = "runas";
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
MessageBox.Show(result);
}
First, i was executing this code in a desktop app and it works.
string createDB = #"sqlcmd -S " + SQLINSTANCE + #" -Q ""CREATE DATABASE " + DBNAME + #"""";
ExecuteCommand(createDB);
But now im trying to execute it in the setup-project with custom action getting this error:
CREATE DATABASE permission denied in database 'master'.
If i execute this string in a cmd console (with and without admin privileges) it work perfectly...
Where is the problem?
Try with the properties UserName and Password instead of runas.
var psi = new ProcessStartInfo();
psi.Domain = "domain";
psi.UserName = "username";
psi.Password = password;

"Multi-Step" commands while using CMD.exe in C#

I'm trying to use "multi-step" command in a c# script, for example the command "net user usrname *" contains 3 steps to enter a password and then validate, i don't know if it is possible to send extra arguments while the Process is running
My code:
Process p = new Process();
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C " + command;
p.StartInfo.WorkingDirectory = startupFolder;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
You would concatenate each command with "&". For example, "cmd /k echo Test 1 & echo test 2".
Edit:
I created a remote control/remote admin solution a while back that uses this same technique to allow you to run batch and PowerShell scripts against remote computers via the web portal. As shown in the below screenshot, it works.
The C# that executes the command can be found here: https://github.com/Jay-Rad/InstaTech_Client/blob/master/InstaTech_Service/Socket.cs#L614
if (cmdProcess == null || cmdProcess.HasExited)
{
var psi2 = new ProcessStartInfo("cmd.exe", "/k " + command);
psi2.RedirectStandardOutput = true;
psi2.RedirectStandardInput = true;
psi2.RedirectStandardError = true;
psi2.UseShellExecute = false;
psi2.WorkingDirectory = Path.GetPathRoot(Environment.SystemDirectory);
cmdProcess = new Process();
cmdProcess.StartInfo = psi2;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.OutputDataReceived += async (object sender, DataReceivedEventArgs args) =>
{
jsonMessage.Status = "ok";
jsonMessage.Output = args.Data;
await SocketSend(jsonMessage);
};
cmdProcess.ErrorDataReceived += async (object sender, DataReceivedEventArgs args) =>
{
jsonMessage.Status = "ok";
jsonMessage.Output = args.Data;
await SocketSend(jsonMessage);
};
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
cmdProcess.BeginErrorReadLine();
}
else
{
cmdProcess.StandardInput.WriteLine(command);
}

How to restart IIS on remote windows server from windows 7 client machine?

I am trying to restart iis remotely (Windows Servr 2012) from my local machine (Windows 7). The below command in command line doesn't work to restart IIS;
iisreset servername /restart
but the below command works fine when I tried in command line.
psexec iisreset \\servername /restart
Now the issue is when I try with below code in C#,
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "\C psexec iisreset \\servername /restart";
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
// capture what is generated in command prompt
var output = process.StandardOutput.ReadToEnd();
If I give any other arguments in the above code like 'ipconfig', it gives me the expected output. But when I try with psexec, it gives empty output. But it works well when tried in command prompt.
I have also tried by using 'psexec.exe' in the filename and by removing '\C psexec' in the arguments. But still no luck.
Could you please anyone help me to resolve this?
Thanks in Advance.
I have found that when using PSexec like this that you Shouldn't use CMD.exe, and you need to ensure that you have the full path to psexec. Even if it is in the same directory as your application exe.
//Assume that psexec.exe is in same location as application
//Get directory of running applications
String AppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).Replace("file:\\","");
//Set up start infor details
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = false;
//Combine path of running app
startInfo.FileName = Path.Combine(AppPath, "psexec.exe");
startInfo.Arguments = "\\servername c:\path\to\iisreset /restart";
//Execute
Process nProc = Process.Start(startInfo);
nProc.Start();
I hope u need to provide the domain admin credentials to it.
private int ExcecuteCommand(string command, string fileName, bool getResult, string timeout = null)
{
try
{
var secure = new SecureString();
foreach (char c in txtAdminPassword.Text)
{
secure.AppendChar(c);
}
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.Domain = txtDomainName.Text;
pProcess.StartInfo.UserName = txtUser.Text;
pProcess.StartInfo.Password = secure;
pProcess.StartInfo.FileName = fileName;// AppDomain.CurrentDomain.BaseDirectory + #"PSTools\PsExec.exe"; ;
//pProcess.StartInfo.Arguments = string.Format(#"\\{0} -i -s -accepteula ipconfig /all", ipAddress);
//pProcess.StartInfo.Arguments = string.Format(#"\\{0} -accepteula netstat -ano",ipAddress);
//pProcess.StartInfo.Arguments = string.Format(#"\\{0} -accepteula -i CheckURLConnectivity", ipAddress);
//pProcess.StartInfo.Arguments = string.Format(#"\\{0} -accepteula ping {2}", ipAddress, AppDomain.CurrentDomain.BaseDirectory + #"Installer\CheckURLConnectivity.exe","10.10.10.35");
//pProcess.StartInfo.Arguments = string.Format(#"\\{0} -accepteula cmd /c type C:\ServiceLog.txt", ipAddress);
pProcess.StartInfo.Arguments = command;//string.Format(#"\\{0} -accepteula -c -f {1}", compName, AppDomain.CurrentDomain.BaseDirectory + #"Installer\CheckURLConnectivity.exe");
pProcess.StartInfo.UseShellExecute = false;
Process.StartInfo.RedirectStandardInput = true;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.StartInfo.CreateNoWindow = true;
logger.log("Query " + command);
pProcess.Start();
if (timeout == null)
pProcess.WaitForExit();
else
pProcess.WaitForExit(Convert.ToInt32(timeout));
string strOutput = string.Empty;
if (pProcess.HasExited == true && pProcess.ExitCode != 0)
{
string _errorMessage = GetWin32ErrorMessage(pProcess.ExitCode);
pProcess.Kill();
return pProcess.ExitCode;
}
else
return 0;
}
catch (Exception)
{
return -1;
}
}
IISreset requires elevated privilege to work.So you have to use the -h switch with psexec
-h If the target system is Vista or higher, has the process run with the account's elevated token, if available.
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "psexec.exe";
startInfo.Arguments = "-h iisreset \\servername /restart";
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
// capture what is generated in command prompt
var output = process.StandardOutput.ReadToEnd();
Thank you all for your valuable response. It works fine with below code :)
startInfo.FileName = #"C:\Windows\Sysnative\PsExec.exe";
startInfo.Arguments = "iisreset \\servername /restart";
Reference: Process.Start in C# The system cannot find the file specified error

C# Run CMD as Administrator

I'm trying to run cmd command as administrator. But the CMD window closes unexpectedly. If CMD window stays I can see the error. I tried to use process.WaitForExit();
I am trying to run the code zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk as administrator.
Here is my code.
//The command that we want to run
string subCommand = zipAlignPath + " -v 4 ";
//The arguments to the command that we want to run
string subCommandArgs = apkPath + " release_aligned.apk";
//I am wrapping everything in a CMD /K command so that I can see the output and so that it stays up after executing
//Note: arguments in the sub command need to have their backslashes escaped which is taken care of below
string subCommandFinal = #"cmd /K \""" + subCommand.Replace(#"\", #"\\") + " " + subCommandArgs.Replace(#"\", #"\\") + #"\""";
//Run the runas command directly
ProcessStartInfo procStartInfo = new ProcessStartInfo("runas.exe");
//Create our arguments
string finalArgs = #"/env /user:Administrator """ + subCommandFinal + #"""";
procStartInfo.Arguments = finalArgs;
//command contains the command to be executed in cmd
using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
{
proc.StartInfo = procStartInfo;
proc.Start();
}
Is there a way to keep the CMD window running/showing?
You are starting a process from the runas.exe executable file. That's not how to elevate a process.
Instead you need to use shell execute to start your excutable, but use the runas verb. Along these lines:
ProcessStartInfo psi = new ProcessStartInfo(...); // your command here
psi.UseShellExecute = true;
psi.Verb = "runas";
Process.Start(psi);
Capture the output(s) from your process:
proc.StartInfo = procStartInfo;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start()
// string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
Then do something with the output.
Note: you shouldn't try to synchronously read both streams at the same time, as there's a deadlock issue. You can either add asyncronous reading for one or both, or just switch back and forth until you're done troubleshooting.
The following method actually works...
private void runCMDFile()
{
string path = #"C:\Users\username\Desktop\yourFile.cmd";
Process proc = new Process();
proc.StartInfo.FileName = path;
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.RedirectStandardOutput = false;
proc.StartInfo.Verb = "runas";
proc.Start();
proc.WaitForExit();
}

Running process openfiles output result to file

I am trying to output the result of the openfiles process to a file but I am not getting any result can someone explain why? I have tried it 2 different ways. If I use the command prompt and run the same process it does display a result to my file.
Update: I added a third method with the change redirectstandardoutput = true
I tried this and now I get a file but with no results
Update:
I found the problem it is with the build option being set to x86 when doing this on a 64bit system I think it is running the 32bit version of openfiles. I tested by running my app and using the RedirectStandardError stream which I should have been doing in the first place :) and this is what it said "ERROR: The target system must be running a 32 bit OS."
//First Method
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "openfiles";
proc.StartInfo.Arguments = "/query /FO CSV /v > " + "\"" + Application.StartupPath + #"\OpenFiles.log" + "\"";
proc.Start();
}
//Second method
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "cmd";
proc.StartInfo.Arguments = "/C openfiles /query /FO CSV /v > " + "\"" + Application.StartupPath + #"\OpenFiles.log" + "\"";
proc.Start();
}
//Third method
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.FileName = "openfiles";
proc.StartInfo.Arguments = "/query /FO CSV /v";
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
if (output != null)
File.WriteAllText(Path.Combine(Application.StartupPath, "OpenFiles.log"), output);
}
The redirect will not work like that as > filename is not seen as an 'argument'.
Typically, you will capture the output in your application and write it to a file yourself:
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
File.WriteAllText(Path.Combine(Application.StartupPath, "OpenFiles.log"), output);

Categories