I am trying to check if a process is running on a remote system. I am using the following code:
string procSearc = "notepad";
string remoteSystem = "remoteSystemName";
Process[] proce = System.Diagnostics.Process.GetProcessesByName(procSearch, remoteSystem);
However, when I try to run the code, I get the following error: "Couldn't connect to remote machine."
I am able to run pslist with the following command:
C:>pslist \remoteSystemName
So I know it is possible to get the information I need, but I need it in the code.
Another possibility would be to integrate pslist into C# and search the list to see if the process is there, but I have not found information on how to do this.
Use the System.ServiceProcess.ServiceController class for a service. You can use Status to check if it's running and the Stop() and Start() to control it.
ServiceController sc = new ServiceController();
sc.MachineName = remoteSystem;
sc.ServiceName = procSearc;
if (sc.Status.Equals(ServiceControllerStatus.Running))
{
sc.Stop();
}
else
{
sc.Start();
}
Below is what I did to get this to work:
First I added a reference to System.ServiceProcess and added: using System.ServiceProcess;
string remoteSystem = "remoteSystemName";
string procSearch = "notepad";
Process[] proc = System.Diagnostics.Process.GetProcessesByName(procSearch, remoteSystem);
if (proc.Length > 0)
{
Console.WriteLine("Able to find: " + proc[0]);
}
else
{
Console.WriteLine("Unable to find: " + procSearch);
}
Does the inner Exception say "Access Denied"?
A similar question may help, it mentions needing to be in the Performance Monitor Users group.
GetProcessesByName() and Windows Server 2003 scheduled task
I figured when running the application by itself I would get an exception window, because exceptions were not handled within my code...
There I saw the reason in the stacktrace: access denied. The reason was that the user running the program that was calling the .NET method to get the process list was not part of the "Performance Monitor Users" group of the remote machine.
After that I got another exception saying that the performance monitoring service was not running on the remote machine. So I started the corresponding service at the remote computer and voila it worked!
This was using a Windows 7 client trying to get the process list of a Windows 2008 Server.
Killing the remote process
I found that the Process.Kill() method does not work when the Process.MachineName has been set, so here is a solution for killing the process remotely, hope it helps others.
The extension method to create the method: KillRemoteProcess
public static class ProcessExtensions
{
public static void KillRemoteProcess(this Process p, string user, string password)
{
new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "TaskKill.exe",
Arguments = string.Format("/pid {0} /s {1} /u {2} /p {3}", p.Id, p.MachineName, user, password),
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
}
}.Start();
}
}
And ofcourse the method to find the processes and consume the KillRemoteProcess
public static void KillProcessesRemote()
{
string targetProcessName = "myProcess"; //Do not put 'process.exe' here just 'process'
string targetMachine = "remotMachine"; //Target machine
string username = "myUser"; //Username
string password = "myPassword"; //Password
Parallel.ForEach<Process>( //Kill all processes found
source: System.Diagnostics.Process.GetProcessesByName(targetProcessName, targetMachine),
body: process => {
process.KillRemoteProcess(username, password);
});
}
You may try impersonate to the user that have access to the remote server.
https://learn.microsoft.com/en-us/dotnet/api/system.security.principal.windowsimpersonationcontext?redirectedfrom=MSDN&view=netframework-4.7.2
After Impersonation, you will no longer hit the error.
Also, you have to make sure there is trust between domain, else impersonation will not work.
LogonUser works only for my domain
Related
Hi I'm trying to change the startup type of a existing Windows service. Say "Spooler" ( Print Spooler). I'm using ServiceController
var service = new ServiceController("Spooler");
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, 600);
Though I'm able to start/stop services I'm not able to figure out how can I change the startup type itself? ( eg: Disabled/Automatic/Manual )
When I peek definition of ServiceController I can see ServiceStartMode being defined. Could someone help me how can I set this option?. My need is to disable a Windows service programmatically using ServiceControl class or any other feasible way..
The simplest way is to use a sc command tool:
Example for changing the startup type to disabled:
sc config "MySql" start=disabled
Note you need to have the administrator privileges to run this command successfully.
Wrapping with C# code:
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "CMD.EXE",
Arguments = string.Format("/C sc {0} {1} {2}", "config", "MySql", "start=disabled"),
};
using (var process = new Process { StartInfo = startInfo})
{
if (!process.Start())
{
return;
}
process.WaitForExit();
Console.WriteLine($"Exit code is {process.ExitCode}");
}
Update:
Use process.Exit code to check if process the operation succeeded or not.
0 ExitCode is success.
Note: In case you are running the process/Visual Studio without the Admin privileges, the ExitCode will be 5 (access deined).
I'm creating a website and in it I'm giving a link where the user enters his/her Azure VM username and password and then I'm gonna go ahead and restart the machine IIS server.
So I'm writing a .NET Code for implementing the same but no luck yet. I'm not able to restart the IIS server for the remote machines, I have even looked for an alternative approach to achieve the same using Powershell but unable to do so.
I tried remotely restarting the IIS server using WMI and also created code for calling Powershell in .Net Core but I'm not able to achieve the same.
Can someone please help me with how to restart the IIS server remotely using C# code or .NET Core code?
As for this...
Share me the link wherein there is a PowerShell script that restarts
IIS on a remote server using the system credentials.
... a quick search using 'Restart IIS on remote machine'
... will give a list of articles in the topic, some from right here on StackOverflow, since this is not the first time this has been asked. So, your question can be considered a potential duplicate of the below.
Example(s):
about_Remote - PowerShell | Microsoft Docs
Restart IIS on remote machine
Some of the answers, not using PowerShell to do this from the above are:
# Simplest will be
iisreset <servername>
# Run command prompt as admin and execute the command.
# Example : If server name is SRVAPP then command will be iisreset SRVAPP
# You could use sc
sc \\RemoteServer stop iisadmin
sc \\RemoteServer start w3svc
# or SysInternals' psexec. The PsTools suite is useful for these scenarios.
psexec \\RemoteServer iisreset
PowerShell Remoting requires you to be in the local admin group on the target host. You cannot run PowerShell code as SYSTEM unless you are running a scheduled task, even then it is the scheduled task running as whatever credential it was set for and running any script in that task. To run PowerShell code as another user, you must know the username and password.
You can use PowerShell to set up a scheduled task to run. Just search for 'PowerShell scheduled task' for details.
I tried the below codes for restarting IIS remotely but it didn't work.
Method 1:
using System.Diagnostics;
using System.Management;
using System.IO;
using System.Security;
Process myProcess = new Process();
ProcessStartInfo remoteAdmin =
new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "iisreset.exe"));
remoteAdmin.Arguments = "/restart";
myProcess.StartInfo.Verb = "runas";
var s = new SecureString();
//s.AppendChar('g');
Console.WriteLine("Enter username:");
string userName = Console.ReadLine();
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Enter password:");
string password = Console.ReadLine();
Console.WriteLine(Environment.NewLine);
var securePasswordString = new SecureString();
// Use ToCharArray to convert string to array.
char[] array = password.ToCharArray();
// Loop through array.
for (int i = 0; i < array.Length; i++)
{
// Get character from the array.
securePasswordString.AppendChar(array[i]);
}
remoteAdmin.UserName = userName;
remoteAdmin.Password = securePasswordString;
remoteAdmin.Domain = "localhost";
myProcess.StartInfo = remoteAdmin;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.Start(); //---ERROR HERE
if (!myProcess.Start())
{
// That didn't work
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Process did not start!!!");
}
myProcess.WaitForExit();
var processExitCode = myProcess.ExitCode;
if (processExitCode == 0)
{
Console.WriteLine("The operation completed successfully.");
}
if (processExitCode != 0)
{
// That didn't work
if (processExitCode == 5)
{
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Access Denied");
}
}
Console.ReadKey();
Method 2:
ConnectionOptions conn = new ConnectionOptions();
conn.Impersonation = ImpersonationLevel.Impersonate;
conn.Username = #"Username";
conn.Password = "";
//ManagementScope theScope = new ManagementScope("\\\\" + txtServerName.Text + "\\root\\cimv2", conn);
theScope.Connect(); //---ERROR HERE
I tried the below code to run powershell script from C# code but I need the script which takes remote server admin credentials and restart the IIS.
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
static void RunPsScriptMethod2()
{
StringBuilder sb = new StringBuilder();
PowerShell psExec = PowerShell.Create();
psExec.AddCommand(#"C:\Users\d92495j\Desktop\test.ps1");
psExec.AddArgument(DateTime.Now);
Collection<PSObject> results;
Collection<ErrorRecord> errors;
results = psExec.Invoke();
errors = psExec.Streams.Error.ReadAll();
if (errors.Count > 0)
{
foreach (ErrorRecord error in errors)
{
sb.AppendLine(error.ToString());
}
}
else
{
foreach (PSObject result in results)
{
sb.AppendLine(result.ToString());
}
}
Console.WriteLine(sb.ToString());
}
I want to open process pon remote machine, this remote machine is inside local network.
I try this command and in the remote machine nothing happen, this user that i connect with have administrators rights.
Both machines running Windows 7
static void Main(string[] args)
{
try
{
//Assign the name of the process you want to kill on the remote machine
string processName = "notepad.exe";
//Assign the user name and password of the account to ConnectionOptions object
//which have administrative privilege on the remote machine.
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = #"MyDomain\MyUser";
connectoptions.Password = "12345678";
//IP Address of the remote machine
string ipAddress = "192.168.0.100";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2", connectoptions);
//Define the WMI query to be executed on the remote machine
SelectQuery query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");
object[] methodArgs = { "notepad.exe", null, null, 0 };
using (ManagementObjectSearcher searcher = new
ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject process in searcher.Get())
{
//process.InvokeMethod("Terminate", null);
process.InvokeMethod("Create", methodArgs);
}
}
Console.ReadLine();
}
catch (Exception ex)
{
//Log exception in exception log.
//Logger.WriteEntry(ex.StackTrace);
Console.WriteLine(ex.StackTrace);
}
}
you are not opening a process with that code but you are enumerating all the running process named "iexplore.exe" and close them.
I think an easier, better way is to use SysInternals PsExec or the Task Scheduler API
If you want to use WMI your code should look like this:
object theProcessToRun = { "YourFileHere" };
ManagementClass theClass = new ManagementClass(#"\\server\root\cimv2:Win32_Process");
theClass.InvokeMethod("Create", theProcessToRun);
----------In reply to your comment------------------
First of all you need to change your attitude and approach to coding and read the code that your are copy/pasting.
Then you should study a little more about programming languages.
No I will not write the code for you. I gave you an hint to point to the right direction. now it is your turn to develop it. Have fun!!
This is script that i did for my company before this using vbs script. can search the net to convert it to C# or etc. Fundamental of the steps and how to start a service using WMI. Have a nice coding and have fun.
sUser = "TESTDomain\T-CL-S"
sPass = "Temp1234"
Set ServiceSet = GetObject("winmgmts:").ExecQuery("Select * from Win32_Service where Name = 'netlogon'")
For Each Service In ServiceSet
Service.StopService
Service.Change "netlogon",Service.PathName, , ,"Automatic",false,sUser,sPass
Service.StartService
Next
Set Service = Nothing
Set ServiceSet = Nothing
I´m trying to run an old .NET application from an ASP.NET website. After reading the web and Stackoverflow (for similar problem) I come to the following code.
The Problem is that I get always an error code (I am using administrator account
just to testing purposes). If I run the exe manually it works ok.
private void Execute(string sPath)
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.UserName = "administrador";
string pass = ".............";
System.Security.SecureString secret = new System.Security.SecureString();
foreach (char c in pass) secret.AppendChar(c);
proc.StartInfo.Password = secret;
proc.StartInfo.WorkingDirectory = ConfigurationManager.AppSettings["WORKINGDIRECTORY"].ToString();
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName = sPath;
proc.Start();
proc.WaitForExit();
string result = proc.StandardOutput.ReadToEnd();
Response.Write(result + " - " + proc.ExitCode);
proc.Close();
}
}
The exitcode I get is: -1066598274
Result variable is empty.
No exception is thrown
I am using Windows 2008 with IIS 7.0
Thanks in advance,
Ezequiel
Don't do this. This is just plain dirty and should not be done from ASP.NET
Write a windows service
Store the request in a queue
The service should poll the queue and process. If needed run the exe. It is suggested that the service stays in a different server.
Don't do this. This is very bad and not scalable and bad for the web server
Don't
Don't
Don't
protected void btnSubmit_Click(object sender, System.EventArgs e)
{
if (Page.IsValid)
{
litMessage.Visible = true;
System.Diagnostics.Process oProcess = null;
try
{
string strRootRelativePathName = "~/Application.exe";
string strPathName =
Server.MapPath(strRootRelativePathName);
if (System.IO.File.Exists(strPathName) == false)
{
litMessage.Text = "Error: File Not Found!";
}
else
{
oProcess =
new System.Diagnostics.Process();
oProcess.StartInfo.Arguments = "args";
oProcess.StartInfo.FileName = strPathName;
oProcess.Start();
oProcess.WaitForExit();
System.Threading.Thread.Sleep(20000);
litMessage.Text = "Application Executed Successfully...";
}
}
catch (System.Exception ex)
{
litMessage.Text =
string.Format("Error: {0}", ex.Message);
}
finally
{
if (oProcess != null)
{
oProcess.Close();
oProcess.Dispose();
oProcess = null;
}
}
}
}
If you use
proc.StartInfo.RedirectStandardOutput = true;
then you have to read the stream as the process executes, instead of before the call to
proc.WaitForExit();
Same goes for the standard error stream. See the MSDN docs for more detail.
You need to reorder the output reading at the end.
It expects you to read before the waitforexit() call, so you should have:
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
Response.Write(result + " - " + proc.ExitCode);
proc.WaitForExit();
proc.Close();
If the application you're trying to run is really a .NET application as you say, you may not need to run it in a separate process at all. Instead, you can take advantage of the fact that .NET executables are also assemblies. I don't think Visual Studio will let you reference assemblies that end in .exe, but the command-line compiler will.
I would try using the command-line compiler to create a wrapper assembly that simply references the executable assembly, and directly calls its Main() method, passing in a string array of any command-line parameters you would normally specify. The exit code, if any, will be an integer return value from the Main method. Then you can simply call your wrapper assembly from your ASP.NET app.
Depending on what the executable does, and how much it interacts with the console, this approach may not work at all. But if it does work for your case, it should perform much better than spinning up a separate process.
What i do is to have the executable called by a ms sql job.
The executable would be run as SQL server agent service account.
Create a new sql server job
Give it a name in the job property's general page
In the steps page, create a new step of type Operating system (CmdExec)
Speeify the command and click ok to save the job parameters
The new job can be called using EXEC msdb.dbo.sp_start_job #jobname, where #jobname is
the variable carrying the name of the job you want to start.
Note that when this job starts, the UI of the exe will be hidden and will not be displayed; but you can find it in your task manager.
I have employed this method in several applications especially time consuming operations that cannot be done on the web page.
You may need to set the proc.StartInfo.LoadUserProfile property to true so the administrator's user profile stuff is loaded into the registry (AFAIK this does not happen by default).
Also, it might be educational to run a 'hello world' program to see if the problem is with actaully creating the process or if the process itself is having problems running in the context it's given.
Finally, as a step in trying to narrow down where the problem might be, you might want to run the ASP.NET process itself with admin or system credentials to see if something in the permissions of the account the ASP.NET instance is running under is part of the problem (but please do this only for troubleshooting).
Use below code:
ProcessStartInfo info = new ProcessStartInfo("D:\\My\\notepad.exe");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
//info.UserName = dialog.User;
info.UserName = "xyz";
string pass = "xyz";
System.Security.SecureString secret = new System.Security.SecureString();
foreach (char c in pass)
secret.AppendChar(c);
info.Password = secret;
using (Process install = Process.Start(info))
{
string output = install.StandardOutput.ReadToEnd();
install.WaitForExit();
// Do something with you output data
Console.WriteLine(output);
}
I have a process that needs to run under administrative privileges. I need the average joe to run the process, but I don't want to give everyone access... so I've created a simple class that will run this ONE task as an administrator, using impersonation.
The code is VERY striaght-forward, but I can't understand why this is crashing. HELP??!!
I'm running this via a batch file, and I've even copied the file that needs to execute to the local hard drive, thinking this might be a permission issue for running an app over the network.
public static Process ImpersonateProcess(string exe, string args, string Username, string Password)
{
ProcessStartInfo psi = new ProcessStartInfo(exe);
psi.Arguments = args;
psi.UseShellExecute = false;
psi.UserName = Username;
psi.Password = new SecureString();
foreach (char c in Password.ToCharArray())
{
psi.Password.AppendChar(c);
}
Process proc = null;
Console.WriteLine("starting...");
proc = Process.Start(psi);
Console.WriteLine("started");
return proc;
}
In the code above, I never get to "started". It throws an error in the Process.Start(psi) and with an error message of "the directory name is invalid."
It could be because you're not setting the WorkingDirectory property. According to the
docs:
Important Note:
The WorkingDirectory property must be set if UserName and Password are provided. If the property is not set, the default working directory is %SYSTEMROOT%\system32.