Nowadays it’s becoming a very common practice to frequently (half-yearly or quarterly) change password for all AD Service Accounts. It’s done as part of password compliance security guidelines, specially post GDPR implementations.
Earlier for BizTalk environments we use to have “Never Expire Password” for service account and used it to configure BizTalk Services (like Host Instances, ENTSSO & RuleEngineUpdateService), IIS App Pools or SQL Server Services. We also used BizTalk Service Account to configure multiple custom utilities for maintenance purpose as Windows Scheduled Tasks or as Windows Service.
Changing password manually for all these services, scheduled tasks and App Pools is very cumbersome and risky task. If we fail miss or mistype password even at one place, it may cause account lock issue and bring complete environment at halt.
Note – This problem can be addressed in BizTalk 2020 by using Group Managed Service Accounts as they don’t require Passwords.
Refer – What’s New in BizTalk Server 2020
Group Managed Service Accounts | Extend windows GMSA support to BizTalk operations and services. Using Group Managed Service Account |
To address this issue in, I have created Windows Application (works for all the version of BizTalk)
It takes three inputs –
- Servers (Comma Separated) => List of Servers where change is required. Ex – In a multi-server BizTalk Server, provide name of all the BizTalk App Servers
- Service Account => AD Account for which password needs to be changed
- New Password
Along with a Checkbox to select features which require change –
- Windows Services – Includes BizTalk Host Instances, ENTSSO, RuleEngineUpdateService, IIS and other custom services using this account
- IIS App Pools
- Scheduled Tasks – Configured with custom utilities
Along with a Checkbox to select features which require change –
- Windows Services– Includes BizTalk Host Instances, ENTSSO, RuleEngineUpdateService, IIS and other custom services using this account
- IIS App Pools
- Scheduled Tasks – Configured with custom utilities
Allowed Operations –
- Stop All Services – It acts as a “Pre-requisites/Prepare for change” step to bring down BizTalk Environment. It will STOP all the Host Instances – irrespective of service account, ENTSSO, RuleEngineUpdateService and IIS.
- Get List – It retrieves a list of all the services, app pools and scheduled task which are configured with given service account.
- Change Password – It changes password for all the services, app pools and scheduled task configured with given service account.
- START all Services – It acts as post change activity to bring BizTalk online by starting all the Host Instances, ENTSSO, RuleEngineUpdateService and IIS
You can choose to perform password change activity on all or any – Services, App Pools and Windows Scheduled Tasks.

Code Explanation –
- Windows Services – Getting and Updating password for the list of services configured for given service account.
I have used WMI Queries –
SELECT * FROM Win32_Service where StartName like '%<Service Account Name>%'
Sample Code to get the list –
string strWMINamespace = @"\\" + strServer + @"\root\cimv2";
if (strServiceAccount.Contains('\\'))
{
//If service account contains backslash it needs to be replaced by double backslash
strServiceAccount = strServiceAccount.Replace(@"\", @"\\");
}
//SELECT * FROM Win32_Service where StartName like '%<Service Account Name>%'
//Yields BizTalk Host Instances and ENTSSO
string strWMIQuery = @"SELECT * FROM Win32_Service where StartName like '%" + strServiceAccount + "%'";
//Create EnumerationOptions and run wql query
EnumerationOptions enumOptions = new EnumerationOptions();
enumOptions.ReturnImmediately = false;
using (ManagementObjectSearcher searchObject = new ManagementObjectSearcher(strWMINamespace, strWMIQuery, enumOptions))
{
//Enumerate through the result set and stop if not stopped and Change Password
foreach (ManagementObject service in searchObject.Get())
{
//Iterate over list of services and perform operation
//Updating the Password, refer - https://morgantechspace.com/2015/03/csharp-change-service-account-username-and-password.html#wmi
//Creating account object
object[] accountParams = new object[11];
//Updating Username for testing
//accountParams[6] = testUserName;
accountParams[7] = strNewPassword;
uint returnCode = (uint)service.InvokeMethod("Change", accountParams);
if (returnCode == 0)
{
updateLogs("Password changed successfully for service - " + service["Name"] + "");
}
}
}
2. IIS App Pools => Getting and updating password for list of App Pools configured using given service account.
using (ServerManager IISServerManager = ServerManager.OpenRemote(strServer))
{
foreach (ApplicationPool appPool in IISServerManager.ApplicationPools)
{
if (appPool.ProcessModel.UserName.ToLower().Contains(strServiceAccount))
{
updateLogs("Attempting to change password for App Pool - " + appPool.Name);
appPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
//Updating Username for testing
//appPool.ProcessModel.UserName = testUserName;
appPool.ProcessModel.Password = strNewPassword;
boolRequiresCommit = true;
}
}
if (boolRequiresCommit)
{
IISServerManager.CommitChanges();
updateLogs("Password changed successfully for App Pools");
}
}
3. Windows Scheduled Tasks => Getting and updating password for list of Windows Scheduled Tasks configured using given service account.
Microsoft.Win32.TaskScheduler.TaskService taskService = new TaskService(strServer);
foreach (Microsoft.Win32.TaskScheduler.Task task
in taskService.RootFolder.GetTasks().Where
(t => t.Definition.Principal.UserId.ToString().ToLower().Contains
(strServiceAccount.ToLower())))
{
//Disabling each task if it's enabled
if (task.State != TaskState.Disabled)
{
task.Stop();
task.Enabled = false;
}
string strRunAsCMD = @"/C schtasks.exe /CHANGE /S " + strServer + " /TN \"" + task.Name + "\" /RU " + strServiceAccount + " /RP " + strNewPassword + "";
updateLogs("Attempting to change password for task - " + task.Name + "");
executeCommand(strRunAsCMD);
updateLogs("Password changed successfully for task - " + task.Name + "");
}
//Code to Execute command in Windows Command Prompt
private void executeCommand(string strRunAsCMD)
{
var processInfo = new ProcessStartInfo("cmd.exe", strRunAsCMD);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.Verb = "runas";
var process = Process.Start(processInfo);
string strProcessOutput = process.StandardOutput.ReadToEnd();
string strProcessError = process.StandardError.ReadToEnd();
string logMsg = "executeCommand - Command Execution Completed with Exit Code : " + process.ExitCode.ToString() + Environment.NewLine;
if (String.IsNullOrEmpty(strProcessError))
{
logMsg += "Process Output - " + strProcessOutput;
}
else
{
logMsg += "Process Error - " + strProcessError;
}
updateLogs(logMsg);
process.WaitForExit();
//Checking if the process execution failed
if (process.ExitCode != 0)
{
updateLogs("executeCommand - Error occurred in execution." + Environment.NewLine + "Exit Code - " + process.ExitCode + Environment.NewLine +
"Process Error Output - " + strProcessError);
}
process.Close();
}
4. Starting/Stopping Host Instances
private async System.Threading.Tasks.Task stopOrStartAllHostInstances(HostAction hostAction)
{
try
{
//Create EnumerationOptions and run wql query
System.Management.EnumerationOptions enumOptions = new System.Management.EnumerationOptions();
enumOptions.ReturnImmediately = false;
//Search for all HostInstances of 'InProcess' type in the Biztalk namespace scope
System.Management.ManagementObjectSearcher searchObject =
new System.Management.ManagementObjectSearcher("root\\MicrosoftBizTalkServer",
"Select * from MSBTS_HostInstance Where HostType=1 And IsDisabled=False", enumOptions);
//Enumerate through the result set and stop each HostInstance if it is running
foreach (ManagementObject inst in searchObject.Get())
{
Task<string> task = new Task<string>(() => stopOrStartHostInstance(inst, hostAction));
task.Start();
updateLogs("Attempting to perform " + hostAction + " on HostInstance of Host: " + inst["HostName"] + " on Server: " + inst["RunningServer"] + "." + Environment.NewLine);
string status = await task;
updateLogs("Successfully performed " + hostAction + " action on " + inst["HostName"] + " on Server: " + inst["RunningServer"] + "." + Environment.NewLine + Environment.NewLine);
}
}
catch (Exception excep)
{
string strExceptionMessage = "Exception occurred in function-stopOrStartAllHostInstances. Message - " + excep.Message + Environment.NewLine + "StackTrace - " + excep.StackTrace;
throw new Exception(strExceptionMessage);
}
}
private string stopOrStartHostInstance(ManagementObject inst, HostAction hostAction)
{
try
{
if (hostAction == HostAction.STOP)
{
//Check if ServiceState is 'Started'
if (inst["ServiceState"].ToString() == "4")
{ inst.InvokeMethod("Stop", null); }
}
if (hostAction == HostAction.START)
{
if (inst["ServiceState"].ToString() == "1")//Status Stopped
{
inst.InvokeMethod("Start", null);
}
}
return "Success";
}
catch (Exception excep)
{
string strExceptionMessage = "Exception occurred in Function - stopOrStartHostInstance. Message - " + excep.Message + Environment.NewLine + "StackTrace - " + excep.StackTrace;
throw new Exception(strExceptionMessage);
}
}
5. Starting/Stopping Services
private async System.Threading.Tasks.Task stopORStartAdditionalServices(string strServerNames, ServiceAction serviceAction)
{
try
{
foreach (string strServerName in strServerNames.Split(','))
{
ServiceController[] scServices = ServiceController.GetServices(strServerName);
foreach (ServiceController service in scServices)
{
//Stopping/Starting IIS, RULEEngineUpdateService and ENTSSO services
if (service.ServiceName.ToUpper().Contains("W3SVC") || service.ServiceName.ToUpper().Contains("RULEENGINEUPDATESERVICE") || service.ServiceName.ToUpper().Contains("ENTSSO"))
{
Task<string> task = new Task<string>(() => stopOrStartService(service, serviceAction));
task.Start();
updateLogs("Attempting to " + serviceAction + " - " + service.DisplayName + " On Server - " + strServerName + Environment.NewLine);
string result = await task;
updateLogs("Successfully performed Action - " + serviceAction + " on Service - " + service.DisplayName + " On Server - " + strServerName + Environment.NewLine);
}
}
}
}
catch (Exception excep)
{
string strException = "Exception Occurred in function - stopORStartAdditionalServices. Message - " + excep.Message + Environment.NewLine + "Stack Trace - " + excep.StackTrace + Environment.NewLine;
throw new Exception(strException);
}
}
private string stopOrStartService(ServiceController service, ServiceAction serviceAction)
{
try
{
if ((serviceAction == ServiceAction.STOP) && (service.Status != ServiceControllerStatus.Stopped))
{
//stopping the service
service.Stop();
}
else if ((serviceAction == ServiceAction.START) && (service.Status == ServiceControllerStatus.Stopped))
{
//Starting the services
service.Start();
}
return "Success";
}
catch (Exception excep)
{
string strException = "Exception Occurred in function - stopOrStartService. Message - " + excep.Message + Environment.NewLine + "Stack Trace - " + excep.StackTrace + Environment.NewLine;
throw new Exception(strException);
}
}
Note – Post this password change activity we started getting error for BAM Portal
Configuration Error –
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: Could not create Windows user token from the credentials specified in the config file. Error from the operating system ‘The user name or password is incorrect.’
This error is bound to come and is explained in detail in below article –
Hope it’s helpful.
Download the complete code from here
Contact Me:-
@Gmail, @Facebook , @Twitter, @LinkedIn , @MSDNTechnet, @My Personal Blog
Contact Me –
Check out my other blogs –
Logic Apps Secure SQL Connection String in Azure Key Vault
While using SQL Connector in Logic Apps we don’t get a straightforward way to fetch/store connection string in Key Vault or in config. By default, the connection string we provide goes and sits in the Configurations as shown in the pics below and is in plaintext format. The regular process to use SQL Connector -…
Save Full File in SQL table Column (varbinary) and read the contents back in t
What if you needed to save full file as-is to a SQL Server table column. I ran into a similar scenario and had to save CSV Files in a table. For this we created a table with a column of type “varbinary” CREATE TABLE [dbo].[TableWithCompleteFiles]([SNo] [int] IDENTITY(1,1) NOT NULL,[FileName] varchar NULL,[FileContent] varbinary NULL) ON [PRIMARY]…
Export SQL Table content as CSV File to a File Location
Recently, I got a request to save the contents of the table to a File. Wroking Command – Above commands will fail with below error – Msg 15281, Level 16, State 1, Procedure xp_cmdshell, Line 1 [Batch Start Line 43]SQL Server blocked access to procedure ‘sys.xp_cmdshell’ of component ‘xp_cmdshell’ because this component is turned off…