Creating Service Accounts is an especially tedious process when we need to create a lot of those for different purposes, mainly driven by the least privilege access across environments, projects, deployments or simply different clients. So why don’t improve this? Let’s make it all more fun, efficient and less error-prone, so let’s automate it!
Let’s first specify that Active Directory since Windows Server 2008 R2 offered a better way to manage service accounts sometimes called virtual account or managed service accounts these are specific but these are specific one single computer/machine. There is a cmd-let to leverage that included in the ActiveDirectory module at the bottom of this page.
In this article, I’m referring to a Service Account that is effectively a special Domain User account under a Service Account OU with different properties or specific Group Policies applied.
What I found particularly useful it’s creating a spreadsheet of the required service accounts in a CSV (comma separated value) format and generate the password file using the bash utility of pwgen via WSL (Windows Subsystem for Linux) for example and use PowerShell to do the rest. If you want to generate a Complex and Random password with PowerShell have a look at my previous article.
This a simple service account list saved on a CSV File called “service_accounts.csv”, I will use it within my simple script.
Service Account List in a CSV file
This is the content of the service_accounts.csv:
samaccountname | password | description |
dev_sw_one | j4!!.3MtXyu{^h,L?;Ua | DEV sw one service account |
test_sw_one | W*VKR:<ajY9F`pJ;HRR* | TEST sw one service account |
prod_sw_one | 97[i,(^t}?+@dYsiH^m@ | PROD sw one service account |
Having a CSV file and the password stored in clear text it’s not ideal and it should never be used except for a temporary data source.
Indeed most of the password managers on the market will import new secrets from a CSV easily or by default so you can delete it afterwards or zeroing the file content once the user creation is successfully completed and when there is no need to keep that file anymore.
If you have already a list of secrets by client or project you should be able to export it with a CSV format from the password manager as well when needed. Microsoft Excel or Google Sheets can create and export CSV natively.
How to read CSV from PowerShell
To double-check the content simply use import-Csv cmdlet:
1 2 3 4 5 6 7 |
PS D:\Scripts> import-csv .\service_accounts.csv samaccountname password description -------------- -------- ----------- dev_swone j4!!.3MtXyu{^h,L?;Ua DEV sw one service account test_swone W*VKR:<ajY9F`pJ;HRR* TEST sw one service account prod_swone 97[i,(^t}?+@dYsiH^m@ PROD sw one service account |
New-ServiceAccount Function
Creating service accounts in Active Directory requires the ActiveDirectory module in Powershell that is installed on a Domain Controller or another windows server or windows client OS using RSAT (Remote Server Administration Toolkit).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#requires -module ActiveDirectory function New-ServiceAccount { Param ( [Parameter(Mandatory=$true)] [string] $samaccountname, [Parameter(Mandatory=$true)] [string] $description, [Parameter(Mandatory=$true)] [string] $password, [Parameter(Mandatory=$true)] [string] $destou ) $psw = convertto-securestring "$password" -asplaintext -force New-ADUser -Path $destou -Name "$samaccountname" -AccountPassword $psw -Enabled $true -AllowReversiblePasswordEncryption $false -CannotChangePassword $true -PasswordNeverExpires $true Write-Output "$samaccountname service account created in $destou" } |
Creating a Service Account is a trivial operation like creating a simple user, but what is key on service accounts creation is the Organizational Unit (OU) chosen and the password settings enabled “cannot change password”, “password never expires”.
Especially for Service Accounts I like to generate longer (stronger) passwords regardless of the settings. I don’t recommend to set the password to never expires to higher environments, but I suggest to use MSA (Managed Service Accounts) instead for PROD env.
E.G. From one of my labs (lab.local domain ) this OU is created for Service account (“OU=Service Accounts,DC=lab,DC=local”).
How to create service accounts from a CSV
I can parametrize on a specific variable the CSV and the OU where I will create my accounts.
1 2 |
$CSVFILEPATH = "D:\Scripts\service_accounts.csv" $DEST_OU="OU=Service Accounts,DC=lab,DC=local" |
as a common practice is always required to test the path if the file exists before trying to import the content to avoid unexpected errors
1 2 3 |
if ((Test-path ($CSVFILEPATH)) -eq $false){ throw "CSV FILE $CSVFILEPATH not found!" } |
Using a foreach loop to create a user at a time:
1 2 3 |
Foreach ($sa in $(import-csv -Path $CSVFILEPATH)){ New-ServiceAccount -samaccountname $sa.samaccountname -description $sa.description -password $sa.password -destou $DEST_OU } |
The same logic applies if you want to create Managed Service Accounts just replace New-ServiceAccount cmd-let with the New-ADServiceAccount.
To check the Service Account creation
1 2 |
#requires -module ActiveDirectory get-aduser -searchbase "OU=Service Accounts,DC=lab,DC=local" -filter * | select-object samaccountname |
I hope you’ll find this useful! As usual, you can find this script on my GitHub repository.
Managed Service Accounts and Virtual Accounts
Creates a new Active Directory managed service account or group managed service account object.
Managed Service Accounts
Managed service accounts in Windows Server 2008 R2 and Windows 7 are managed domain accounts that provide the following features to simplify service administration:
- Automatic password management.
-
Simplified SPN management, including delegation of management to other administrators. Additional automatic SPN management is available at the Windows Server 2008 R2 domain functional level. For more information, see “Requirements for using managed service accounts and virtual accounts” in this document.
Virtual Accounts
Virtual accounts in Windows Server 2008 R2 and Windows 7 are “managed local accounts” that provide the following features to simplify service administration:
- No password management is required.
-
The ability to access the network with a computer identity in a domain environment.
There is a cmd-let included in the ActiveDirectory module called New-ADServiceAccount.
Hi,
I got below error message. Would you be able to advise where is the problem?
New-ServiceAccount : Cannot process argument transformation on parameter ‘password’. Cannot convert the “Ddgp,Bs1`![!OM’L*%i=” value of type “System.String” to type “System.Security.SecureString”.
At C:\temp\PL_Wintel\New-Service-Accounts.ps1:33 char:98
+ … countname -description $sa.description -password $sa.password -destou …
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [New-ServiceAccount], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,New-ServiceAccount
Hi Piotr,
Thanks for your comment. It can be either an escape or a quote character or both that break/truncate the string variable. Try to avoid those and re-run the function.
You can add some break points using a debugger and see what the actual value is at runtime or simply break the function into steps and run line-by-line and check the password (String) and SecureString value once converted.
Please have also a look at this article on about SecureString objects: https://www.scriptinglibrary.com/languages/powershell/securestring-how-to-decode-it-with-powershell/
I hope this answered your question.
Thanks
Hi Paolo –
I got the script to work as a csv, but I had to take the “$psw = convertto-securestring” out of the function and put it into the loop. Could just be my environment. Maybe that will help someone. It worked great! thanks!
Hi Gary,
Thanks for your comment. As I’ve mentioned here if you use special characters such as “;” or “,” in your passwords you have few options to work around this if you are using a CSV File.
The only note to keep in mind if you choose to use a SecureString format pay attention of how you generate that SecureString object, in other words, if you pass a key you need to use it also to convert from or if you use the DPAPI you should be able to convert it back just under your user context.
This is the official doc page as a reference
Hey, just found this after trying to automate some AD credentials and had some major issues with the ConvertTo-SecureString.
The problem was that in my test I had a simple plain-text password, but it was already defined as a SecureString in the parameters, simply changing the parameter to “string” instead of “SecureString” allowed me to then convert the plaint-text regular string of “password” to a secure-string in processing.
Might help someone else out there running into the same problem!