Changing Log On Credentials of Windows Services

There was a question from an internal group asking for a way to programmatically
change the log on name (and of course password) of a Windows service – this is the
user account, local or domain, under which the service process runs when started.
Unfortunately, the .NET framework does not provide any class to accomplish this.
You might be tempted to use System.ServiceProcess.ServiceProcessInstaller
class but it allows configuring log on details (via Username and Password properties)
only when installing a new Windows service, not for an already existing one. The
alternatives are WMI and P/Invoke. Here is the sample code:

WMI Version:


using System.Management; // Add reference to System.Management assembly
... ...
// Set SQL Server service to run as NETWORK SERVICE
ManagementObject mo = new ManagementObject("Win32_Service.Name='MSSQLSERVER'");

// 7th parameter is user name and 8th one is password

// Pass null for a parameter if the corresponding property setting shouldn't be changed
mo.InvokeMethod ("Change", new object[] {null, null, null, null, null, null, @"LocalSystem", null, null, null, null});

mo.Dispose();

You can change other settings such as display name, start mode, desktop interactivity, etc as well for a service process. Refer to the documentation of Win32_Service.Change() for more details.


P/Invoke Version:


using System.ServiceProcess;
using System.Runtime.InteropServices;
... ...
[DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool ChangeServiceConfig (SafeHandle hService, UInt32 nServiceType, UInt32 nStartType, UInt32 nErrorControl, String lpBinaryPathName, String lpLoadOrderGroup, IntPtr lpdwTagId, String lpDependencies, String lpServiceStartName, String lpPassword, String lpDisplayName);
private const uint SERVICE_NO_CHANGE = 0xffffffff;
... ...
ServiceController sc = new ServiceController ("MSSQLSERVER");
if (ChangeServiceConfig (sc.ServiceHandle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null,
@"NT AUTHORITY\Network Service", null, null))
{
    Console.WriteLine ("Service configuration changed successfully.", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
    Console.WriteLine ("Error changing service configuration. Win32 error code: " + Marshal.GetLastWin32Error().ToString());
}
sc.Dispose ();

You can find other service configuration settings that can be changed via this Win32 API here.


Couple of Comments: (1) Neither option will work if the calling user does not have the necessary rights to change service configuration details (2) The service should be restarted for the new settings to take effect – what this means is that if the password you supplied for the user name is incorrect, for example, you will not know this until the service is restarted!

Exception Message Box

A little-known component that comes with SQL Server 2005 is the exception message box (EMB) – I am sure you would have seen this anytime you work with SQL Server Management Studio (or Express).





It is almost a replacement for the standard message box (System.Windows.Forms.MessageBox) with the additional feature of displaying exceptions. It is a great UI component if you want to show detailed exception information (including inner/nested exceptions) to the end-user. What’s more – you can program almost every aspect of the exception message box: icon, number of buttons, button text, additional check box (remember ‘Do not show this message again’ option?) and much more.You can download the Exception Message Box from here.



A detailed how-to on EMB is also here.



Once installed, add a reference to Microsoft.ExceptionMessageBox.dll under [SYSDRIVE]:\Program Files\Microsoft SQL Server\90\SDK\Assemblies and you are all set to use it in your application. A simplest example is below:



using Microsoft.SqlServer.MessageBox;
... ...
try
{
}
catch (Exception xcp)
{
    ExceptionMessageBox emb = new ExceptionMessageBox (xcp);
    emb.Show();
}

A little customized exception message box:



ExceptionMessageBox emb = new ExceptionMessageBox (xcp);
emb.ShowCheckBox = true;
emb.Buttons = ExceptionMessageBoxButtons.OKCancel;
emb.CheckBoxText = "Do not show this message again";
emb.Symbol = ExceptionMessageBoxSymbol.Error;
emb.Show();

You can also have your own text for the buttons:



emb.Buttons = ExceptionMessageBoxButtons.Custom;
emb.SetButtonText ("Printer", "Clipboard", "File");

EMB redistributable (MSI package) is available with SQL Server 2005 SP1 which you can use to pack with your application.

Peformance Comparison: WCF Vs. The Rest

Excellent article comparing Windows Communication Foundation (WCF) framework with other Microsoft distributed technologies (ASP.NET Web Services, .NET Enterprise Services and .NET Remoting): http://msdn2.microsoft.com/en-us/library/bb310550.aspx