I'm writing a c# program that should ran a proccess and print the output to the console or file.
But the exe I want to run must run as admin. I saw that to run an exe as admin i need to set useShellExecute to true. but to enable output redirection i need to set it to false.
What can i do to achieve both?
Thank you!
In this code I get the error printed to the console (because UseShellExecute=false ),
and when changed to true - the program stops.
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = false;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = "aaa.exe";
proc.RedirectStandardError = true;
proc.RedirectStandardOutput = true;
proc.Verb = "runas";
Process p = new Process();
p.StartInfo = proc;
p.Start();
while (!p.StandardOutput.EndOfStream)
{
string line = p.StandardOutput.ReadLine();
Console.WriteLine("*************");
Console.WriteLine(line);
}
You could try something like this:
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
#endregion
namespace CSUACSelfElevation
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
// Update the Self-elevate button to show a UAC shield icon.
this.btnElevate.FlatStyle = FlatStyle.System;
SendMessage(btnElevate.Handle, BCM_SETSHIELD, 0, (IntPtr)1);
}
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
static extern int SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);
const UInt32 BCM_SETSHIELD = 0x160C;
private void btnElevate_Click(object sender, EventArgs e)
{
// Launch itself as administrator
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
try
{
Process.Start(proc);
}
catch
{
// The user refused to allow privileges elevation.
// Do nothing and return directly ...
return;
}
Application.Exit(); // Quit itself
}
}
}
Related
**EDIT: When I put a breakpoint in my MinimizePlayer() method, and step through it, it minimizes the wmplayer process. But it does not without stepping through. I don't know why. **
I had a similar script on my Linux machine where I automated some tasks that I use every time I boot up. I was able to start Rhythmbox, begin playing my playlist, and minimize the process.
Well, I'm trying the same thing on my new Windows 10 machine, and I don't know how to minimize the wmplayer.exe process from my script.
This is what I have so far. It works fine, I just want wmplayer to be minimized:
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace Playlist
{
class Program
{
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
private enum WindowShowStyle:uint
{
Hide = 0,
ShowMinimized = 2,
Minimize = 6
}
static void Main(string[] args)
{
Run();
}
public static void Run()
{
String username = Environment.UserName;
username = char.ToUpper(username[0]) + username.Substring(1);
Console.WriteLine("Hello " + username);
Thread.Sleep(2000);
Console.WriteLine("Opening Playlist...");
Thread.Sleep(2000);
Process.Start("wmplayer.exe", "C:\\Users\\" + username + "\\Music\\A_ChillstepMix.mp3");
//Thread.Sleep(2000);
//Console.WriteLine("Opening your IDE...");
//Thread.Sleep(2000);
//Process.Start("C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\IDE\\devenv.exe");
//Thread.Sleep(2000);
MinimizePlayer();
Thread.Sleep(2000);
Console.WriteLine("Goodbye...");
Thread.Sleep(2000);
System.Environment.Exit(0);
}
public static void MinimizePlayer()
{
Process[] ps = Process.GetProcesses();
foreach(Process p in ps)
{
if(p.ProcessName.Contains("wmplayer"))
{
IntPtr h = p.MainWindowHandle;
ShowWindow(h, WindowShowStyle.Minimize);
}
}
}
}
}
You can specify the WindowStyle of the process you are starting if you use the ProcessStartInfo object:
var psi = new System.Diagnostics.ProcessStartInfo();
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
psi.FileName = "wmplayer.exe";
System.Diagnostics.Process.Start(psi);
Ok, I got it. I needed to add Thread.Sleep() before the MinimizePlayer() method. Working code is as follows (I commented out the Visual Studio stuff while debugging to speed things up):
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace Playlist
{
class Program
{
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
private enum WindowShowStyle:uint
{
Hide = 0,
ShowMinimized = 2,
Minimize = 6
}
static void Main(string[] args)
{
Run();
}
public static void Run()
{
String username = Environment.UserName;
username = char.ToUpper(username[0]) + username.Substring(1);
Console.WriteLine("Hello " + username);
Thread.Sleep(2000);
Console.WriteLine("Opening Playlist...");
Thread.Sleep(2000);
Process.Start("wmplayer.exe", "C:\\Users\\" + username + "\\Music\\A_ChillstepMix.mp3");
//Thread.Sleep(2000);
//Console.WriteLine("Opening your IDE...");
//Thread.Sleep(2000);
//Process.Start("C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\IDE\\devenv.exe");
Thread.Sleep(2000);
Console.WriteLine("Minimizing Player...");
Thread.Sleep(2000);
MinimizePlayer();
Thread.Sleep(2000);
Console.WriteLine("Goodbye...");
Thread.Sleep(5000);
System.Environment.Exit(0);
}
public static void MinimizePlayer()
{
Process[] ps = Process.GetProcesses();
foreach(Process p in ps)
{
if(p.ProcessName.Contains("wmplayer"))
{
IntPtr h = p.MainWindowHandle;
ShowWindow(h, WindowShowStyle.Minimize);
}
}
}
}
}
I have to open maximized internet explorer using C#. I have tried the following:
try
{
var IE = new SHDocVw.InternetExplorer();
object URL = "http://localhost/client.html";
IE.ToolBar = 0;
IE.StatusBar = true;
IE.MenuBar = true;
IE.AddressBar = true;
IE.Width = System.Windows.Forms.SystemInformation.VirtualScreen.Width;
IE.Height = System.Windows.Forms.SystemInformation.VirtualScreen.Height;
IE.Visible = true;
IE.Navigate2(ref URL);
ieOpened = true;
break;
}
catch (Exception)
{
}
I can open with different sizes, but I couldn't find how to open maximized IE. I have checked the msdn, there is no property to for maximize.
Please give me some suggestions.
PS: I am developing C# console application, .Net4.5, and VS2012
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Maximize_IE
{
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
var IE = new SHDocVw.InternetExplorer();
object URL = "http://google.com/";
IE.ToolBar = 0;
IE.StatusBar = true;
IE.MenuBar = true;
IE.AddressBar = true;
IE.Visible = true;
ShowWindow((IntPtr)IE.HWND, 3);
IE.Navigate2(ref URL);
//ieOpened = true;
}
}
}
I would use the process method.
You could start any executable and
It has a property which starts your process maximized
ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Maximized;
startInfo.Arguments = "www.google.com";
Process.Start(startInfo);
Quick google of "csharp maximize SHDocVw window" gives this example:
[DllImport ("user32.dll")]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
private const int SW_MAXIMISE = 3;
public void OpenWindow()
{
SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorer(); //Instantiate the class.
ShowWindow((IntPtr)ie.HWND, SW_MAXIMISE); //Maximise the window.
ie.Visible = true; //Set the window to visible.
}
try this:
var proc = new Process
{
StartInfo = {
UseShellExecute = true,
FileName = "http://localhost/client.html",
WindowStyle = ProcessWindowStyle.Maximized
}
};
proc.Start();
I'm trying to do this:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("git config --global user.name \"My Name\"");
sw.WriteLine("git config --global user.email \"my email\"");
sw.WriteLine("call start-ssh-agent");
sw.WriteLine("ssh-add c:\\temp\\ServerPull.ppk");
System.Threading.Thread.Sleep(10000);
sw.WriteLine(Environment.NewLine);
sw.WriteLine("git clone git#github.com:myrepo");
}
}
Console.WriteLine("Done");
}
Problem is that the "ssh-add" command wants a passphrase entering, and I can't make C# enter it. Any other commands after the Thread.Sleep go into the buffer until I actually enter something on the CMD box myself.
Console.Writeline() outputs into that same box, but it doesn't actually get "entered"
Edit: For clarity, I'm not looking to do a Console.ReadLine() or actually get input from a user. The commands are how I need them, but I need to automatically send a string to another application (ssh-add) that is asking for a passphrase. Writing the passphrase through sw.WriteLine does not work as the console wont execute any code if it's waiting for input.
EDIT:
In writing my first edit, I had a eureka moment on some code suggestions from the comments. Ended up with this now:
const int VK_RETURN = 0x0D;
const int WM_KEYDOWN = 0x100;
static void Main(string[] args)
{
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("git config --global user.name \"my name\"");
sw.WriteLine("git config --global user.email \"my email\"");
sw.WriteLine("call start-ssh-agent");
var enterThread = new Thread(
new ThreadStart(
() =>
{
Thread.Sleep(10000);
var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0);
}
));
enterThread.Start();
sw.WriteLine("ssh-add c:\\temp\\ServerPull.ppk");
sw.WriteLine("git clone myrepo");
sw.WriteLine("ping 127.0.0.1");
}
}
Console.WriteLine("Done");
}
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
which sends the enter key after a delay. I should be able to modify this from there to send in whatever I need.
I think you can use args[] of the main method. See the sample below.
public class CommandLine
{
public static void Main(string[] args)
{
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine(string.Format("git config --global user.name {0}",args[0]));
sw.WriteLine(string.Format("git config --global user.email {0}",args[1]));
sw.WriteLine("call start-ssh-agent");
sw.WriteLine(string.Format("ssh-add {0}",args[2]));
System.Threading.Thread.Sleep(10000);
sw.WriteLine(Environment.NewLine);
sw.WriteLine("git clone git#github.com:myrepo");
}
}
Console.WriteLine("Done");
}}
Execute your exe and in command line use arguments:
x:\> yourapp.exe user2645643 xyx#yourdomain.com c:\temp\ServerPull.ppk
Update
Then its quite simple. Use var inp = Console.ReadLine() and place you input variable wherever you want.
This works fine for Keying in Command Prompt
foreach (var v in message)
{
PostMessage(cmdProcess.MainWindowHandle, WM_CHAR, (IntPtr)v, IntPtr.Zero);
}
PostMessage(cmdProcess.MainWindowHandle, WmKeyUp, (IntPtr)Keys.Enter, IntPtr.Zero);
I think you can do this ,..
https://stackoverflow.com/a/9634490/3156689
This link Explains howto send return key to Console .. It is better than simulating keypresses or closing stdin stream
I've got a problem where I need to enable a card that has been disabled already and a searcher on WMI NetworkAdapter does not return the object.
I can think of a possible way to do this but I've been unable to get it to work, thats is to create a managementObject using this as the constructor name. but this just throws exceptions
{\\.\root\CIMV2:Win32_NetworkAdapter.NetConnectionID='Wireless Network Connection'}
The other way was to shell a netsh and enable the device, which is kind of ugly, or to use shell32/dll "Enable" to do the same, again, both passing just the name. Ive been getting the name from a registry scan on HKLM\SYSTEM\CurrentControlSet\Network and looking for MediaType=2 to get a string list of wireless devices. All is good if I run the application while the adapter is enabled as I can get the networkObject for the wireless device but it all falls over if the application starts while the wireless device is disabled.
Thanks
Edit : This is the code that I would love to work but no go :(
using System;
using System.Management;
class Sample
{
public static int Main(string[] args)
{
ManagementObject mObj = new ManagementObject("\\\\.\\root\\CIMV2:Win32_NetworkAdapter.NetConnectionID=\"Wireless Network Connection\"");
mObj.InvokeMethod("Enable", null);
return 0;
}
}
This method essentially is using C# to leverage the WMI and Win32_NetworkAdapter Class. It should have methods built in for:
Enable
Disable
So you can execute your command on a Selected interface.
You can achieve that in this manner:
SelectQuery query = new SelectQuery("Win32_NetworkAdapter", "NetConnectionStatus=2");
ManagementObjectSearcher search = new ManagementObjectSearcher(query);
foreach(ManagementObject result in search.Get())
{
NetworkAdapter adapter = new NetworkAdapter(result);
// Identify the adapter you wish to disable here.
// In particular, check the AdapterType and
// Description properties.
// Here, we're selecting the LAN adapters.
if (adapter.AdapterType.Equals("Ethernet 802.3"))
{
adapter.Disable();
}
}
There is a blog that actually outlines such a task; it defines how to create a Wrapper around the WMI Class.
Another solution may be to also use the ControlService (advapi32).
[DllImport("advapi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);
Hopefully that one of those ways help..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Security.Principal;
namespace WifiRouter
{
public partial class Form1 : Form
{
bool connect = false;
public Form1()
{
InitializeComponent();
}
public static bool IsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal p = new WindowsPrincipal(id);
return p.IsInRole(WindowsBuiltInRole.Administrator);
}
public void RestartElevated()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
startInfo.Verb = "runas";
try
{
Process p = Process.Start(startInfo);
}
catch
{
}
System.Windows.Forms.Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
string ssid = textBox1.Text, key = textBox2.Text;
if (!connect)
{
if (String.IsNullOrEmpty(textBox1.Text))
{
MessageBox.Show("SSID cannot be left blank !",
"Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
if (textBox2.Text == null || textBox2.Text == "")
{
MessageBox.Show("Key value cannot be left blank !",
"Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
if (key.Length >= 6)
{
Hotspot(ssid, key, true);
textBox1.Enabled = false;
textBox2.Enabled = false;
button1.Text = "Stop";
connect = true;
}
else
{
MessageBox.Show("Key should be more then or Equal to 6 Characters !",
"Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
else
{
Hotspot(null, null, false);
textBox1.Enabled = true;
textBox2.Enabled = true;
button1.Text = "Start";
connect = false;
}
}
private void Hotspot(string ssid, string key,bool status)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe");
processStartInfo.RedirectStandardInput = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;
Process process = Process.Start(processStartInfo);
if (process != null)
{
if (status)
{
process.StandardInput.WriteLine("netsh wlan set hostednetwork mode=allow ssid=" + ssid + " key=" + key);
process.StandardInput.WriteLine("netsh wlan start hosted network");
process.StandardInput.Close();
}
else
{
process.StandardInput.WriteLine("netsh wlan stop hostednetwork");
process.StandardInput.Close();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
if (!IsAdmin())
{
RestartElevated();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
Hotspot(null, null, false);
Application.Exit();
}
}
}
I have a function for starting processes on a local machine:
public int StartProcess(string processName, string commandLineArgs = null)
{
Process process = new Process();
process.StartInfo.FileName = processName;
process.StartInfo.Arguments = commandLineArgs;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.ErrorDialog = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
return process.Id;
}
It is supposed to start the process without opening a new window. Indeed, when I test it with timeout.exe no console window is opened. But when I test it with notepad.exe or calc.exe their windows still open.
I saw online that this method works for other people. I'm using .NET 4.0 on Windows 7 x64.
What am I doing wrong?
The CreateNoWindow flag applies to Console processes only.
See here for the details:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
Secondly applications can ignore the WindowStyle argument - it has effect the first time the new application calls ShowWindow, but subsequent calls are under the control of the application.
Following program will show/hide the window:
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
static void Main()
{
// The 2nd argument should be the title of window you want to hide.
IntPtr hWnd = FindWindow(null, "Untitled - Notepad");
if (hWnd != IntPtr.Zero)
{
//ShowWindow(hWnd, SW_SHOW);
ShowWindow(hWnd, SW_HIDE); // Hide the window
}
}
}
Source: http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/1bc7dee4-bf1a-4c41-802e-b25941e50fd9
You need to remove the process.StartInfo.UseShellExecute = false
public int StartProcess(string processName, string commandLineArgs = null)
{
Process process = new Process();
process.StartInfo.FileName = processName;
process.StartInfo.Arguments = commandLineArgs;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.ErrorDialog = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
return process.Id;
}