Posted On March 11, 2021

PowerShell: Update CSV File Using Active Directory

kimconnect 0 comments
blog.KimConnect.com >> Codes , Windows >> PowerShell: Update CSV File Using Active Directory
# adAccountsCsvUpdate.ps1

$originalCsv='C:\Users\rambo\Desktop\kimconnectUsers.csv'
$newCsv='C:\Users\rambo\Desktop\kimconnectUsers-processed.csv'
$newEmailSuffix='@kimconnect.com'
$newOu='OU=Test,DC=kimconnect,DC=com'

function adAccountsCsvUpdate{
  param(
    $originalCsv,
    $newCsv,
    $newEmailSuffix,
    $newOu
  )

  function generateRandomPassword{
    param(
        $minLength = 10,
        $maxLength = 16,
        $nonAlphaChars = 2,
        $excludeRegex='[:\$\%\&\,]',
        $replaceExclusionWith=@(';','!','/','{','^','+','-','*','_')
    )
    add-type -AssemblyName System.Web
    $randomLength = Get-Random -Minimum $minLength -Maximum $maxLength   
    $randomPassword = [System.Web.Security.Membership]::GeneratePassword($randomLength, $nonAlphaChars)
    $sanitizedPassword = $randomPassword -replace $excludeRegex,"$(Get-Random -InputObject $replaceExclusionWith)"
    $fixedRepeating = .{$rebuiltString=''
                        for ($i=0;$i -lt $sanitizedPassword.length;$i++){
                        $previousChar=$sanitizedPassword[$i-1]
                        $thisChar=$sanitizedPassword[$i]
                        $nextChar=$sanitizedPassword[$i+1]
                        if($thisChar -eq $nextChar){
                            do{
                                $regenChar=[char](Get-Random (65..122) )
                                }until($regenChar -ne $previousChar -and $regenChar -ne $nextChar)
                            $rebuiltString+=$regenChar
                            }
                        else{$rebuiltString+=$thisChar}
                        }
                        return $rebuiltString
                        }
                             
    return $fixedRepeating
  }

  $csvContents=import-csv $originalCsv
  write-host "Pulling existing records from Active Directory of $env:USERDNSDOMAIN..."
  $allExistingUsers=get-aduser -Filter * -property SamAccountName,GivenName,sn,EmailAddress,Department,Description,telephoneNumber,Title,Manager,ManagedBy,City,State,postalCode,Enabled

  write-host "First pass: newSamAccountName"
  $firstPass=@()
  $count=$csvContents.count
  $itemIndex=0
  foreach ($row in $csvContents){
    $samAccountName=$row.SamAccountName
    $firstName=$row.GivenName
    $lastName=$row.Surname
    #$userPrincipalName=$row.UserPrincipalName
    $itemIndex++
    write-host "Processing $itemIndex of $count`: $samAccountName..."
    $newSamAccountName=.{
      # Default: return NULL if account already exists
      # $matchedEmail=$allExistingUsers|?{$_.EmailAddress -eq $userPrincipalName}
      # if($matchedEmail){
      #   return $null
      # }

      # Method 1: check to determine whether there are not duplicating records
      $matchedSam=$allExistingUsers|?{$_.SamAccountName -eq $samAccountName}
      if(!$matchedSam){
        return $samAccountName
      }
      # Method 1: testing firstname initials + lastname combinations
      for ($i=0;$i -lt $firstName.length;$i++){
        $testUsername=($firstName[0..$i] -join '')+$lastName
        if($testUserName -notin $allExistingUsers.SamAccountName){
          return $testUsername
        }
      }
      # Method 2: incrementing the username by a single digit
      for($i=1;$i -lt 11;$i++){
        $testUsername2=$samAccountName+$i
        if($testUserName2 -notin $allExistingUsers.SamAccountName){
          return $testUsername2
        }
      }
    }
    if($newSamAccountName -ne $samAccountName){
      write-host "SAM in CSV $samAccountName shall be updated as $newSamAccountName"
    }  
    $firstPass+=$row|select-object *,@{Name='newSamAccountName';Expression={$newSamAccountName}}
  }

  write-host "Second pass: newManagerSamAccount"
  $secondPass=@()
  foreach ($row in $firstPass){
    $manager=$row.Manager
    $firstName=[regex]::match($manager,'^(.+)\s(.+)').groups[1].Value
    $lastName=[regex]::match($manager,'^(.+)\s(.+)').groups[2].Value
    $matchedManagerSam=$firstPass|?{$_.GivenName -eq $firstName -and $_.Surname -eq $lastName}
    $newManagerSamAccount=.{      
      if($matchedManagerSam){
        return $matchedManagerSam.newSamAccountName
      }else{
        return $null
      }
    }
    if($newManagerSamAccount -ne $manager){
      write-host "Manager in CSV '$manager' shall be updated as '$newManagerSamAccount'"
    }
    $secondPass+=$row|select-object *,@{Name='newManagerSamAccount';Expression={$newManagerSamAccount}}
  }

  write-host "Third pass: adding new manager Distinguished Name paths..."
  $thirdPass=@()
  foreach ($row in $secondPass){
    $thisNewManagerSamAccount=$row.newManagerSamAccount   
    $newManagerDN=if($thisNewManagerSamAccount){
      $matchedRow=$secondPass|?{$_.newSamAccountName -eq $thisNewManagerSamAccount}
      $surName=$matchedRow.Surname
      $givenName=$matchedRow.GivenName
      "CN=$surName\, $givenName,"+$newOu
    }else{''}
    $thirdPass+=$row|select-object *,@{Name='newManagerDN';Expression={$newManagerDN}}
  }

  
  write-host "Forth pass: adding new email addresses..."
  $forthPass=@()
  foreach ($row in $thirdPass){
    $username=$row.newSamAccountName
    $forthPass+=$row|select-object *,@{Name='newEmailAddress';Expression={$username+$newEmailSuffix}}
  }  

  write-host "Fifth pass: generating new randomized passwords"
  $fifthPass=@()
  foreach ($row in $forthPass){
    $fifthPass+=$row|select-object *,@{Name='newPassword';Expression={[string](generateRandomPassword)}}
  }

  $newCsvContents=$fifthPass
  $conflictingUserNames=$newCsvContents|?{$_.SamAccountName -ne $_.newSamAccountName}
  write-host "There are $($conflictingUsernames.count) usernames that have conflicted with existing accounts in Active Directory. Hence, new account usernames would be modified to mitigate collisions."
  if(test-path $newCsv){remove-item $newCsv -force}
  if(!(test-path $(split-path $newCsv -parent))){mkdir $(split-path $newCsv -parent) -force}
  $oldHeaders='"'+$($csvContents[0].psobject.Properties.Name -join '","')+'"'
  $newHeaders=$oldHeaders+',"newSamAccountName","newManagerSamAccount","newManagerDN","newEmailAddress","newPassword"'
  Add-Content -Path $newCsv -Value $newHeaders
  $newCsvContents|Export-Csv $newCsv -NoTypeInformation -append
}

adAccountsCsvUpdate $originalCsvFile $newCsvFile $newEmailSuffix $newOu
$originalCsvFile='C:\temp\ActiveDirectoryUsers.csv'
$newCsvFile='C:\temp\ActiveDirectoryUsers_Updated.csv'

function updateRecordsUsingActiveDirectory($originalCsv,$newCsv){
  $csvContents=import-csv $originalCsv
  write-host "Pulling existing records from Active Directory of $env:USERDNSDOMAIN..."
  $allExistingUsers=get-aduser -Filter * -property SamAccountName,GivenName,sn,EmailAddress,Department,Description,telephoneNumber,Title,Manager,ManagedBy,City,State,postalCode,Enabled

  write-host "First pass: newSamAccountName"
  $firstPass=@()
  $count=$csvContents.count
  $itemIndex=0
  foreach ($row in $csvContents){
    $samAccountName=$row.SamAccountName
    $firstName=$row.GivenName
    $lastName=$row.sn
    $itemIndex++
    write-host "Processing $itemIndex of $count`: $samAccountName..."  
    $newSamAccountName=.{
      # Default if there are not duplicating records
      $matchedSam=$allExistingUsers|?{$_.SamAccountName -eq $samAccountName}
      if(!$matchedSam){
        return $samAccountName
      }
      # Method 1: testing firstname initials + lastname combinations
      for ($i=0;$i -lt $firstName.length;$i++){
        $testUsername=($firstName[0..$i] -join '')+$lastName
        if($testUserName -notin $allExistingUsers.SamAccountName){
          return $testUsername
        }
      }
      # Method 2: incrementing the username by a single digit
      for($i=1;$i -lt 11;$i++){
        $testUsername2=$samAccountName+$i
        if($testUserName2 -in $allExistingUsers.SamAccountName){
          return $testUsername2
        }      
      }
    }
    if($newSamAccountName -ne $samAccountName){
      write-host "SAM in CSV $samAccountName shall be updated as $newSamAccountName"
    }  
    $firstPass+=$row|select-object *,@{Name='newSamAccountName';Expression={$newSamAccountName}}
  }
  
  write-host "Second pass: newManagerSamAccount & newManagerDN"
  $secondPass=@()
  foreach ($row in $firstPass){
    $manager=.{if($row.Manager -notmatch '\s'){
        return $row.Manager
      }else{
        $managerArray=$row.Manager -split ' '
        $managerLastName=$managerArray[$managerArray.count-1]
        return $($row.Manager)[0]+$managerLastName
      }
    }
    $matchedManagerSam=$firstPass|?{$_.SamAccountName -eq $manager}
    $newManagerSamAccount=.{      
      if($matchedManagerSam){
        return $matchedManagerSam.newSamAccountName
      }else{
        return $null
      }
    }
    if($newManagerSamAccount -ne $manager){
      write-host "Manager in CSV '$manager' shall be updated as '$newManagerSamAccount'"
    }
    $newManagerDN=.{
      if($matchedManagerSam.OU){
        return "CN=$($matchedManagerSam.sn)\, $($matchedManagerSam.GivenName),"+$matchedManagerSam.OU
      }else{
        return "CN=$($row.sn)\, $($row.GivenName),"+$row.OU
      }
    }
    $secondPass+=$row|select-object *,@{Name='newManagerSamAccount';Expression={$newManagerSamAccount}},@{Name='newManagerDN';Expression={$newManagerDN}}
  }
  
  write-host "Third pass: generating new randomized passwords"
  $thirdPass=@()
  function generateRandomPassword{
    param(
        $minLength = 10,
        $maxLength = 16,
        $nonAlphaChars = 2,
        $excludeRegex='[:\$\%\&\,]',
        $replaceExclusionWith=@(',',';','!','/','{','^','+','-','*','_')
    )
    add-type -AssemblyName System.Web
    $randomLength = Get-Random -Minimum $minLength -Maximum $maxLength   
    $randomPassword = [System.Web.Security.Membership]::GeneratePassword($randomLength, $nonAlphaChars)
    $sanitizedPassword = $randomPassword -replace $excludeRegex,"$(Get-Random -InputObject $replaceExclusionWith)"
    $fixedRepeating = .{$rebuiltString=''
                        for ($i=0;$i -lt $sanitizedPassword.length;$i++){
                        $previousChar=$sanitizedPassword[$i-1]
                        $thisChar=$sanitizedPassword[$i]
                        $nextChar=$sanitizedPassword[$i+1]
                        if($thisChar -eq $nextChar){
                            do{
                                $regenChar=[char](Get-Random (65..122) )
                                }until($regenChar -ne $previousChar -and $regenChar -ne $nextChar)
                            $rebuiltString+=$regenChar
                            }
                        else{$rebuiltString+=$thisChar}
                        }
                        return $rebuiltString
                        }
                             
    return $fixedRepeating
  }

  foreach ($row in $secondPass){
    $thirdPass+=$row|select-object *,@{Name='newPassword';Expression={[string](generateRandomPassword)}}
  }

  $newCsvContents=$thirdPass
  $conflictingUserNames=$newCsvContents|?{$_.SamAccountName -ne $_.newSamAccountName}
  write-host "There are $($conflictingUsernames.count) usernames that have conflicted with existing accounts in Active Directory. Hence, new account usernames would be modified to mitigate collisions."
  if(test-path $newCsv){remove-item $newCsv -force}
  if(!(test-path $(split-path $newCsv -parent))){mkdir $(split-path $newCsv -parent) -force}
  $oldHeaders='"'+$($csvContents[0].psobject.Properties.Name -join '","')+'"'
  $newHeaders=$oldHeaders+',"newSamAccountName","newManagerSamAccount","newManagerDN","newPassword"'
  Add-Content -Path $newCsv -Value $newHeaders
  $newCsvContents|Export-Csv $newCsv -NoTypeInformation -append
}

updateRecordsUsingActiveDirectory $originalCsvFile $newCsvFile

Leave a Reply

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

Related Post

Great GPL Windows Admin Tools

1. Wireshark 2. amanda.org (backup server) 3. mailarchiva.com (mail backup) 4. http://rbac.codeplex.com (remote admin for Exchange servers) 5. Core Configurator, ,…

ASCII Characters

DEC OCT HEX Symbol HTML Number Description 32 040 20     Space 33 041…

Delegate Administration Priviledges to Junior Admins

View Current Delegated Permissions: MMC Concole >> View Advanced Features >> Right-click desired OU, Properties…