What is the best way to install a windows service written in C# (in the standard way) on a remote machine, where I need to provide the username and password it should run as?
I am going to run it from MSBuild as part of integration tests.
EDIT: I don't have an msi and I don't want to create one.
You can use the SC command.
sc.exe \\remotecomputer create newservice binpath= C:\Windows\System32\Newserv.exe start= auto obj= DOMAIN\username password= pwd
(Note the spaces after the equals signs are important)
Creates a service entry in the registry and Service Database.
SYNTAX:
sc create [service name] [binPath= ] <option1> <option2>...
CREATE OPTIONS:
NOTE: The option name includes the equal sign.
type= <own|share|interact|kernel|filesys|rec>
(default = own)
start= <boot|system|auto|demand|disabled>
(default = demand)
error= <normal|severe|critical|ignore>
(default = normal)
binPath= <BinaryPathName>
group= <LoadOrderGroup>
tag= <yes|no>
depend= <Dependencies(separated by / (forward slash))>
obj= <AccountName|ObjectName>
(default = LocalSystem)
DisplayName= <display name>
password= <password>
Installutil called from WMI invoked from Powershell is one way to go.
We used to use PsExec to do everything on remote machine.
At this time I saw naother solution called PowerShell Remoting, but haven't tried myself.
It might be worth you checking out a utility I wrote which lets you install/uninstall/start/stop windows services on a local or remote machine. If you have a feature you need added let me know (comment/github issues or PM and I'll happily oblige).
ServiceConfigurator on GitHub
As #Raj More suggested, it uses WMI invoked from .NET.
Related
I want to get service name inside service. The rough idea is to get process id and compare the process id with services enumerated by WMI, ServiceCotroller or EnumServicesStatusEx() API.
The problem is that the service is running under a domain account (it isn't local administrator). When I want to enumerate the services inside the running service, the running service itself is missing from enumeration!
If I move the service account to local administrator, the running service is found. So it isn't code issue. (If code issue, the behavior should be same: service not found.)
If I extract the logic to a console application (or by powershell) and run application or powershell under service account, the service is found, too. So it isn't permission issue. (If permission issue, the behavior should be same: service not found.)
The service CANNOT be enumerated when the service account IS NOT administrator and INSIDE service. It is very wire issue.
I check documentation for EnumServicesStatusEx from MSDN and find local administrator has extra SC_MANAGER_LOCK than local authenticated user. Is it the reason? But I CANNOT link the lock with service enumeration.
Or somebody please indicate a way to query service name inside the service.
Thanks.
BTW, It is on Windows 2008 R2.
I found a related question: How to get name of windows service from inside the service itself.
the 1st answer is not acceptable for me. I want to provide a common library and has no control to installer.
the 2nd answer is same idea with me. I guess it should be same with my result.
It is a permission issue.
Run psservice from Sysinternals like:
psservice.exe security InstrumentationTestService
and I got the following result:
PsService v2.24 - Service information and configuration utility
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
SERVICE_NAME: InstrumentationTestService
DISPLAY_NAME: InstrumentationTestService
ACCOUNT: LocalSystem
SECURITY:
[ALLOW] NT AUTHORITY\SYSTEM
Query status
Query Config
Interrogate
Enumerate Dependents
Pause/Resume
Start
Stop
User-Defined Control
Read Permissions
[ALLOW] BUILTIN\Administrators
All
[ALLOW] NT AUTHORITY\INTERACTIVE
Query status
Query Config
Interrogate
Enumerate Dependents
User-Defined Control
Read Permissions
[ALLOW] NT AUTHORITY\SERVICE
Query status
Query Config
Interrogate
Enumerate Dependents
User-Defined Control
Read Permissions
It indicates that my service account has no permission to Query the service status.
If I use service account to run powershell/WMI/ServiceController, the service account will turn into a INTERACTIVE user. So it has the permission to query service status.
The solution is to grant the service account Query status permission.
This is not a pure PowerShell answer, but you've got a good tool as far as EXEs,DLLs and SERVICEs are concerned it's TASKLIST.EXE.
Have a look to /FI and /FO. In the following sample I get information for the search service.
tasklist /FI "SERVICES eq WSearch" /FO "CSV"
To integrate it with PowerShell youcan use :
tasklist /FI "SERVICES eq WSearch" /FO "CSV" | ConvertFrom-Csv
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.
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"
I'm writing the windows form program to monitor our in-house windows services.
The screenshot is provided for the draft version of that program.
What I want to do is... I want to pass UserName & Password to run the services from my program. I don't know which class or components to use.
I tried to use the following codes, as we used in Installing the services. However, it does not still work. Perhaps, I don't know how to bind the user credential with service controller.
ServiceProcessInstaller serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.User;
serviceProcessInstaller1.Password = txtPassword.Text;
serviceProcessInstaller1.Username = txtUserName.Text;
So, Please advise me how could I achieve my requirements? Thanks.
Have a look at this library which lets you do just that:
Install a Windows Service in a smart way instead of using the Windows Installer MSI package
Since you are trying to manipulate the account that an existing, installed service is running under, you will need to use the code specified in the following article:
http://weblogs.asp.net/avnerk/archive/2007/05/08/setting-windows-service-account-c-and-wmi.aspx
Basically, the author found that it wasn't as simple as expected but it was possible (without a registry modification).
I have the following C# code
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
// ...
}
which gives me the exception
Access to the registry key
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell'
is denied.
According to this, the solution is to start PowerShell as an administrator.
Ordinarily, this can be accomplished by right-clicking PowerShell and selecting "Run as Administrator". Is there a way to do this programmatically?
I know this is an old post, but we ran into this same problem recently.
We had to scope the execution policy on the machine running the C# code by running the following from PowerShell...
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
When we had done this previously, without scoping, we were setting the execution policy for Administrator. Visual Studio \ C# was running as the current user, causing it to fail with insufficient permissions.
Check this out
You need to impersonate as an administrator to do it (you will of course need administrator credentials)
Check that article, that also comes with code ready to use (I've used it and it works great)
Basically, you need to do this:
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
}
}
Administrative privileges are at the application level. The app that needs admin access in this case is yours. Creating runspaces in C# in a custom app does not invoke powershell the application - it just loads some assemblies into your application.
That said, you can elevate as the other poster said although embedding admin usernames and passwords into source code make me feel ill.
-Oisin
I think an alternative model would be to wrap the powershell executor into a simple asp.net webapi webservice.
The webservice could then be configured to run with the required permissions needed to do it's job. It can provide it's own security to determine which clients can call it.
To execute a script, you would just call webservice methods. You could make the method quite general - script name and params.
It's a bit more work, but a lot more secure (see x0n's thoughts).
Strictly for DEV environment
This is relatively very old post.
But I have found a new way to do this.
I am hosting the C# web api on IIS 8 having some powershell code that I want to run with administrator privileges.
So I provided the admin credentials in the Application pool identity setting.
Just set administrator account in app pool identity.
Hope this helps to anyone. :)