Directory Services

Changing the Password on a Service's User Account

For a service instance that logs on with a user account, rather than the LocalSystem account, the Service Control Manager (SCM) on the host computer stores the account password, which it uses to log on the service when the service starts up. As with any user account, you must change the password periodically to maintain security. When you change the password on a service account, update the password stored by the SCM. The following code example shows how to do both.

The code examples use IADsUser::SetPassword to set the account password. This method uses the distinguished name of the account. Then the sample opens a handle to the installed service on the specified host computer, and uses the ChangeServiceConfig function to update the password cached by the SCM. This function uses the SAM name (domain\username) of the account.

Note  This code must be executed by a domain administrator.

For a replicable service in which each replica uses a different logon account, you could update the passwords for all of the replicas by enumerating the service instances. For more information, and a code example, see Enumerating the Replicas of a Service.

DWORD UpdateAccountPassword(
		LPTSTR szServerDNS,   // DNS name of host computer
		LPTSTR szAccountDN,   // Distinguished name of service's logon account
		LPTSTR szServiceName, // Name of the service
		LPTSTR szOldPassword, // Old password
		LPTSTR szNewPassword  // New password
		)
{
SC_HANDLE schService = NULL;
SC_HANDLE schSCManager = NULL;
 
DWORD dwLen = MAX_PATH;
TCHAR szAccountPath[MAX_PATH];
IADsUser *pUser = NULL;
HRESULT hr;
 
DWORD dwStatus=0;
SC_LOCK sclLock = NULL; 

if(!szServerDNS || !szAccountDN || !szServiceName || !szOldPassword || 
   !szNewPassword)
{
	_tprintf(TEXT("Invalid parameter"));
	 goto cleanup;
}
 
// Set the password on the account.
// Use the distinguished name to bind to the account object.
_tcsncpy(szAccountPath, TEXT("LDAP://"), MAX_PATH);
_tcscat(szAccountPath, szAccountDN, MAX_PATH - _tcslen(szAccountPath));
hr = ADsGetObject(szAccountPath, IID_IADsUser, (void**)&pUser);
if (FAILED(hr)) {
	_tprintf(TEXT("Get IADsUser failed - 0x%x\n"), dwStatus = hr);
	 goto cleanup;
}
 
// Set the password on the account. 
hr = pUser->ChangePassword(CComBSTR(szOldPassword), CComBSTR(szNewPassword));
if (FAILED(hr)) {
	_tprintf(TEXT("ChangePassword failed - 0x%x\n"), dwStatus = hr);
	 goto cleanup;
}
 
// Update the account and password in the SCM database.
// Open the Service Control Manager on the specified computer.
schSCManager = OpenSCManager(
				szServerDNS, 		// DNS name of host computer
				NULL, 			 // database (NULL == default)
				SC_MANAGER_ALL_ACCESS   // access required
						);
if (! schSCManager) {
	_tprintf(TEXT("OpenSCManager failed - %d\n"), dwStatus = GetLastError());
	goto cleanup;
}
 
// Open a handle to the service instance.
schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
if (! schService) {
	_tprintf(TEXT("OpenService failed - %s\n"), dwStatus = GetLastError());
	goto cleanup;
}
 
// Get the SCM database lock before changing the password. 
sclLock = LockServiceDatabase(schSCManager); 
if (sclLock == NULL) {
	_tprintf(TEXT("LockServiceDatabase failed - %d\n"), dwStatus = GetLastError());
	goto cleanup;
}
 
// Set the account and password that the service uses at startup.
if (! ChangeServiceConfig( 
		schService, 	// Handle of service 
		SERVICE_NO_CHANGE, // Service type: no change 
		SERVICE_NO_CHANGE, // Change service start type 
		SERVICE_NO_CHANGE, // Error control: no change 
		NULL, 		// Binary path: no change 
		NULL, 		// Load order group: no change 
		NULL, 		// Tag ID: no change 
		NULL, 		// Dependencies: no change 
		NULL, 		// Account name: no change 
		szNewPassword,  // New password 
		NULL) ) { 	// Display name: no change
	_tprintf(TEXT("ChangeServiceConfig failed - %s\n"), dwStatus = GetLastError());
	goto cleanup;
}
_tprintf(TEXT("Password changed for service instance on: %s\n"), szServerDNS);
cleanup:
 
if (sclLock)
	UnlockServiceDatabase(sclLock); 
if (schService)
	CloseServiceHandle(schService);
if (schSCManager)
	CloseServiceHandle(schSCManager);
if (pUser)
	pUser->Release();
 
return dwStatus;
 
}