Once a while, you will have a need to setup a new environment with new service accounts for all your apps/services. We all know, over time, those accounts in the current environments are added gradually one at a time. It would be nice if we can have a script to populate them and have a way to know what they are even.
So here you go, I created these Power Shell scripts to read the settings from a XML file and then create them into the domain AD. So from this point on, you can just maintain these XML config files for you various environments/domains. Easy to maintain, audit, and create a new one.
First, this is the XML file looks like. You can sure add more nodes/attributes to it to fit your needs.
<Env id="UAT"> <LDAPServer>MyLDAPServerName</LDAPServer> <OU>OU=Service Accounts,OU=MyOU,dc=uat,dc=MyDomain</OU> <Accounts> <Account id="ServiceAccount1"> <Description>Service Account for Service1</Description> <sAMAccountName>ServiceAccount1</sAMAccountName> <UserPrincipalName>ServiceAccount1@MyCompany.com</UserPrincipalName> <Password>MyPassword1</Password> </Account> <Account id="ServiceAccount2"> <Description>Service Account for Service2</Description> <sAMAccountName>ServiceAccount2</sAMAccountName> <UserPrincipalName>ServiceAccount1@MyCompany.com</UserPrincipalName> <Password>MyPassword2</Password> </Account> <Accounts> </Env>
Second, let’s create a PS file to do the creation
function SetupAServiceAccount ($ldapServer, $ou, $accountName, $sAMAccountName, $userPrincipalName, $accountPassword, $accountDescription) { ### There is a limitation of maximum length (20) of sAMAccountname. So we have to watch the error for it $errorDeviceNotFunctioning = 'Exception calling "SetInfo" with "0" argument(s): "A device attached to the system is not functioning.' ### Error for object (account) already exist. We will ignore it and proceed to update the account $errorObjectAlreadyExist = 'Exception calling "SetInfo" with "0" argument(s): "The object already exists.' ### Initialize variables $errorString = "" ### Get the AD object $objOU=[adsi]"LDAP://$ldapServer/$ou" ### Try to Create a new account $objUser = $objOU.Create("user", "cn=$accountName") $objUser.Put("sAMAccountName", $sAMAccountName) try { $objUser.SetInfo() $objUser="" write-host "*** Account Creation Success: $accountName ***" } catch { [string] $errorString = $_ } if ($errorString.Contains($errorDeviceNotFunctioning) -eq $True) { write-host "%%% Creation Unsuccess: $accountName - $errorString %%%" write-host "%%% The length of sAMAccountName cannot be more than 20 %%%" } elseif ($errorString.Contains($errorObjectAlreadyExist) -eq $True -Or $errorString -eq "") { if ($errorString.Contains($errorObjectAlreadyExist) -eq $True) { write-host "*** Account Alreday Exist, will update it instead ***" } if ($errorString -eq "") { write-host "*** Prepare to update ***" } $objUser=[adsi]"LDAP://$ldapServer/cn=$accountName,$ou" $objUser.SetPassword($accountPassword) $objUser.Put("pwdLastSet", -1) $objUser.Put("userPrincipalName", $userPrincipalName) $objUser.Put("description", $accountDescription) $objUser.Put("userAccountControl", 66048) try { $objUser.SetInfo() write-host "*** Update Success: $accountName ***" $objUser = "" & 'C:\Program Files (x86)\Windows Resource Kits\Tools\ntrights.exe' +r SeServiceLogonRight -u $userPrincipalName } catch { write-host "%%% Update Unsuccess: $accountName - $_ %%%" } } else { write-host "%%% Creation Unsuccess : $accountName - $errorString %%%" } }
Note: Here I used a tool called notrights.exe to grant the LogonAsService permission to those newly created accounts. It is a Microsoft tool and you can get it from here
Finally, we need to loop through the config file to run by the script we just created.
. ".\SetupAServiceAccount.ps1" ### Read the config XML $configFile = $args[0] [xml]$thisEnv = Get-Content $configFile ### Create a service account for each element in the xml file (under accounts) $ldapServer = $thisEnv.Env.LDAPServer $ou = $thisEnv.Env.OU $thisEnv.Env.Accounts.Account| foreach {SetupAServiceAccount $ldapServer $ou $_.id $_.sAMAccountName $_.UserPrincipalName $_.Password $_.Description}