I've been busting my brains for over two hours trying to accomplish a relatively simple task - changing the username and password of a currently running Windows Service. Should be trivial enough, but the managed ServiceController class doesn't give me that ability, so I had to resort to more esoteric solutions.
Assuming I wish to avoid direct registry manipulation - an easy enough choice to make - I can either P/Invoke the ChangeServiceConfig method (from advapi32.dll) or use System.Management and call the Win32_Service WMI class. I decided to use as little interop as possible and headed down the WMI path.
Now, Win32_Service doesn't have a property for the user password, which makes sense for security reasons. What I can do is invoke the Change method on it, passing it the username and password. Unfortunately, Change accepts 11 different parameters that can be changed, most of which I wish to leave untouched.
I tried using MgmtClassGen.exe to generate a strongly-typed wrapper around Win32_Service, but the Change method is created for me needed work - it asked for an ErrorControl parameter as a Byte, for instance, but the ErrorControl property was strongly typed as a String - I had to start tweaking the parameters myself, receiving strange exceptions and potentially modifying properties I didn't want to.
Most code samples I could find refer to VBscript, which can simply not pass the parameters it doesn't want, but C# isn't as flexible. Ultimately, though, I decided to simulate this approach by simply passing null for any parameters I want untouched. This requires me to work without the MgmtClassGen class, and invoke the Change method untyped, like this. I can't say it's code I'm especially proud of, but it gets the work done.
string objPath = string.Format("Win32_Service.Name='{0}'", serviceName);
using (ManagementObject service = new ManagementObject(new ManagementPath(objPath)))
{
object[] wmiParams = new object[11];
wmiParams[6] = username;
wmiParams[7] = password;
service.InvokeMethod("Change", wmiParams);
}