Miscellaneous Debris

Avner Kashtan's Frustrations and Exultations
Setting Windows Service Account - C# and WMI

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);
}

Published Tuesday, May 08, 2007 10:54 AM by Avner Kashtan

Filed under: , , ,

Comments

# re: Setting Windows Service Account - C# and WMI@ Wednesday, May 23, 2007 10:24 AM

This came along just in time, and works like a charm. I had just gotten to the same point you did (hey, why are the properties not the same type as the Change parameters?).  I don't like using Invoke if I can avoid it, but you're right, it works. On to the next problem.

bschuth

# re: Setting Windows Service Account - C# and WMI@ Friday, June 15, 2007 4:30 PM

Same here, this came handy in the right time. Hope it works good.

pvsn

# re: Setting Windows Service Account - C# and WMI@ Friday, January 18, 2008 11:35 AM

I don't suppose there is an easy way to find the account of the service running? Like "Local System Account" versus the name of a specific user's domain account?

asbf

# re: Setting Windows Service Account - C# and WMI@ Friday, January 18, 2008 12:10 PM

This is the only way I can find to do it. Not very elegant.

string serviceName = "eventLog";

               System.Management.SelectQuery query = new System.Management.SelectQuery(string.Format("select name, startname from Win32_Service where name = '{0}'", serviceName));

               using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(query))

               {

                   foreach (System.Management.ManagementObject service in searcher.Get())

                   {

                       Console.WriteLine(string.Format("Name: {0} - Logon : {1} ", service["Name"], service["startname"]));

                   }

               }

asbf

# re: Setting Windows Service Account - C# and WMI@ Friday, January 18, 2008 1:37 PM

Ah, my original question didn't post. I wanted to know if there was a way to query the service account after the service was installed.

asbf

# re: Setting Windows Service Account - C# and WMI@ Thursday, February 21, 2008 5:36 PM

Just a note for anyone else using this code snippet.  To change to the system account, pass in "LocalSystem" and "" for username and password.  This might be obvious, but it took me a few guesses before I got it right.

See this article for other things you can do with this function:

msdn2.microsoft.com/.../aa384901(VS.85).aspx

Andy

# re: Setting Windows Service Account - C# and WMI@ Friday, February 22, 2008 5:32 AM

Brilliant - worked just as advertised.

Swordwolf

# re: Setting Windows Service Account - C# and WMI@ Thursday, May 08, 2008 5:07 PM

Thanks for the code. I am trying to change the user account of a windows service but could not get it to work. The code seems to run without exception but when i check the "Log on As" column of my service i don't see the new account set up. Am i missing anything here?

Jason

# re: Setting Windows Service Account - C# and WMI@ Thursday, July 10, 2008 9:23 PM

Thank you very much for the code.

I have spent hours looking for this solution. Hope it works fine...

Thanks a lot.

Bhargav

# re: Setting Windows Service Account - C# and WMI@ Wednesday, July 30, 2008 4:13 PM

Thanks! I'm just starting to learn how to become a "smarter" sys adm, and this greatly helped me!

Piffer

Leave a Comment

(required) 
(required) 
(optional)
(required)