How do I get the command-line arguments of a Windows service? - c#

I'm looking for a way to figure out the command-line arguments of any Windows service.
For a non-service process, the command-line arguments can be found in the Windows Task Manager, or programmatically by using WMI as shown in this post.
Unfortunately, these two solutions don't work for a Windows service that is started by the ServiceController.Start(String[] args) method. Both of them show only the executable file path on the command-line, even though some arguments were passed in.
What is the difference
between two scenarios (a service vs.
a non-service process)?
Is there a
way to figure out the arguments of the
Windows service?
I also tried creating a simple service that just logs any command-line arguments it has to the event log. I started it using "sc.exe start <my service> <arg1>" and verified that <arg1> was written to the event log.
However, none of the solutions has worked for me. I still only saw the path to the executable file. My OS version is Windows Server 2008 R2 SP1 x64 Enterprise.

There are two types of arguments for services:
Arguments that were passed on the process start command line. You can get to those easily using Process Explorer, etc.
Arguments that were passed to the ServiceMain function. This is the WIndows API that a service is supposed to implement. The .NET equivalent is ServiceBase.OnStart. This is what is used when you do an SC START \[arguments\]. This has nothing to do with "command line process arguments".
The second type of parameters is probably only known by the service itself, if the implementation makes any use of it which is not the case for many services. I don't think Windows keep track of this when we look at low level Windows structures like the PEB: Process and Thread Structures (MSDN), even the undocumented parts of it, Undocumented functions of NTDLL.

You can find the service EXE file details and edit or just see the commandline options in the registry entry for the service. You'll find that under
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services
Be sure to restart the Services window if you decide to change this as it won't reread it live.

Try the Process Explorer application from Sysinternals
It is like Task Manager, only it lists all the running processes. Select your service and see its properties.

A service process is not started as a usual EXE file. Even more, a service process could be just a .dll file. See: Windows service (Wikipedia).
Many appear in the processes list in the Windows Task Manager, most often with a username of SYSTEM, LOCAL SERVICE or NETWORK SERVICE, though not all processes with the SYSTEM username are services. The remaining services run through svchost.exe as DLLs loaded into memory.
Just override the ServiceBase.OnStart(string[] args) method. See more:
ServiceBase.OnStart(String[]) Method (MSDN)

Using Powershell you can call
(Get-CimInstance Win32_Service -Filter 'Name = "<my service>"').PathName
to get the full command line of the service (it returns file and arguments)
Just replace <my service> with the name of the desired service.
For example:
(Get-CimInstance Win32_Service -Filter 'Name = "Dnscache"').PathName
returns "C:\WINDOWS\system32\svchost.exe -k NetworkService -p"

Related

How to call "Action Result" ASP.NET MVC at specific time (Daily)

I have a system for sending E-mails to users by a specific time .
built in ASP.NET MVC4 and has an action result "function" for checking the time of messages and send it if the day of the message is today .
how can I call this action result (daily) -like a scheduler- in efficient way ?
Thanks.
Whilst a separate service / application would be better, you could use wget.
GNU Wget is a free software package for retrieving files using HTTP,
HTTPS and FTP, the most widely-used Internet protocols. It is a
non-interactive commandline tool, so it may easily be called from
scripts, cron jobs, terminals without X-Windows support, etc.
You would then do something like:
"C:\Program Files (x86)\GnuWin32\bin\wget.exe" --no-check-certificate https://www.exammple.com/YouController/YourAction -O NUL
in a .bat file and set that to run via a windows Scheduled task at the time you require (assuming you don't need to run it less than every 60 seconds - if you do, let me know as I have another way around this using a windows service to call the bat file instead).
Omitting the -O NUL part would also save the output so you could see if everything ran successfully by doing:
public ActionResult YourAction()
{
//Do your code, get some stats that show it ran properly.
return Content("Return your stats here.");
}
from your controller action.
More efficient will be when you create new application as Windows Service. There u can easy set code to start at specific time. in this solution you will have more flexibility and independent. You can start hire : Windows Service to run a function at specified time
You could create a small console application that just calls the API do send out the emails. You can then schedule the console app to run at a specific time using the Windows Scheduler; you can even have it run without showing the console window. See here or here for details on how to schedule a task.
Use Azure Functions, that's exactly what it was built for. It's really good.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview

Automating IISRESET via remote desktop connection after a TFS build

I want to automate a process, which is invoked after a successful build on TFS. The process will RDP to a test server, then call a C# application on that server, and reset IIS on that server. Each step will return the result so whether or not to call next step is based on the previous step.
There are a few obstacles in implementing it. Below is what I want to know if it is possible, and how to code it.
1) Invoking the process via a build on TFS
There is an option in Build definition to invoke automated test. I assume that the process can be invoked by implementing it as a test.
2) RDP to remote server
I found the links below, which might be a solution
Process rdcProcess = new Process();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\cmdkey.exe");
rdcProcess.StartInfo.Arguments = "/generic:TERMSRV/192.168.0.217 /user:" + "username" + " /pass:" + "password";
rdcProcess.Start();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\mstsc.exe");
rdcProcess.StartInfo.Arguments = "/v " + "192.168.0.217"; // ip or name of computer to connect
rdcProcess.Start();
Run mstsc.exe with specified username and password
Automating remote desktop connection
3) IISReset
I think it should be simply invoke "IISRESET" after RDP, but the problem is that, HOW to captrue the result of running IISRESET.
The tools that might be suitable are:
1) Powershell - I don't know much about Powershell but am willing to learn if required
2) C#
My question is that how to implement it, any code example, and idea would be very much appreciated.
Check my answer here which is somewhat related: Answer
If the user which runs the TFSBuild Service on the build server have enough rights on the test server then you can use psexec or powershell to run your commands remotely. Read the below links:
PSEXEC
PowerShell Remote commands
There is no inbuilt activity/process which can help you run scripts on remote machines in TFS build workflow.
Step 1 for you is to identify how you are going to run scripts on the remote machine, as mentioned above you can either use PSEXEC or Powershell (though running PowerShell on remote computers may be a little more complicated to set up).
Step2, write the actual scripts to do the work, stop services, install MSI etc.
Step3, Edit your current build defintion - create a new custom activity or make use of InvokeProcess activity from within your build definition to invoke the script that you have created in Step 2. InvokeProcess Activity
in most cases you do not need to run iisreset
if you want to upgrade an asp.net application, try to put app_offline.htm in the application folder, it will stop an application and application files will be unlocked
after upgrading an application, it will restart automatically, or you can "touch" web.config to force restart
You might be better using the Lab Build to run the scripts as part of an environment ob the target computer. It can run any powershell against that machine as well as deploy and execute applications....
Question: HOW to capture the result of running IISRESET
I believe the old fashioned way, Hope this is what you are looking for
c:> IISRESET >> C:\temp.log
You can use the above either from CMD or powershell
In the past I have used Psexec to run commands against a remote server and where ever we need to control flow on the result of that command, we simply piped the console out to a shared folder and checked for our success flag.
I am not sure if TFS can run commands in this manner but we implemented it on hudson/jenkins.
This won't answer your question directly but it may offer a better way forward
An Example:
psexec.exe \remoteserver "iisreset > h:\iisreset.log"
Then run a grep or similar against the iisreset.log with your success flag as a condition to run the next step.

Finding which service has run an executable in C#

I was wondering if it were possible to find out which windows service has run an executable?
I've got two different services running from the same exe, doing different things. The main method of the program detects a command line parameter and will either start the console app (if running in Environment.UserInteractive), or start one of the two possible services. I can't find a good way to discern which service is running so I can choose the correct service to start in the code. Passing in .exe parameters in the image path of the windows service doesn't seem to work. The services are running on a server and starting automatically, so doing it manually isn't really an option.
I'd really like to avoid having to have two different projects with different executables, so any way I can notify the program of which service to run would be great.
You can pass arguments in the ImagePath. I know I have done it at some point using a .net windows service, but as I recall, I had to install the service using something other than the standard .Net installer.
The .Net installer adds quotes around whatever you pass, which makes ImagePath go from C:\test\test.exe -arguments to "C:\test\test.exe -arguments" when it should be "C:\test\test.exe" -arguments.
Check out WiX, sc.exe or CreateService to get the correct registry value.
To test, install your service as usual and browse in regedit to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\yourServiceName and edit ImagePath. For an example of how it should look, check out HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\seclogon.
You could create a Mutex in your service at the point it starts, using a name unique to the version it is running. If the mutex is obtained then you know it isn't running. If it can't be obtained then the service is already running.
You could then start your services through a new process that first tries to obtain the mutex for the first service and if it can't obtain it it starts the second.
So, you start ServiceRunner.exe -foo. A mutex called "foo" is obtained, so you release the Mutex and ServiceRunner.exe starts Service.exe -foo.
If the mutex is not obtained you then try to obtain a mutex called "bar" and follow the same process.
This is a nasty solution, and would require your to create a new exe that simply tries to start the services.
Have your service share its start state( temp file, registry key or other method, it could even write this as html to a web server... )
ServiceController yourService = new ServiceController( "YourServiceName" , "YourMachine" );
if( yourService.Status == ServiceControllerStatus.Stopped )
{
yourService.Start();
}

Visual Studio 2012 debugging of remote process not working as expected

I am struggling with a rather difficult debugging challenge and hoping that someone might have some clues how to make this work.
Here's the scenario:
I have a C# Windows service that runs under a user account with admin privileges and launches a separate executable process under a user account that has standard user privileges. The two processes are designed to communicate using WCF.
Unfortunately, when the child process is launched, it crashes immediately, with nothing in the event log that suggests what happened. The parent process continues running without exceptions.
For information: these two applications work reliably together in a configuration whereby the parent process is a desktop application. I have also had success with the parent as a Windows service, but only when both processes run under the same user account with admin privileges.
I now need to reconfigure their relationship to restrict the privileges of the child process, but this is when the crash occurs.
In order to prove that what I am trying to do is feasible, I have created two stub applications and launched them successfully in the desired configuration. So, I can deduce that my real child app contains something that is incompatible with this configuration and which causes a crash even before the code starts executing. Unfortunately, since the child process is a based on some rather complex legacy code, it is not easy to isolate its elements until I eliminate the problem, so I really need a reliable means of stepping through it.
If I modify the code of the child process to launch debugging immediately on startup, it invites me to attach a debugger, but fails to complete the attachment, with a message that indicates that The Just-in-time debugger does not have permission to debug the process.
I have also seen this question and attempted to implement this proposed solution (which looks really promising) but it fails to work in my scenario. Instead of launching debugging prior to launching the application it appears to do nothing - niether the debugger nor the application are launched and the debugging invite dialog is not displayed. However, I have verified that this technique works in my environment (by using it to launch Notepad.exe) so there is clearly something about my application or the way that I am launching it that is causing the problem.
I am happy to experiment and to share more details about my test results, if anyone has any suggestions.
Many thanks for your ideas,
Tim
The fact that the debugger never starts for the child means the error should be occuring in the PARENT server process. If you properly set the Image File Execution Options (which is easiest to do using GFlags program using the free Windows Debugging Tools from Microsoft), then that means you never start creating the child. The simplest way to test this is by adding an Assert to your code, right before the create child process call, build your parent service in debug mode, install/register it as a service, and start it up. When the Assert pops up, attach to the process, and start debugging from there. You should then see the create process error occuring in the parent.
If you want to interactively debug both the parent service and the child process, you can do this using WinDbg and GFlags, but it will be complicated.
You will need WinDbg and GFlags. These tools are included free from Microsoft as part of the Debugging Tools for Windows. You can find that free software package here:
http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx
Use GFlag to set the execution option for your PARENT SERVICE with the following debugger options:
"C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x86\WinDbg.exe" -server tcp:port=5000:9000 -o -g
When Windows starts your parent service, it will do so under WinDbg. Because of the -o option, WinDbg will also manage the launched child process, allowing you to interactively DEBUG the child from start up. Because of the -g option, WinDbg will start the ParentService up and let it run, rather than stop it at load up as is normal debugging behavior. This will prevent Windows SCM from shutting it down and starting a new instance.
Because you are running a service, it will not have access to the desktop, so neither will its host WinDbg. You will have to attach ANOTHER debugger to the running instance of the WinDbg running your ParentService. You can do this using another WinDbg instance. To do that, start a second instance of WinDbg, and connect remotely by using the menu item "File|Connect To Remote Session...". At the dialog, put in:
tcp:Port=5000:9000,Server=[machinename]
Once you are connected, you will be able to work with your ParentService.exe, and when it creates the ChildProcess, the executing context will swap to it, and you will be able to debug it as well.
I've used this technique to debug a child process created by a windows service before. It isn't as easy as just debugging something in Visual Studio's built in debugger in its IDE, but it does work.
WinDbg has extensive documentation available for it, both from Microsoft and from other sources online. The URL I provided above includes links to WinDbg documentation.
I recommend using GFlags because it will make all the necessary edits to your Registry for running executables under a debugger of your choice. It also does much more, and is worth the time to learn about.
It is possible to set up breakpoints and set all sorts of options when WinDbg starts. I replace the -g option with the command line option:
-c "$$<c:\MyDebugCommands.txt"
This instructs WinDbg to run a command, and the command is to run a WinDbg script named "MyDebugCommands.txt". I populate MyDebugCommands.txt file with all the set up changes I need (such as load symbol options), as well as setting the breakpoints I am interested in, with the final command in the file being -g
As I said, it isn't as easy as just using the VS IDE and its built in debugger, but it will let you interactively debug your parent service and its launched child process.
According to my tests based on your scenario above (parent process is service with admin rights, child is console without admin rights), I see the same debugging error as you when I artificially force the child process to throw a permission exception as soon as it starts. The error message in this instance might be misleading, as it's not clear that this is actually a debugger permission problem
It would be useful to know what type of application your child process is, because that will affect the debugging options that you have.
The first way I've tried to debug this is to intercept all unhandled exceptions in my child process (a console app). You can do this by adding the following code in the start-up procedure of your child app:
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(App_UnhandledException);
Then I added code to my App_UnhandledException procedure to log the exception. This worked for me, and I could see the reason for the permission error. The only caveat is that this won't intercept an exception where your app won't even load because of the permission problem. But this approach should at least reduce your search space in understanding the permission problem.
If the exceptioon is generated before your exception handler is reached, another possiblity is to use the assembly binding log viewer. This is a very useful tool.
FWIW you can step through your service code (but unfortunately not into your child process) by starting your service within Visual Studio. The code shown below in the switch case called DEBUG will let you start/debug your service within VS.
// This is the entry point
static void Main(string[] args)
{
// If parameter passed, act on it
if ( args.Length > 0 )
{
switch (args[0] )
{
// Debug the service as a normal app from within Visual Studio
case DEBUG:
MyService DebugService = new MyService();
DebugService.OnStart(null);
break;
// Install the service programatically
case INSTALL:
ManagedInstallerClass.InstallHelper(new string[] _
{ Assembly.GetExecutingAssembly().Location });
break;
// Un-install the service programatically
case UNINSTALL:
ManagedInstallerClass.InstallHelper(new string[] +
{ UNINSTALL, Assembly.GetExecutingAssembly().Location });
break;
// We don't understand this parameter!
default:
message = string.Concat(DEBUG, " to run service manually.", Environment.NewLine);
message += string.Concat(INSTALL, " to install service.", Environment.NewLine);
message += string.Concat(UNINSTALL, " to un-install service.", Environment.NewLine);
message += string.Concat("Do not understand the command-line parameter ", args[0]);
throw new System.NotImplementedException(message);
}
}
// If no parameter passed, just start the service normally
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(ServicesToRun);
}
}
Have you tried running Visual Studio as Administrator and calling the Process.EnterDebugMode() method?
If I modify the code of the child process to launch debugging immediately on startup, it invites me to attach a debugger, but fails to complete the attachment, with a message that indicates that The Just-in-time debugger does not have permission to debug the process
Run secpol.msc as administrator and under 'Local Policies | User Rights Management' select 'Debug Programs'. Then add the 'Users' group to that. See if that fixes the permissions issue.
HTH

Add commandline arguments to service installer c#

I am working on an application which starts as a service but only if a commandline switch tells it to (otherwise a standard form is opened). So when the service is started by Windows at bootup, it must pass this commandline option or the service fails to start.
I would like to have the installer (ServiceProcessInstaller) add a commandline option so that when the service is started it adds the commandline option to the command.
Example:
MyService.exe -commandlineoption
I thought this was what the ServiceProcessorInstaller.Context property was for, but that is for the arguments that were executed on InstallUtil.
Any suggestions?
When I've added command-line options to services, I've always defaulted to running as a service. However, I know that the opposite is possible because it's how SvcHost works: it's an EXE that's always configured to load DLL's as services.
A service is only installed once per release. It sounds like you are talking about passing a command line argument to the service when it's started.
You can pass command line arguments to the service when you start it using the ServiceController.Start method:
using (var controller = new ServiceController("servicename")) {
controller.Start(arg0, arg1);
}

Categories

Resources