Import Users from a CSV File into Active Directory using PowerShell

Manipulating Active Directory objects programmatically isn’t anything new or exciting, however, I had to assist a client recently with a request where PowerShell was the preferred delivery method (normally I prefer to write managed code in one of the .NET languages).

Objectives

  1. Process a large input file (in CSV format)
  2. Edit existing user object with attributes from the file
  3. Assign manager attribute from the file

Approach

Importing a CSV file is dead simple in PowerShell:

Import-CSV $importfile

Where $importfile is a variable set to the path of the script. We create a loop that goes through each imported line by piping the import into ForEach-Object command:

Import-CSV $importfile | ForEach-Object {
     #do something here
}

To copy fields from the CSV file into variables, we access the properties of the imported object using “this object” reference, $_ – like so:

$sam = $_.Users
$manager = $_.Manager
$location = $_.Location
$company = $_.Company
$department = $_.Department

Where “Users”, “Manager”, “Location”, etc are names of the CSV columns contained in the first row of the CSV file.

Next, while in the ForEach-Object loop, we call Active Directory and set user properties using the following command: Set-ADUser.

Set-ADUser -Identity $sam department=$department

This command assumes that the user already exists in the directory, if your use case is different, for example you are not sure if the user exists, you could test the presence of the user object via Try/Catch block:

Try { $exists = Get-ADUser -LDAPFilter "(sAMAccountName=$sam)" }
Catch { }
If ($exists)
{
     Set-ADUser -Identity $sam department=$department
}

So the next issue, is that not all attributes of AD objects can be modified using this direct approach, like shown above with department attribute. Only commonly used attributes are accessible this way, as per Microsoft Set-ADUser documentation. Other attributes will need to be accessed using -Replace parameter. When supplying values to certain parameters, you have to test for nulls and ensure that new values you pass to -Replace are not nothing.

If ($location) { Set-ADUser -Identity $sam -Replace @{l=$location} }
If ($company) { Set-ADUser -Identity $sam -Replace @{company=$company} }

Finally, if you are working with special attributes that are stored as distinguishedName references to other objects (linked value attributes), you may have to call out to the directory to obtain the dn of the object being referred to. This is true of Manager, Reports, and MemberOf attributes. Here we need to also test that the object we are about to reference actually exists.

Try { $exists = Get-ADUser -LDAPFilter "(sAMAccountName=$manager)" }
Catch { }
If ($exists)
{
     Get-ADUser -Identity $sam | Set-ADUser -Manager $_.Manager
}

Import and Modify Existing Objects Script

Now let’s put the things above into a PowerShell script that imports a CSV file and updates attributes of user objects, that already exist in the directory.

Import-Module ActiveDirectory
$path = Split-Path -parent $MyInvocation.MyCommand.Definition

# ENSURE THAT IMPORT FILE IS IN THE SAME DIRECTORY AS THIS SCRIPT
#
$importfile = $path + "\sample.csv"
$logfile = $path + "\logfile.txt"
#
# DO NOT EDIT AFTER THIS LINE

Function ImportUsers
{
     Import-CSV $importfile | ForEach-Object {
          $sam = $_.Users.ToLower()
          $manager = $_.Manager
          $output = "User: " + $sam
     
     Try {
          $location = $_.Location 
          $company = $_.Company
          $department = $_.Department

          If ($location) { Set-ADUser -Identity $sam -Replace @{l=$location} }
          If ($department) { Set-ADUser -Identity $sam department=$department }
          If ($company) { Set-ADUser -Identity $sam -Replace @{company=$company} }

          If ($manager) {
               Try { $exists = Get-ADUser -LDAPFilter "(sAMAccountName=$manager)" }
               Catch { }
               If ($exists) {
                    Get-ADUser -Identity $sam | Set-ADUser -Manager $_.Manager
               }
          }

          $output + " updated successfully" | Out-File $logfile -append
     }

     Catch {
          $output + " update failed: " + $error[0].ToString() | Out-File $logfile -append
     }
     }
}

ImportUsers

Dump User Attributes Script

In some cases, it may be useful to write out the attributes you are about to mass-update. This could be handy in HR matters, or to have a paper record for change management purposes. Suppose that we have the same input CSV file as the one used in the import script above. In this script below, we import the contents of the input file, but only read the Users field. We then query Active Directory for presence of each user, and if the user is located, we write out the attributes into a separate text file.

Import-Module ActiveDirectory
$path = Split-Path -parent $MyInvocation.MyCommand.Definition 

# ENSURE THAT IMPORT FILE IS IN THE SAME DIRECTORY AS THIS SCRIPT
#
$importfile = $path + "\sample.csv"
$logfile = $path + "\logfile.txt"
$before = $path + "\before.txt"
#
# DO NOT EDIT AFTER THIS LINE

Function ImportUsers
{
     "users,company,department,location,manager" | Out-File $before -append

     Import-CSV $importfile | ForEach-Object {
          $sam = $_.Users

          Try {
               $u = Get-ADuser $sam -Properties samaccountname,department,city,company,manager 
               $u.samaccountname + "," + $u.company + "," + $u.department + "," + $u.city + "," + $u.manager | Out-File $before -append 
          }

          Catch {
               "Error: failed to process user " + $sam + " - " + $error[0].ToString() | Out-File $logfile -append
          }
     }
}

ImportUsers

Note how -Properties parameter is used in Get-ADUser commandlet to specify which attributes of the user object we want to load.

Import and Create New Active Directory Accounts Script

Suppose that we are still working with the same input file, but instead of editing existing user objects we need to create new ones.

Instead of Set-ADUser commandlet we will be using New-ADUser commandlet. Another twist in the script below is setting of a new temporary password. User objects can’t (or rather, should not) have blank passwords. Finally, when we create a new account, by default it will be created as disabled account; we override this by passing $True boolean value with -Enabled parameter.

$initialpassword = "some complex password"
$setpass = ConvertTo-SecureString -AsPlainText $initialpassword -force
 New-ADUser $sam -DisplayName $sam -Company $_.Company -Department $_.Department -City $_.Location -AccountPassword $setpass -Enabled:$True

In addition to setting of the account status and password, we may want to move the account to some target organizational unit (OU).

$location = "OU=Test,DC=corp,DC=domain,DC=com"
$dn = (Get-ADUser $sam).DistinguishedName
Move-ADObject -Identity $dn -TargetPath $location

That’s all there is to it. Now the full script:

Import-Module ActiveDirectory
$path = Split-Path -parent $MyInvocation.MyCommand.Definition 
$count = 0

# ENSURE THAT IMPORT FILE IS IN THE SAME DIRECTORY AS THIS SCRIPT
#
$importfile = $path + "\sample.csv"
$location = "OU=Test,DC=corp,DC=domain,DC=com"
$initialpassword = "some complex password"
$logfile = $path + "\logfile.txt"
#
# DO NOT EDIT AFTER THIS LINE

Function ImportUsers
{
Import-CSV $importfile | ForEach-Object {
     $sam = $_.Users.ToLower()
     $manager = $_.Manager.ToLower()
     $output = "User: " + $sam

     Try {
          $setpass = ConvertTo-SecureString -AsPlainText $initialpassword -force
          New-ADUser $sam -DisplayName $sam -Company $_.Company -Department $_.Department -City $_.Location -AccountPassword $setpass -Enabled:$True

          $dn = (Get-ADUser $sam).DistinguishedName
          Move-ADObject -Identity $dn -TargetPath $location

          Try { $exists = Get-ADUser -LDAPFilter "(sAMAccountName=$manager)" }
          Catch { }
          If ($exists)
          {
               Get-AdUser -Identity $sam | Set-AdUser -Manager $_.Manager
          }
          $output + " imported successfully" | Out-File $logfile -append 
     }

     Catch {
          $output + " failed to import: " + $error[0] | Out-File $logfile -append
     }
     }
}

ImportUsers

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *