As promised.  Not really much “new” going on here that hasn’t been done by others.  But maybe, just maybe, there’s a slim, microscopic, chance that it might help someone somewhere at sometime in some way.

It takes a CSV file with the first row being the names of Active Directory User object attributes, including Exchange 2016 and/or Skype for Business, extended attributes, as well as custom, glue-sniffing, kitty-litter munching, underwear over the head attributes.  You know, the kind you might find at a keg party.

I manually declare the list(s) of attributes to read form the CSV input and apply to the user accounts.  The reason for this is I want to selfishly take control of the bus and steer it directly into the mountainside.  No, seriously, it’s because the input file might contain bogus attribute names, and I’d rather not lean on exception handling due to performance overhead.

For example, allowing all mushroom-chomping hallucinated attributes in the bar entrance, while the bouncer plays with his/her phone, with 100,000 users, slows the processing down by about 20-25% on a good day.  White-listing them, (having the bouncer taser them with some Krav Maga and a set of steak knives, at the door and piling their bodies on a wheelbarrow) cuts that margin out entirely.  Geez.  I’ve been watching the wrong movies for too long.

Anyhow, here goes…

Imports AD user accounts from a CSV input file. Accommodates custom
and extended attributes if requested.

Required: Full path and filename of CSV input file.

Note that the CSV input file must have the following...

1. The top row contains AD schema attribute names
2. One of the headings is "path" for the LDAP path where accounts will be created
3. No read-only attributes are specified (e.g. msExtendedAttribute20)

.\Import-ADUsers.ps1 -CsvFile ".\sad_angry_users.csv" -Verbose

Author =
Date = 01/13/2017
Version = 2017.01.13.01

User accepts any and all risk and liability 

param (
  [parameter(Mandatory=$True, Position=0)]
  [string] $CsvFile
$ErrorActionPreference = "Stop"
$startTime = Get-Date
$ScriptVer = "2017.01.13.01"

function New-RandomPassword {
  param (
    [parameter(Mandatory=$False)][int] $Length = 15
  Generate a random password of a given length.
  Optional: Length of password to generate (number of digits).
  Default: 15

  New-RandomPassword -Length 24

  thanks to

  $punc = 46..46
  $digits = 48..57
  $letters = 65..90 + 97..122
  $password = Get-Random -count $length `
    -Input ($punc + $digits + $letters) |
      % -Begin { $aa = $null } `
      -Process {$aa += [char]$_} `
      -End {$aa}
  return $password

function Update-ADUser {
  param (
    [string] $AttList
  Applies an array of attribute values to a specified AD user object.
  An object defined from Get-ADUser.
  An array obtained from one row in a CSV input file.
  A comma-delimited string that contains the names of AD user schema attributes to apply.

  Update-ADUser -User $user -DataRow $csvRow -AttList $atts

  foreach ($att in $AttList.Split(',')) {
    write-verbose "internal: att = $att"
    if (!($excluded.Contains($att))) {
      $v = $DataRow."$att"
      write-verbose "internal: value = $v"
      if ($($v.Trim()).Length -gt 0) {
        write-verbose "info: applying input: $att"
        write-verbose "info: value = $v"
        Set-ADUser $User -replace @{"$att"="$v"} -Confirm:$False
      else {
        write-verbose "info: ignoring null input: $att"

write-output "info: script version $ScriptVer"

if (!(Test-Path $csvfile)) {
  write-host "error: $csvfile not found"
else {
  $rowcount = 0
  $excluded = ("name","path","samaccountname")
  write-verbose "info: reading input data file..."
  $csvData = Import-Csv -Path $csvfile
  foreach ($row in $csvData) {
    $upath = $row.Path
    $rpwd = New-RandomPassword -Length 24
    $sam = $row.sAMSccountName -replace "(?s)^.*\\", ""
    try {
      $user = Get-ADUser -Identity "$sam" -ErrorAction SilentlyContinue
      write-output "info: updating user: $sam"
    catch {
      $user = $null
      write-output "info: creating user: $sam"
      New-ADUser -Name "$sam" -SamAccountName "$sam" -Path $upath -AccountPassword (ConvertTo-SecureString $rpwd -AsPlainText -Force) -Enabled:$True
      $user = Get-ADUser -Identity "$sam"
    if ($user -eq $null) {
    # pathetic manual declaration of lonely attributes...
    $atts1 = "employeeid,displayName,title,telephoneNumber,mobile,"
    $atts1 += "physicalDeliveryOfficeName,mail,initials,Description,"
    $atts1 += "company,facsimileTelephoneNumber,department,co,l,manager,"
    $atts1 += "st,streetAddress,postalCode,sn,givenName,userPrincipalName,"
    $atts1 += "employeeType,pager,MailNickName,roomNumber,businessCategory,"
    $atts1 += "departmentnumber,otherTelephone,street,adminDescription,"
    $atts1 += "countryCode,initials,ipPhone,localeID,c,proxyaddresses"
    Update-ADUser $user $row $atts1

    write-verbose "info: exchange attributes..."

    $atts3 = "destinationIndicator,ExtensionAttribute1,ExtensionAttribute3,"
    $atts3 += "extensionattribute5,extensionattribute6,extensionattribute8,"
    $atts3 += "extensionattribute12,ExtensionName"
    Update-ADUser $user $row $atts3

    write-verbose "info: custom attributes..."

    $atts4 = "xlisprimary,xlacctcd,xlsublob,xlDvision,xlsubdivision,"
    $atts4 += "xlSubDivDescr,xlSection,xlSectionDescr,xlsubSection,xlsubSectionDescr"

    Update-ADUser $user $row $atts4

    $rowcount += 1
  write-host "info: completed $rowcount rows"
$StopTime = Get-Date
$RunTime= New-TimeSpan -Start $startTime -End $StopTime
write-host "info: runtime was $($RunTime.Seconds) seconds. You can make this faster! You must try!"



Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s