How do I enable "Allow service to interact with desktop" programmatically?
In services.msc > Action > Properties > Log On > Allow service to interact with desktop, I can enable my service to interact with the desktop. I want my service to play sound (MP3, WAV, etc.).
I'm going to take some liberties in here in trying to interpret your question from keywords. In the future, please spend more time writing your questions so that they make sense to another person who is trying to read and understand them.
There is a checkbox under the Log On tab in the properties window for a Windows service that is called "Allow service to interact with desktop." If you're trying to check that box programmatically, you need to specify the SERVICE_INTERACTIVE_PROCESS flag when you create your service using the CreateService API. (See MSDN).
However, note that as of Windows Vista, services are strictly forbidden from interacting directly with a user:
Important: Services cannot directly interact with a user as of
Windows Vista. Therefore, the
techniques mentioned in the section
titled Using an Interactive Service
should not be used in new code.
This "feature" is broken, and conventional wisdom dictates that you shouldn't have been relying on it anyway. Services are not meant to provide a UI or allow any type of direct user interaction. Microsoft has been cautioning that this feature be avoided since the early days of Windows NT because of the possible security risks. Larry Osterman argues why it was always a bad idea. And he is not the only one.
There are some possible workarounds, however, if you absolutely must have this functionality. But I strongly urge you to consider its necessity carefully and explore alternative designs for your service.
Because the service does not run in the context of a user session, you create a second application to interact with the service.
For example, the Microsoft SQL server has a monitoring tool. This application runs in the user session and connects to the service providing you information on whether the service is running and allowing you to stop and start the database service.
Since that application does run in a user session, you can interact with the desktop through that application.
You need to add serviceinstaller and write down below code in commited event of serviceinstaller.
using System.Management;
using System.ComponentModel;
using System.Configuration.Install;
private void serviceInstaller1_Committed(object sender, InstallEventArgs e)
{
ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope mgmtScope = new ManagementScope(#"root\CIMV2", coOptions);
mgmtScope.Connect();
ManagementObject wmiService;
wmiService = new ManagementObject("Win32_Service.Name='" + serviceInstaller1.ServiceName + "'");
ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", InParam, null);
}
Related
I want to implement an update service in my application (so users don't need admin rights to update my app once the service is installed, much like Google or Mozilla do their updates), and I think I found a good way to do this with WCF.
I have a WCFServiceLibrary-Project which contains the ServiceContract and the core functionality (download/install updates) and a Windows Service-Project which implements the WCFServiceLibrary as a Windows Service.
Additionally, there is a Visual Studio Installer-Project which installs the service and my application, which should be able to start/stop/communicate with the service using NamedPipes.
The service is configured to start manually with the LocalSystem-Account.
Now when the service is installed, I can start/stop it using services.msc (probably elevated), but not when I try it with net start Servicename (Error 5: Access denied) or with my application, which tells me that the local users probably don't have the permission to start/stop the service.
I need the service to run with higher permissions in order to perform the installation of updates, so I would like to give local users permission to start my service either during the first installation of the service or when the service starts for the first time (since I can trigger that also during installation).
However, how would I accomplish this with VB.NET (or C#)? I found some examples using API-Calls of advapi32.dll, but it didn't looks like the permission can be changed with this.
So, long story short, heres a summary of what I'm looking for:
Grant Group "Local Users" permission to Start my Service, best approach either during installation (Maybe with Custom Actions in Visual Studio Installer Project? Or in the ServiceInstaller-Class in the Windows Service-Project?) or the first time the service starts (OnStart-Event in Windows Service Project)
The service must not run with local user rights, since it would miss elevated privileges then which would be necessary to install updates.
I can't assign permissions through GPO/Local Policy since the users are not within our company, but all around the world. For the same reason I cannot assume that they can get an admin to elevate them everytime an update comes out.
I would like to avoid commandline calls if possible (as in assign permissions through command line, since those are most likely os-dependent)
Another solution would be to configure the Service as Automatic and Start it after install, but I don't like the idea that my service runs all the time since its only needed when my main application starts up.
Its most likely not a file permission issue. EVERYONE, SYSTEM and SERVICE got FULL ACCESS to the services folder and files in it.
There are already different similar questions here, but none did give a clear answer to this problem. One user probably did it using the WiX-Installer, but I would like to keep the Visual Studio Installer Project since it's pretty straight forward and easy to use.
After a bit more of googling and trying to find a "clean" solution, I've given up and using now Process.Start to execute sc.exe and set new Permissions after Installation.
Here's my ServiceInstaller-Class, for anyone curious:
[VB.NET]
Imports System.ComponentModel
Imports System.Configuration.Install
Imports System.ServiceProcess
<RunInstaller(True)>
Public Class SvcInstaller
Inherits Installer
Dim svcprocinst As ServiceProcessInstaller
Dim svcinst As ServiceInstaller
Public Sub New()
svcprocinst = New ServiceProcessInstaller
svcprocinst.Account = ServiceAccount.LocalSystem
svcinst = New ServiceInstaller
svcinst.ServiceName = "KrahMickeySvc"
svcinst.DisplayName = "Mickey-Service"
svcinst.Description = "This Service is used by KRAH Mickey for application updates and maintenance"
Installers.Add(svcprocinst)
Installers.Add(svcinst)
End Sub
Private Sub SvcInstaller_AfterInstall(sender As Object, e As InstallEventArgs) Handles Me.AfterInstall
'Set new permissions acc. to Security Descriptor Definition Language (SDDL)
'Source: https://blogs.msmvps.com/erikr/2007/09/26/set-permissions-on-a-specific-service-windows/
'Keeping the source DACL and just adding RP,WP and DT (Start/Stop/PauseContinue) to IU (Interactive User)
Dim DACLString As String = "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRCRPWPDT;;;IU)(A;;CCLCSWLOCRRC;;;SU)"
process.Start("sc.exe", $"sdset {svcinst.ServiceName} ""{DACLString}""")
End Sub
End Class
I have a windows service which I silent install using msiexec.exe and I am passing the username and password for the "Set Service Login"
The Service is successfully installing but upon Starting the service I am receiving "error 1069: The service did not start due to logon problems"my logon account is administrator and I have tested that when I manually install using the same msi file and start the service it is starting successfully, I am stuck and need some ideas and guidance of what I am missing.
here is my overriden method from Installer Class.
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
var userName = Context.Parameters["USERNAME"];
var password = Context.Parameters["PASSWORD"];
if (!string.IsNullOrWhiteSpace(userName) && userName.ToLower() != "admin")
{
CustomInstallerParameters customParameters = new CustomInstallerParameters(Context);
SaveCustomParametersInStateSaverDictionary(stateSaver, customParameters);
}
else
{
Context.Parameters.Remove("USERNAME");
Context.Parameters.Remove("PASSWORD");
}
}
TIA.
It appears that you are using a Visual Studio setup project, and most likely also using one of the TextBoxes dialogs to collect the input.
You can't silently pass these parameters on the command line because Visual Studio generates custom actions to clear them (and I don't know why). In a silent install Windows runs just the InstallExecuteSequence, and if you look in there with (for example) Orca you'll see custom actions such as "CustomTextA_SetProperty_EDIT1" that clear the values. To state the obvious, the values you currently get will be blank, and you could verify this by logging the values somewhere.
So a starting point to getting this to work is to use Orca to delete those custom action calls in the InstallExecuteSequence table.
After that, there is a potential problem that the values won't make it to your custom action because they are not secured, so in the Property table you'd need to add those property names to the SecureCustomProperties list, semi-colon delimited (EDIT1;EDIT2 and so on).
Visual Studio setup projects aren't good at any of this, and something like WiX would be better because no code is required to install, start or stop services, or configure them with an account.
Most likely, different decade, same problem.... (SeServiceLogonRight)
http://iswix.com/2008/09/22/different-year-same-problem/
FWIW, I wasn't a big WiX user yet back then (I was merely dabbling at that point) but there are some real gems in the comments from my Matthew Rowan. He is correct... all of this gets WAY easier if you are using WiX.
For example you can follow this tutorial:
https://github.com/iswix-llc/iswix-tutorials
This creates a windows service running as SYSTEM. Add a reference to the WiXUtil extension and namespace and author a User element with the LogonAsService right set and your all set.
FWIW, my only concern with all this is that MSI needs property persistence if you don't want a repair to come by and corrupt the username and password. Property persistence is pretty easy to remember ( See: http://robmensching.com/blog/posts/2010/5/2/the-wix-toolsets-remember-property-pattern/ ) but the problem is providing enough encryption to not expose the account.
It's for the reason I typically suggest just running as NetworkService or SYSTEM and grant the computer object rights in a domain. An alternative is to have the installer create the service account and randomize the password on each repair so you don't have to persist it.
I'm currently developing a windows service with c# and .net framework 4.5 to extend the functionality of an existing propietary application, this service blocks on an EventWaitHandleClass (msdn link) waiting for a named event signaled from the main application. Something like this:
bool boolWithFalse = false;
string eName = "notification_event";
string usr = Environment.UserDomainName + "\\" + Environment.UserName;
EventWaitHandleSecurity security = new EventWaitHandleSecurity(); //*
EventWaitHandleAccessRule rule = new EventWaitHandleAccessRule(usr, EventWaitHandleRights.Synchronize, AccessControlType.Allow);
security.AddAccessRule(rule);
EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.ManualReset, eName, out boolWithFalse, security);
//... some non relevant code lines here
//This is where the it locks waiting for the named event
var w = EventWaitHandle.WaitAny(new[] { handle }, Timeout.Infinite);
*: EventWaitHandleSecurity MSDN
Now this works like a charm if i execute my program as a console application, i can easily catch events from the main application and handle them as i intend, BUT, when i install the application as a service it locks waiting for this same named event but never receive the signal. The service is set to run using the NT AUTHORITY\LOCALSERVICE account, i've already tried using my own account (wich the progam uses while running as a console application) and yet nothing happens.
If it helps the application that originates the signal is running under my own account. I appreciate any help as i'm a complete beginner developing desktop applications for windows.
You got lost in the security hoopla. Two problems. The first one is that somebody has to create the event and somebody else has to open it so both components share the same event object. One of them has to use the EventWaitHandle constructor, the other has to call the EventWaitHandle.OpenExisting() method. The normal way is for the service to create the event and for the UI program to open it.
Next problem is the event object visibility. Windows implements namespaces for named operating system objects, pretty similar to how you use namespaces in the C# language. The root namespace is named by the session. And a service runs in a different session than the user's desktop programs. To get the desktop session program to see the event created in the service session, you have to use a "global" event name. Which looks like this:
string eName = "Global\\notification_event";
Do be careful of how you name your globally visible named event. There's another programmer somewhere someday that thinks that "notification_event" is a good choice for a name. You don't want to meet him. A {guid} is a good name, you get one from Tools + Create GUID. It is unique in the known universe, possibly beyond.
I am writing a windows service that occasionaly has to renew IP address of the system and It would call ipconfig /renew to do it.
The code is going to look like this
Process ipconfigProcess = new Process();
ipconfigProcess.StartInfo.FileName = "ipconfig";
ipconfigProcess.StartInfo.Arguments = " /renew";
ipconfigProcess.StartInfo.UseShellExecute = false;
ipconfigProcess.StartInfo.RedirectStandardOutput = true;
ipconfigProcess.Start();
strOutput = compiler.StandardOutput.ReadToEnd();
ipconfigProcess.WaitForExit();
I suppose a windows service is not allowed to show windows/dialogs. So my question is whether renewing ip as above would be a problem in windows service because it may or may not show a console to run ipconfig ?
I think the only issue you're going to face is that of permissions - you should have no problem running a process like this (as long as you don't want to interact with any kind of UI), but your windows service needs to run as an account that will be able to spawn a process and execute ipconfig.
This does not require an instance of cmd.exe. Many command line applications are used in this manner.
A service can use GUI functions and/or create a console. Windows creates a dummy display surface to draw on as necessary. (Obviously, this dummy surface can't interact with the user.)
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).