ImageForTitle

Powershell: Create User Accounts in Active Directory

Date: Febuary 8, 2021

Go To:

Summary
Cmdlet(s)
Details
Full Script Code

Summary:

Creating users in Active Directory is a very common task, but can be tedious to do manually. This led me to create this Object Oriented script which also supports parameters. This same object will be used in my other AD posts to allow you to add them together easily into one script. Main Cmdlet used will be New-ADUser.

Cmdlet(s):

New-AdUser
Used to create new users in active directory. Requires SamAccountName to be declared as a property, the rest are optional at the time
More info can be found on Microsoft's website: Microsoft Create Accounts


Details:

Parameters are first set to declare the main variables that we are going to be using. I'm a big fan of using Parameter in scripts, so I include them as often as possible. For creation of an account we will need the following inputs from the user: first/last name, and the group. The script will find the distinguished name of the group, the domain its in, and generate the username on its own.


  [CmdletBinding()]Param (

      $first = "",
      $last = "",
      $userName = "",
      $group = ""

  )
            

'Import-module activedirectory' is required to modify Active Directory in powershell. FYI this can be added by going to server manager >add feature > ad module for powershell. To allow the script to be run in different domains without modification, ‘longdomain’ finds the current domain and ‘shortdomain’ takes off the ‘.com’ at the end. If your domain doesn’t end in ‘.com’ then no worries, 'shortdomain' will just be set to the full domain.

here we also introduce the creation of the object we will be using of ‘employee’ and call it $userobj for this part of the script.
Modify $password to your default password. Later you'll see the script sets the password to be change at next logon.


   Import-Module ActiveDirectory
   $GLOBAL:longDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
   $GLOBAL:shortDomain = ($longDomain -replace '.com','')
   $userObj = [Employee]::New()
   $password = "TopSecret123!"
          

In ‘ouList’ list, replace the string values with your own OU’s, the numbers aren’t necessary but some people find them easier to use over having to type out the whole name. Now we ask the user for which group they want to add the user to. This will only be displayed if ‘group’ hasn’t been given as a param with the ‘if(!$group)’ statement. This is essentially saying if the group variable is null or empty perform this action.

‘ckey’ gets the value from the array that matches what the user inputs. This helps validate if the entry was properly spelled to reduce errors during account creation.


  #list of OUs in Active Directory
  $ouList = ("1 - Sales","2 - HR", "3 - IT", "4 - Accounting")

  Write-Output "Domain is set to: $longDomain"

  #get the OU if it wasn't given as a Parameter
  if (!$group){

     Write-Output "`nListing groups :" $ouList
     $group = Read-Host "`nEnter the OU for the user "
     }

  #grab the proper OU thats found in 'ouList'
  $ckey =""
  $ckey = $ouList | Where {$_ -match $group}
          

Let’s do a verification check to make sure ‘ckey’ is not actually empty. And if it is, then ask for the user to re-enter the value until ‘ckey’ has a value inside. To do this we’ll put it in a while loop with the condition of ‘!$ckey’ and as mentioned before this is saying to keep looping while 'ckey' is null or empty.

As you might have realized, ckey will have the array entry including the number, so we need to cut that off the first 4 characters like ‘1 - ‘ and only get the OU name. Note: If you did not include numbers in your ‘ouList’ array then remove the substring command.


  #have user renter OU if entry wasn't found in "ouList"
  while(!$ckey){
      $group = Read-Host "Entry did not match an OU. Re-Enter the OU"
      $ckey = $ouList | Where {$_ -match $group}
  }

  #cut off the numbers ex, '1 - Sales' will just be 'Sales'
  $ckey = $ckey.Substring(4)
  Write-Output "The chosen group is "$ckey
          

Nothing too fancy here, just ask for the first and last name if it wasn't given as a Parameter.


  #get first and last name if not provided as Param
  if(!$first){
      $first = Read-Host "`nEnter the FIRST name " }

  if(!$last){
      $last = Read-Host "Enter the LAST name " }
          

Now that we have all the values we need from the user, lets pass them to our object 'Employee'. We will see these varibles in a little bit when we declare them in the actual object.


  #Pass values to object
  $userObj.lastName = $last
  $userObj.firstName = $first
  $userObj.userGroup = $ckey
  $userObj.userPass = $password
          

The benefit of creating classes is we can create methods to do all the dirty work which allows the main code to look cleaner. So the first method we would like to do is generate a username/SamAccountName for when we create the account. Let’s name it ‘GetSamName’ and only call it if a username wasn’t given as a Parameter.


  #generate username if not given from Param
  if(!$userName){
      $userObj.GetSamName()}
  else{
      $userObj.SamName = $userName }

  Write-Output "Username will be " $userObj.SamName
          

For the last part of the main script, before we get to the object, we will call the method to create the account then clear the variables. This is helpful because sometimes they stay in cache and can cause problems if you run the script again since there’s logic that says do such and such if the variable is empty

Instead of just calling the method I want to put it in a try/catch statement which are great for error handling. If the 'try'block is successful then it will print the ‘success’ output and perform a Get-Aduser on the new account to print out its details. If there’s an error then it will go to the 'catch' block and display the ‘fail’ message and output the error with '$_'.


  try{
    $userObj.CreateAccount()
    Write-Output "SUCCESS: Account was created. Outputing Account info below:"
    Get-ADUser $userObj.SamName
  }
  catch{
    Write-Host "FAIL: account did not get created due to error below:" -ForegroundColor Red
    $_
  }

  clear-variable -Name last,first,password,group,username
          

Finally welcome to the object of 'Employee'. Declare the properties first, followed by the methods. Throughout the object I will refer to it's variables with variables of '$this'. For example, think of '$this.SamName' as 'Employee.SamName'.


  class Employee{
    [string]$lastName
    [string]$firstName
    [string]$userGroup
    [string]$SamName
    [string]$userPass
          

Here is our first method ‘GetSamName’ and we will set as a ‘void’ because we won’t be returning anything. Nodify this part to however your orginazation set's thier usernames. Here it takes the first name initial, period, first 6 characters of last name, and a number. So mine would be 'j.villar1' with this logic.


  [void]GetSamName(){

    if($this.lastName.Length -le 6){
        $length = $this.lastName.Length}
    else{
        $length = 6 }

    #generate next username available
    $start = $this.firstName[0] + "."
    $mid = $this.lastName.Substring(0,$length)
    $end = 1
    [string]$fullSam = $start + $mid + $end
          

While the username that we generate is taken, increase number at the end by 1 and check again. Repeat until a username is not taken. Then pass this back to the class property of ‘SamName’.


  #check Sam Account Name isn't take, if it is then add '1'
  while(([ADSISearcher] "SamAccountName=$fullSam").FindOne()){
      $end += 1
      [string]$fullSam = $start + $mid + $end
  }
  $this.SamName = $fullSam

  }
          

Now we get to the method that creates the account ‘CreateAccount’. It is also set as a ‘void’ since we aren’t returning any variables to the main script. It uses all the object's properties and finds the distinguished path to the group that user picked. ‘New-AdUser’ sets all the values which again can be customized to your liking. If you need to add the user to be a 'memberof' then uncomment the ‘Add-ADGroupMember’ command and replace '$PutGroupHere' with the group name.


  [void]CreateAccount(){
    #get group path
    $dPath = Get-ADOrganizationalUnit -Filter 'Name -eq $this.userGroup' |
             Select Name,DistinguishedName

    New-ADUser -SamAccountName $this.SamName `
       -GivenName $this.firstName `
       -SurName $this.lastName `
       -userPrincipalName ($this.SamName + "@" + $GLOBAL:longDomain) `
       -Path $dPath.DistinguishedName `
       -Name ($this.lastName + "," + $this.firstName) `
       -Enabled $true `
       -AccountPassword(ConvertTo-SecureString $this.userPass -AsPlainText -force) `
       -ChangePasswordAtLogon $true

    #add user to be member of
    #Add-ADGroupMember -Identity $PutGroupHere -Members $this.SamName
  }
          

Thanks for reading this article about creating users with Powershell while using objects!


Full Script Code:


  [CmdletBinding()]Param (

      $first = "",
      $last = "",
      $userName = "",
      $group = ""

  )

  Import-Module ActiveDirectory
  $GLOBAL:longDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
  $GLOBAL:shortDomain = ($longDomain -replace '.com','')
  $userObj = [Employee]::New()
  $password = "TopSecret123!"


  #list of OUs in Active Directory
  $ouList = ("1 - Sales","2 - HR", "3 - IT", "4 - Accounting")

  Write-Output "Domain is set to: $longDomain"

  #get the OU if it wasn't given as a Parameter
  if (!$group){

      Write-Output "`nListing groups :" $ouList
      $group = Read-Host "`nEnter the OU for the user "
    }

  #grab the proper OU thats found in 'ouList'
  $ckey =""
  $ckey = $ouList | Where {$_ -match $group}


  #have user renter OU if entry wasn't found in "ouList"
  while(!$ckey){
      $group = Read-Host "Entry did not match an OU. Re-Enter the OU"
      $ckey = $ouList | Where {$_ -match $group}
  }

  #cut off the numbers ex, '1 - Sales' will just be 'Sales'
  $ckey = $ckey.Substring(4)
  Write-Output "The chosen group is "$ckey

  #get first and last name if not provided as Param
  if(!$first){
      $first = Read-Host "`nEnter the FIRST name " }

  if(!$last){
      $last = Read-Host "Enter the LAST name " }

  #Pass values to object
  $userObj.lastName = $last
  $userObj.firstName = $first
  $userObj.userGroup = $ckey
  $userObj.userPass = $password

  #generate username if not given from Param
  if(!$userName){
      $userObj.GetSamName()}
  else{
      $userObj.SamName = $userName }

  Write-Output "Username will be " $userObj.SamName

  try{
      $userObj.CreateAccount()
      Write-Output "SUCCESS: Account was created. Outputing Account info below:"
      Get-ADUser $userObj.SamName
  }
  catch{
      Write-Host "FAIL: account did not get created due to error below:" -ForegroundColor Red
      $_
  }

  clear-variable -Name last,first,password,group,username

  ############CLASS###########
  class Employee{
    [string]$lastName
    [string]$firstName
    [string]$userGroup
    [string]$SamName
    [string]$userPass

    [void]GetSamName(){

      if($this.lastName.Length -le 6){
          $length = $this.lastName.Length}
      else{
          $length = 6 }

      #generate next username available
      $start = $this.firstName[0] + "."
      $mid = $this.lastName.Substring(0,$length)
      $end = 1

      [string]$fullSam = $start + $mid + $end

      #check Sam Account Name isn't take, if it is then add '1'
      while(([ADSISearcher] "SamAccountName=$fullSam").FindOne()){
          $end += 1
          [string]$fullSam = $start + $mid + $end
      }
      $this.SamName = $fullSam

    }

    [void]CreateAccount(){
      #get group path
      $dPath = Get-ADOrganizationalUnit -Filter 'Name -eq $this.userGroup' |
           Select Name,DistinguishedName

      New-ADUser -SamAccountName $this.SamName `
           -GivenName $this.firstName `
           -SurName $this.lastName `
           -userPrincipalName ($this.SamName + "@" + $GLOBAL:longDomain) `
           -Path $dPath.DistinguishedName `
           -Name ($this.lastName + "," + $this.firstName) `
           -Enabled $true `
           -AccountPassword(ConvertTo-SecureString $this.userPass -AsPlainText -force) `
           -ChangePasswordAtLogon $true

           #add user to be member of
           #Add-ADGroupMember -Identity $PutGroupHere -Members $this.SamName
    }

  }