Sunday, June 14, 2009

Scripting: Win32_Service – Change Account/Password

When using Win32_Service to change the service account and/or service account password the following needs to be understood.

StartName is an account name and not the name of the service which is Name for internal service short name and DisplayName for the full visible service name.  The account name MUST be specified when changing the password as it appears that both are always validated.  The only time a Null or empty password can be used is when setting the account to LocalService.  All unused arguments in VB or VBScript must be set to Null or you will get an error. 

Note that the account used must be an accessible account either local or AD and must have the "run as a service" permission or you will get an service account not valid error.  The password must be present but does not need to be correct as this is only checked on an account restart.  Restating the service will check the  password and use the new setting.  If you are just setting passwords then you will have a race condition.

It is more normal to create a new account with the new password and reset all services to the new account.  This will guarantee that you DO NOT have a race condition when setting multiple accounts as the old account can keep the old password until all services have been re-provisioned.

uploads/2491/WMIChangeService.vbs.txt

1 Function WMIChangeServiceAccount(sComputer,serviceName, account, password ) 2 Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sComputer & "\root\cimv2") 3 Set colServices = wmi.ExecQuery("Select * From Win32_Service Where Name = '" & serviceName & "'") 4 For Each oService in colServices 5 result = oService.Change(Null ,Null ,Null ,Null ,Null ,Null ,account , password) 6 If result <> 0 Then 7 Select Case result 8 Case 0 : msg = "Success" 9 Case 1 : msg = "Not Supported" 10 Case 2 : msg = "Access Denied" 11 Case 3 : msg = "Dependent Services Running" 12 Case 4 : msg = "Invalid Service Control" 13 Case 5 : msg = "Service Cannot Accept Control" 14 Case 6 : msg = "Service Not Active" 15 Case 7 : msg = "Service Request Timeout" 16 Case 8 : msg = "Unknown Failure" 17 Case 9 : msg = "Path Not Found" 18 Case 10 : msg = "Service Already Running" 19 Case 11 : msg = "Service Database Locked" 20 Case 12 : msg = "Service Dependency Deleted" 21 Case 13 : msg = "Service Dependency Failure" 22 Case 14 : msg = "Service Disabled" 23 Case 15 : msg = "Service Logon Failure" 24 Case 16 : msg = "Service Marked For Deletion" 25 Case 17 : msg = "Service No Thread" 26 Case 18 : msg = "Status Circular Dependency" 27 Case 19 : msg = "Status Duplicate Name" 28 Case 20 : msg = "Status Invalid Name" 29 Case 21 : msg = "Status Invalid Parameter" 30 Case 22 : msg = "Status Invalid Service Account" 31 Case 23 : msg = "Status Service Exists" 32 Case 24 : msg = "Service Already Paused" 33 Case Else : msg = "Not defined" 34 End Select 35 Wscript.StdErr.WriteLine "WMIChangeServiceAccount failed:" & msg 36 End If 37 Next 38 End Function 39 40 WMIChangeServiceAccount ".", "Browser", "domain\account", "newpassword" 41 42

"Browser" is the name of the service.  The display name is "Computer Browser".  These names are not interchangeable.  "Name" required the internal short name of the service.  You can change the code to use "DisplayName" as the filter.

PowerShell is much better for WMI as it can let us view elements quickly at the command line.

gwmi win32_service
will get all of the installed services
gwmi win32_service | select name
will give us all internal service names
gwmi win32_service -filter "name like 'b%'"
will filter all names that have "b" as a first letter.

Try this with vbscript of CMD.  It can be done but takes far longer to accomplish.

Here is the same password change coded in PowerShell:

gwmi win32_service -filter "name like 'bro%'"|%{$_.Change($null,$null,$null,$null,$null,$null,$null,"domain\account","newpw")}

The decode of the result could be added as an "Enum" extension to the PowerShell type system and we could also add a script to the class that would allow a method of "ChangePassword" that would just take a password.