Initial AD Bulk Loading of Random Users and propagating a NetIQ Identity Vault

Here is a method to populate an AD domain for a development environment. This document also includes additional detail of using an AD driver to pull the data into the Identity Vault.

This could be used for any Identity Manager Solution. Most customers have Active Directory in their environment and so an AD driver/connector will be available regardless of the Identity Manager framework / technology.

This script was originally created by Helge Klein, https://helgeklein.com. I have modified the script some to help pull accounts into my Windows 2016 test domain. Please continue to give credit to Helge in referencing his name in any script you use.
Obtain the original script and associated files from: https://github.com/RobBridgeman/ADImporter

I did not find the Original script from Helge’s website and used the one from Rob Bridgeman.

Copy in the below script over the existing powershell script from Helge’s script. Modify the powershell script with your configuration parameters for your development domain controller. There may be syntax formatting issues with the copy and paste with comments spanning multiple lines. Review the data input logs to add or remove data that would conform to your environment. Set the number of users to create to your desired amount. Currently set to 50,000.

#Credit for original script to Helge Klein https://helgeklein.com.

#Adapted to allow higher numbers of users with the same information set.
#Modified to address some issues found.




# Summary of changes.

# Reduced Male and Female names into one list for ease of expansion

# Changed Displayname code to create each combination of names possible

# Changed sAMAccountname generation to add unique account ID with orgShortName as suffix.







# Known issues

# Usercount (For me anyway) seems to be inaccurate when import completes. May be related to errorcheck compensation when usercount is reduced. Consistently seem to get many more users that intended.







Set-StrictMode -Version 2




Import-Module ActiveDirectory

# Set the working directory to the script's directory

Push-Location (Split-Path ($MyInvocation.MyCommand.Path))

#

# Global variables

#

# User properties

$ou = "OU=Corporate,DC=NetIQ-DEV,DC=site"   # Which OU to create the user in

$initialPassword = "N3t!Q123"           # Initial password set for the user

$orgShortName = "NetIQ-DEV"    # This is used to build a user's sAMAccountName

$dnsDomain = "NetIQ-Dev.site"      # Domain is used for e-mail address and UPN

$company = "NetIQ-Dev co"      # Used for the user object's company attribute




$departments = (# Departments and associated job titles to assign to the users

                  @{"Name" = "Finance & Accounting"; Positions = ("Manager", "Accountant", "Data Entry")},

                  @{"Name" = "Human Resources"; Positions = ("Manager", "Administrator", "Officer", "Coordinator")},

                  @{"Name" = "Sales"; Positions = ("Manager", "Representative", "Consultant")},

                  @{"Name" = "Marketing"; Positions = ("Manager", "Coordinator", "Assistant", "Specialist")},

                  @{"Name" = "Engineering"; Positions = ("Manager", "Engineer", "Scientist")},

                  @{"Name" = "Consulting"; Positions = ("Manager", "Consultant")},

                  @{"Name" = "IT"; Positions = ("Manager", "Engineer", "Technician")},

                  @{"Name" = "Planning"; Positions = ("Manager", "Engineer")},

                  @{"Name" = "Contracts"; Positions = ("Manager", "Coordinator", "Clerk")},

                  @{"Name" = "Purchasing"; Positions = ("Manager", "Coordinator", "Clerk", "Purchaser")}

               )

$phoneCountryCodes = @{"GB" = "+44"} # Country codes used in the address file




# Other parameters

$userCount = 50000              # How many users to create

$locationCount = 5              # How many different offices locations to use




# Files used

$firstNameFile = "Firstnames.txt"            # Format: FirstName

$lastNameFile = "Lastnames.txt"              # Format: LastName

$addressFile = "Addresses.txt"  # Format: City,Street,State,PostalCode,Country

$postalAreaFile = "PostalAreaCode.txt"   # Format: PostalCode,PhoneAreaCode




#

# Read input files

#

$firstNames = Import-CSV $firstNameFile | select -ExpandProperty Firstname

$lastNames = Import-CSV $lastNameFile | select -ExpandProperty Lastname

$addresses = Import-CSV $addressFile

$postalAreaCodesTemp = Import-CSV $postalAreaFile




# Convert the postal & phone area code object list into a hash

$postalAreaCodes = @{}

foreach ($row in $postalAreaCodesTemp)

{

   $postalAreaCodes[$row.PostalCode] = $row.PhoneAreaCode

}

$postalAreaCodesTemp = $null




#

# Preparation

#

$securePassword = ConvertTo-SecureString -AsPlainText $initialPassword -Force




# Select the configured number of locations from the address list

$locations = @()

$addressIndexesUsed = @()

for ($i = 0; $i -lt $locationCount; $i++)

{

   # Determine a random address

   $addressIndex = -1

   do

   {

      $addressIndex = Get-Random -Minimum 0 -Maximum $addresses.Count

   } while ($addressIndexesUsed -contains $addressIndex)

   

   # Store the address in a location variable

   $street = $addresses[$addressIndex].Street

   $city = $addresses[$addressIndex].City

   $state = $addresses[$addressIndex].State

   $postalCode = $addresses[$addressIndex].PostalCode

   $country = $addresses[$addressIndex].Country

   $locations += @{"Street" = $street; "City" = $city; "State" = $state; "PostalCode" = $postalCode; "Country" = $country}

   

   # Do not use this address again

   $addressIndexesUsed += $addressIndex

}







#

# Create the users

#




#

# Randomly determine this user's properties

#

   

# Sex & name

for ($i = 0; $i -lt $userCount; $i++) 

    {

       $Fname = Get-Random -InputObject $firstNames -count 1

       $Lname = Get-Random -InputObject $lastNames -count 1




       $displayName = $Fname + " " + $Lname




       # Address

       $locationIndex = Get-Random -Minimum 0 -Maximum $locations.Count

       $street = $locations[$locationIndex].Street

       $city = $locations[$locationIndex].City

       $state = $locations[$locationIndex].State

       $postalCode = $locations[$locationIndex].PostalCode

       $country = $locations[$locationIndex].Country

   

       # Department & title

       $departmentIndex = Get-Random -Minimum 0 -Maximum $departments.Count

       $department = $departments[$departmentIndex].Name

       $title = $departments[$departmentIndex].Positions[$(Get-Random -Minimum 0 -Maximum $departments[$departmentIndex].Positions.Count)]




       # Phone number

       if (-not $phoneCountryCodes.ContainsKey($country))

       {

          "ERROR: No country code found for $country"

          continue

       }

       if (-not $postalAreaCodes.ContainsKey($postalCode))

       {

          "ERROR: No country code found for $country"

          continue

       }

       $officePhone = $phoneCountryCodes[$country] + "-" + $postalAreaCodes[$postalCode].Substring(1) + "-" + (Get-Random -Minimum 100000 -Maximum 1000000)

   

       # Build the sAMAccountName: $orgShortName + employee number

       $employeeNumber = Get-Random -Minimum 100000 -Maximum 1000000

       $sAMAccountName = $orgShortName + $employeeNumber

       $userExists = $false

       Try   { $userExists = Get-ADUser -LDAPFilter "(sAMAccountName=$sAMAccountName)" }

       Catch { }

       if ($userExists)

       {

          $i=$i-1

          if ($i -lt 0)

          {$i=0}

          continue

       }




       #

       # Create the user account

       #

          New-ADUser -SamAccountName $sAMAccountName -Name $displayName -Path $ou -AccountPassword $securePassword -Enabled $true -GivenName $Fname -Surname $Lname -DisplayName $displayName -EmailAddress "[email protected]$dnsDomain" -StreetAddress $street -City $city -PostalCode $postalCode -State $state -Country $country -UserPrincipalName "[email protected]$dnsDomain" -Company $company -Department $department -EmployeeNumber $employeeNumber -Title $title -OfficePhone $officePhone




       "Created user #" + ($i+1) + ", $displayName, $sAMAccountName, $title, $department, $street, $city"

       $i = $i+1

       $employeeNumber = $employeeNumber+1




       "User Count =" + ($userCount)




          if ($i -ge $userCount) 

       {

           "Script Complete. Exiting"

           exit

       }

}

AD Driver

Once your script works on creating accounts it will be easy to pull users into the Identity Vault with the AD driver. Modify the Publisher channel’s Matching NOVLADDCFG-pub-mp policy to disable the “veto out-of-scope events” rule. This will allow objects to not be entitled to have an association from the AD to eDirectory Publisher channel flow. If your AD environment will not be authoritative, re-enable this rule once your data is migrated. Last of all, migrate your data into the Identity Vault via iManager, or have the driver up and running when you create the users with the powershell script.

You can then modify the script to your needs. Use Apache Directory Studio to find similar objects and add a jobcode or other attributes that will be used for your business logic.

Benefits

• Your dev environment isn’t using real users or real domain names and emails, so email notifications or other processes are dissimilar to production and testing.

• You can have similar data that conforms to your business, but consultants and other entities don’t see your production like data in your dev environment.

• Your dev environment is setup fairly quickly with large amounts of users to large jobs.

• You have a script to continue to modify to conform to your needs. Once you have the script the way you want and satisfactory data, you could proceed with LDIF exports to bulk data in the future.

When considering your authoritative systems such as an HR database, it may be worth considering populating a dev database table as an initial HR simulated table, using a JDBC driver. Many times the source system, such as a HR connected system, will need time to be configured and tuned by the HR sysadmins. I have seen this take 1-3 months depending on the size of the environment and how the backend HR system is configured.

You may be able to do your own development and testing ahead of time with a separate dummy table to mimic how your data is planned to look in advance. Once you have the data imported from the Identity Vault to the dummy HR system, you could then populate your additional HR columns such as employee number, hire date, etc into the table and start building your logic on how that data will get into the identity vault, etc.

Use a different driver from the HR system so that prior associations are available, so that you have data that already exists in AD and the vault and you can simulate matching data from a new HR source system and how it matches data in your other systems.