Learn What IT Pros Need to Know About Windows 11 - August 24th at 1 PM ET! Learn What IT Pros Need to Know About Windows 11 - August 24th at 1 PM ET!

Creating Active Directory User Accounts with ADSI and PowerShell

I hope you have been enjoying our exploration of PowerShell Active Directory alternatives. Certainly, the Active Directory module from RSAT is the way to go but sometimes you may want a bit more control. You also may have a need to roll your own tools. Today, I want to give you some ideas on how to create user accounts using LDAP and ADSI. If you are just jumping in, I recommend you take a few minutes to get caught up with the previous articles:



Sponsored Content

Read the Best Personal and Business Tech without Ads

Staying updated on what is happening in the technology sector is important to your career and your personal life but ads can make reading news, distracting. With Thurrott Premium, you can enjoy the best coverage in tech without the annoying ads.





The first thing you will need is an ADSI reference to the organizational unit or container.

[ADSI]$OU = "LDAP://OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local"

I want to create a user account for a new hire, Ginger Snaps. I will do this with the Create() method on the OU object. This method needs an object type and a canonical name. Be sure to save the results to a variable because you will need it.
$new = $OU.Create("user","CN=Ginger Snaps")

Right now, this account only exists locally. The first property to set is the account name. This is a new object, which means we need to use the Put() method.

You can also use the InvokeSet() method.

Even though I will be setting additional properties, I need to commit the account to Active Directory before going any further.

Don’t worry. The account is disabled by default and does not have a password. So let’s set those things now.

If you want to disable the account, do not set it to this or 546. You can define a new password and configure the account. The user will have to change the password at next login.
#set initial password
$new.setpassword("[email protected]")

#force change at next logon

All of these changes are with the local cached copy of the user account. While I am at it, I might as well set some additional user properties.
$new.put("UserPrincipalName","[email protected]")
$new.put("DisplayName","Ginger Snaps")
$new.put("Title","PowerShell Specialist")
$new.put("description","PowerShell/DevOps Team")

The tricky part is figuring out the LDAP property name. Some of them are not obvious. One thing you can do is use the AttributeEditor on a user account in Active Directory Users and Computers. I started a disabled dummy account and filled out all of the fields. Next, I used the Attribute Editor tab.

User Attribute Editor (Image Credit: Jeff Hicks)
User Attribute Editor (Image Credit: Jeff Hicks)

If you do not see this, make sure you have checked the Advanced Features under the View menu.

Do not forget to commit the changes one more time.


As soon as replication converges, I can see the new account.

Verify the new account (Image Credit: Jeff Hicks)
Verify the New Account (Image Credit: Jeff Hicks)

Deleting an account is even easier. Invoke the Delete method on the OU or container object.

$OU.Delete("user","CN=Ginger Snaps")

Be careful. The deletion is immediate and there is no -WhatIf support.

Of course, this would be much easier with some sort of tooling like a function. You could write a version of New-ADUser customized to your environment with different parameters for the different user properties. I wrote something a bit more flexible.

Function New-LDAPUser {
[parameter(Position = 0, Mandatory)]
[string]$DefaultPassword = "[email protected]",
[string]$OU = "OU=Employees,DC=Globomantics,DC=Local",

#try to get the OU
[ADSI]$Parent = "LDAP://$OU"

#verify the OU exists
if (-Not $parent.distinguishedname) {
    Write-Warning "Can't find  OU $OU"
    #bail out

#split name into two variables
$firstname,$lastname = $name.split()

#define samaccountname
$sam = "{0}{1}" -f $firstname[0],$lastname
Write-Verbose "Testing if $sam already exists in the domain"

#test if name already exists in the domain
[ADSI]$Test = "WinNT://$($env:userdomain)/$sam,user"
If ($test.ADSPath) {
    Write-Warning "A user with the account name of $sam already exists"
    #bail out

Write-Verbose "Creating new user $Name in $OU"

$new = $parent.Create("user","CN=$Name")

Write-Verbose "Setting name properties"
$new.put("userprincipalname","[email protected]")

if ($hash) {
    Write-Verbose "Setting additional properties"
    foreach ($key in $hash.keys) {
        Write-Verbose "...$key"
        #verify property is valid
        Try {
        Catch {
            Write-Warning "$key is not a valid property name"

Write-Verbose "set initial password"
$new.setpassword("[email protected]")

Write-Verbose "force change at next logon"

if ($Disable) {
    Write-Verbose "Disabling the account"
else {

Write-Verbose "committing changes"

if ($Passthru) {

} #end function

This version does not include support for WhatIf but you could add it. The function needs the distinguishedname for the parent container and the user’s name. I am using simple names such as John Deere. The samAccountname is derived from the first initial of both the first and last name. I have a code that creates it from the username, which I have split.
#split name into two variables
$firstname,$lastname = $name.split()
#define samaccountname
$sam = "{0}{1}" -f $firstname[0],$lastname

Of course, you would need to define your own standard code. I have included some validation to ensure a valid OU without a naming conflict. This version simply reports any of these problems and bails out.

Otherwise, the function uses the steps I outlined above to create and define a user account.

Creating a new user (Image Credit: Jeff Hicks)
Creating a New User (Image Credit: Jeff Hicks)

Here is the account in ADUC:

The new account (Image Credit: Jeff Hicks)
The New Account (Image Credit: Jeff Hicks)

The other feature in this function is that it accepts a hashtable of LDAP property names and values.

[email protected]{
Company = "globomantics"
Department = "IT"
Title = "DevOps Engineer"
Description = "Project Phoenix"
PhysicalDeliveryOfficeName = "QK-456"
phone = "x8732"

The function processes this hashtable and sets the value for each entry, assuming it is valid. I use the InvokeGet() method, which will throw an error with an invalid property. I can create a richer user account.
New-LDAPUser -Name "Ken Dew" -OU "OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=local" -Properties $hash -Passthru -Verbose

Creating a rich user object (Image Credit: Jeff Hicks)
Creating a Rich User Object (Image Credit: Jeff Hicks)

Understanding the ADSI basics is key. It is not that difficult to build custom AD tooling for your environment that does not rely on RSAT. Next time, we will turn our attention to managing groups and group membership with ADSI and PowerShell.

Related Topics:


Don't have a login but want to join the conversation? Sign up for a Petri Account

Comments (0)

Leave a Reply

Register for Advanced Microsoft 365 Day!

GET-IT: Advanced Microsoft 365 1-Day Virtual Conference - Live August 24th!

Join us on Tuesday, August 24th and hear from Microsoft MVPs and industry experts about how to take advantage of Microsoft 365 at a technical level and dive deep into the features and functionality that will make your environment more secure and compliant.


Sponsored By