# Create New Users: defined as names in CSV that does not exist in Existing Users records of Active Directory
$csvFile='C:\newUsers.csv'
$primaryEmailSuffix='@kimconnect.com'
$proxyEmailSuffix='@kimconnect.net'
$removeProxyEmailSuffix='@gmail.com'
$baseOu='CN=Users,DC=kimconnect,DC=com'
$companyName='Kim Connect'
$logFile="c:\temp\createActiveDirectoryAccounts-$(get-date -f yyyy-mm-dd-hh-mm-ss).txt"
function renameUser{
  $username='testAccount'
  $newName='test_Account'
  $distinquishedName=(get-aduser $username).DistinguishedName
  rename-adobject -identity $distinquishedName -NewName $newName
}
function createActiveDirectoryAccountsByOu{
  param(
    $csvFile,
    $baseOu,
    $companyName,
    $primaryEmailSuffix,
    $proxyEmailSuffix,
    $logFile
  )

  # Declare variables Log Files
  $failures = @()
  $usersAlreadyExist =@()
  $successes = @()
  $erroractionpreference = "Continue"

  write-host "Gathering Active Directory Users Information..."
  # Gather user accounts in a defined OU
  $existingUsers=get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,sn,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps
  $csvContents=import-csv $csvFile
  
  write-host "Checking whether there are any new users to be created."
  $usersToCreate=if($null -ne $existingUsers){
    $csvContents|?{$_.'First Name' -notin $existingUsers.Givenname -and $_.'Last Name' -notin $existingUsers.sn -and $_.'Last Name' -notin $existingUsers.EmailAddress}
  }else{
    $csvContents
  }

  if($usersToCreate){
    $allExistingUsers=Get-ADUser -Filter * -property SamAccountName,GivenName,sn,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps
    $voidChars='#N/A','',$null
    $ou=if($baseOu){$baseOu}else{
      $domainLdapExpression='DC='+((($env:USERDNSDOMAIN).tolower() -split '\.') -join ',DC=');
      'CN=Users,'+$domainLdapExpression
    }
  
    write-host "Commencing users creation..."
    foreach ($user in $usersToCreate) {
      $firstName=$user.'First Name'
      $lastName=$user.'Last Name'
      $emailAddress=$user.'Business Email'
      #$emailSuffix=[regex]::match($emailAddress,'@(.*)$').Captures.Groups[0].Value
      $newSamAccountName=.{          
        # Method 1: check to determine whether there are not duplicating records
        $testSamAccountName=$firstName[0]+$lastName
        $matchedSam=$allExistingUsers|?{$_.SamAccountName -eq $testSamAccountName}
        if(!$matchedSam){
          return $testSamAccountName
        }
        # Method 2: 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 3: incrementing the username by a single digit
        for($i=1;$i -lt 11;$i++){
          $testUsername2=$samAccountName+$i
          if($testUserName2 -notin $allExistingUsers.SamAccountName){
            return $testUsername2
          }
        }
      }
      $proxyEmailAddress=$newSamAccountName+$proxyEmailSuffix
      $proxyAddresses=if($emailAddress -eq $proxyEmailAddress){'SMTP:'+$emailAddress}else{@("SMTP:$emailAddress","smtp:$proxyEmailAddress")}
      $userExists=$emailAddress -in $allExistingUsers.EmailAddress -or $proxyEmailAddress -in $allExistingUsers.EmailAddress
      if(!$userExists){
        $jobTitle=if($user.'Business Title' -notin $voidChars){$user.'Business Title'}else{$null}
        $password = $user.newPassword | ConvertTo-SecureString -AsPlainText -Force
        $streetAddress=if($user.'Street 2' -notin $voidChars){$user.'Street 1'+', '+$user.'Street 2'}elseif($user.'Street 1' -notin $voidChars){$user.'Street 1'}else{$null}
        $city =if($user.City -notin $voidChars){$user.City}else{$null}
        $state =if($user.State -notin $voidChars){$user.State}else{$null}
        $postalCode=if($user.PostalCode -notin $voidChars){$user.PostalCode}else{$null}
        $country=if($user.Country -notin $voidChars){$user.Country}else{$null}      
        $telephone=if($user.telephoneNumber -notin $voidChars){$user.telephoneNumber}else{$null}
        $extension=if($user.Extension -notin $voidChars){$user.Extension}else{$null}
        $displayName=$lastName+', '+$firstName
        $newUserPrincipleName=$newSamAccountName+'@'+$env:USERDNSDOMAIN
        $employeeId=if($user.'File #' -notin $voidChars){$user.'File #'}else{$null}
        $userInitials=if($user.Initials -notin $voidChars){$user.Initials}else{$null}
        $description=if($user.description -notin $voidChars){$user.description}else{$null}
        $office=if($user.office -notin $voidChars){$user.office}else{$null}
        $managerDn=if($user.newManagerDN -notin $voidChars){$user.newManagerDN}else{$null}
        $department=if($user.Department -notin $voidChars){$user.Department}else{$null}
        $division=if($user.Division -notin $voidChars){$user.Division}else{$null}
  
        # Generating a hash table as a splatting technique
        $params = @{        
          SamAccountName = $newSamAccountName;
          Path = $ou;
          Enabled = $true;        
          AccountPassword = $password;
          ChangePasswordAtLogon = $False;
          EmployeeID = $employeeId;        
          GivenName = $firstName;
          Surname = $lastName;
          Name = $displayName;
          DisplayName = $displayName;
          UserPrincipalName = $newUserPrincipleName;
          Initials = $userInitials;
          Description = $description;    
          Office = $office;
          Title = $jobTitle
          Manager = $managerDn;
          Company = $companyName;
          Department = $department;
          Division = $division;
          StreetAddress = $streetAddress;
          EmailAddress = $emailAddress;
          City = $city
          State = $state
          PostalCode = $postalCode
          Country = $country
          OfficePhone = $telephone
          OtherAttributes = @{ 
              IPPhone = $extension;
              proxyAddresses = $proxyAddresses;
              proxyAddressesforgapps = $proxyAddresses;
              #extensionAttribute3 = $($User.extensionAttribute3);
              #extensionAttribute4 = $($User.extensionAttribute4);
            }
          }
      
        # Removing empty values
        @($params.OtherAttributes.Keys)|%{if(-not $params.OtherAttributes[$_]){$params.OtherAttributes.Remove($_)}}
        $voidCount=(@($params.OtherAttributes.Keys) | % {if ($params.OtherAttributes[$_] -in $voidChars) {$_}}).Count
        if($params.OtherAttributes.Keys.count -eq $voidCount){$params.Remove('OtherAttributes')}
        @($params.Keys) | % {if ($null -eq $params[$_]) {$params.Remove($_)}}
        
        try{       
          # Creating the user account
          New-ADUser @params -PassThru #-Verbose       
          $successes+="$newSamAccountName with display name '$displayName' has been succesfully created"
        }catch{
          $failures+="$newSamAccountName creation has failed with error: $_"
        }
      }else{
        write-warning "$newSamAccountName already exists in $env:USERDNSDOMAIN"
        $usersAlreadyExist+="$newSamAccountName already exists"
      }
    }
    $divider='`r`n`r`n==============================================================`r`n`r`n'
    $logMessages=$failures+$divider+$usersAlreadyExist+$divider+$successes
  }else{
    $logMessages="$($csvContents.count) records have been checked. There are no new users to create."
    write-host $logMessages
  }

  $logMessages | Out-File -FilePath $logFile
  write-host "Results have been logged at $logFile"
}
function addProxyEmails{
  $csvFile='C:\Userliases.csv'
  $baseOu='CN=Users,DC=kimconnect,DC=com'

  $existingUsers=if($baseOu){
    #get-aduser - Filter * -searchbase $baseOu
    get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Enabled|?{$_.Enabled -eq $true}
  }else{
        #get-aduser -Filter *
        get-aduser -Filter * -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Enabled|?{$_.Enabled -eq $true}
      }
  $csvContents=import-csv $csvFile
  foreach ($user in $csvContents){
      $emailAddress=$user.user
      $alias=$user.Alias
      $matchSamAccount=$existingUsers|?{$emailAddress -eq $_.EmailAddress}
      if($null -ne $matchSamAccount){
          $existingProxyEmails=$matchSamAccount.ProxyAddresses
          $existingProxyEmailsForGapps=$matchSamAccount.proxyAddressesForGapps    
          $existingEmailAddress=$matchSamAccount.EmailAddress
          $newAlias=$user.alias
          if(!($existingProxyEmails|?{$_ -like "smtp:$newAlias"})){
              Set-ADUser -Identity $matchSamAccount.SamAccountName -Add @{proxyAddresses = "smtp:$newAlias"}
          }else{
              write-host "de nata"
          }
          if(!($existingProxyEmailsForGapps|?{$_ -like "smtp:$newAlias"})){
              Set-ADUser -Identity $matchSamAccount.SamAccountName -Add @{proxyAddressesForGapps = "smtp:$newAlias"}
          }else{
              write-host "de nata"
          }
      }
  }
}
function updateUserAccounts{
  param(
    $csvFile,
    $baseOu,
    $companyName,
    $primaryEmailSuffix,
    $proxyEmailSuffix,
    $logFile,
    $updateManagers=$false
  )
  $progress=''
  # Match labels according to CSV
  # $samAccountLabel='SamAccountName'
  # $nameLabel='Name'
  # $firstNameLabel='First Name'
  # $lastNameLabel='Last Name'
  # $employeeIdLabel='File #'
  # $jobTitleLabel='Business Title'
  # $passwordLabel='newPassword'
  # $emailLabel='Business Email' # This field is required
  # $aliasLabel='Alias'
  # $streetLabel='Street 1'
  # $streetLabel2='Street 2'
  # $cityLabel='city'
  # $stateLabel='state'
  # $postalLabel='PostalCode'
  # $countryLabel='Country'
  # $telephoneLabel='telephoneNumber'
  # $extensionLabel='Extension'
  # $initialsLabel='Initials'
  # $descriptionLabel='Description'
  # $officeLabel='Office'
  # $managerDnLabel='newManagerDN'
  # $departmentLabel='Department'
  # $divisionLabel='Division'
  # $newAccountLabel='newEmployee'

  $samAccountLabel='SamAccountName'
  $nameLabel='Name'
  $firstNameLabel='FIRST NAME'
  $lastNameLabel='LAST NAME'
  $employeeIdLabel='File #'
  $jobTitleLabel='JOB TITLE'
  $passwordLabel='newPassword'
  $emailLabel='WORK EMAIL' # This field is required
  $aliasLabel='Alias'
  $streetLabel='STREET ADDRESS'
  $streetLabel2='Street 2'
  $cityLabel='CITY'
  $stateLabel='STATE'
  $postalLabel='POSTAL CODE'
  $countryLabel='COUNTRY'
  $telephoneLabel='WORK TELEPHONE'
  $extensionLabel='WORK EXTENSION'
  $initialsLabel='Initials'
  $descriptionLabel='Description'
  $officeLabel='Office'
  $managerDnLabel='newManagerDN'
  $departmentLabel='DEPARTMENT'
  $divisionLabel='Division'
  $newAccountLabel='newEmployee'
  $hireDateLabel='HIRE DATE'
  $supervisorNameLabel='SUPERVISOR NAME'

  function createUsers{
    # Declare variables
    $failures=@()
    $usersAlreadyExist=@()
    $successes=@()
    $erroractionpreference="Continue"
    $pauses=2

    write-host "Gathering Active Directory Users Information..."
    # Gather user accounts in a defined OU
    $existingUsers=if($baseOu){
      #get-aduser -Filter * -searchbase $baseOu
      get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,DistinguishedName
    }else{
      #get-aduser -Filter *
      get-aduser -Filter * -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,DistinguishedName
    }
    $fileExists=test-path $csvFile
    $csvContents=if($fileExists){import-csv $csvFile}else{return $false}
    if(!$csvContents){
      write-warning "$csvFile has no data."
      return $false
    }
    $usersToCreate=if($null -ne $existingUsers){
        $csvContents|?{
          $newAccount=$_.$newAccountLabel
          $firstname=$_.$firstNameLabel
          $lastname=$_.$lastNameLabel
          $alias=$_.$aliasLabel
          if($alias){
            $aliasFirstname=$alias.split(' ')|select -first 1
            $aliasLastname=$alias.split(' ')|select -first 2|select -last 1
          }else{
            $aliasFirstname=$aliasLastname=$null
          }
          $lastnameMatches=$existingUsers.Surname|?{$_ -eq $lastname -or $_ -eq $aliasLastname}
          $firstNameMatches=if($lastnameMatches){
            if($lastnameMatches.Givenname|?{$_ -eq $firstname -or $_ -eq $aliasFirstname}){$true}else{$false}
          }else{$false}
          $newAccount -or !($lastnameMatches -and $firstNameMatches)
        }
      }else{
        $csvContents
      }
    
    if($usersToCreate){      
      write-host "Creating new accounts..."
      $allExistingUsers=Get-ADUser -Filter * -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,DistinguishedName
      $voidChars='#N/A','',$null
      $ou=if($baseOu){$baseOu}else{
        $domainLdapExpression='DC='+((($env:USERDNSDOMAIN).tolower() -split '\.') -join ',DC=');
        'CN=Users,'+$domainLdapExpression
      }
      foreach($user in $usersToCreate){
        $firstname=$user.$firstNameLabel
        $lastName=$user.$lastNameLabel
        $alias=$user.$aliasLabel
        $givenEmail=$user.$emailLabel
        $samAccountName=.{          
          # Default:
          if($user.$samAccountLabel){return $user.$samAccountLabel}

          # Method 1: check to determine whether there are not duplicating records
          $testSamAccountName=$firstName[0]+$lastName
          $matchedSam=$allExistingUsers|?{$_.SamAccountName -eq $testSamAccountName}
          if(!$matchedSam){
            return $testSamAccountName
          }
          # Method 2: 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 3: incrementing the username by a single digit
          for($i=1;$i -lt 11;$i++){
            $testUsername2=$samAccountName+$i
            if($testUserName2 -notin $allExistingUsers.SamAccountName){
              return $testUsername2
            }
          }
        }
        $proxyEmail=if($samAccountName){$samAccountName+$proxyEmailSuffix}else{$null}
        $primaryEmail=if($samAccountName){$samAccountName+$primaryEmailSuffix}else{$null}
        $userExists=$givenEmail -in $allExistingUsers.EmailAddress -or $primaryEmail -in $allExistingUsers.EmailAddress
        if(!$userExists){
          $jobTitle=if($user.$jobTitleLabel -notin $voidChars){$user.$jobTitleLabel}else{$null}
          $password = $user.$passwordLabel | ConvertTo-SecureString -AsPlainText -Force
          $streetAddress=if($user.$streetLabel -notin $voidChars){$user.$streetLabel+', '+$user.$streetLabel2}elseif($user.$streetLabel -notin $voidChars){$user.$streetLabel}else{$null}
          $city =if($user.$cityLabel -notin $voidChars){$user.$cityLabel}else{$null}
          $state =if($user.$stateLabel -notin $voidChars){$user.$stateLabel}else{$null}
          $postalCode=if($user.$postalLabel -notin $voidChars){$user.$postalLabel}else{$null}
          $country=if($user.$countryLabel -notin $voidChars){$user.$countryLabel}else{$null}      
          $telephone=if($user.$telephoneLabel -notin $voidChars){$user.$telephoneLabel}else{$null}
          $extension=if($user.$extensionLabel -notin $voidChars){$user.$extensionLabel}else{$null}
          $displayName=if($user.$nameLabel){$user.$nameLabel}else{$lastName+', '+$firstName}
          $userPrincipleName=$samAccountName+'@'+$env:USERDNSDOMAIN
          $employeeId=if($user.$employeeIdLabel -notin $voidChars){$user.$employeeIdLabel}else{$null}
          $userInitials=if($user.$initialsLabel -notin $voidChars){$user.$initialsLabel}else{$null}
          $description=if($user.$descriptionLabel -notin $voidChars){$user.$descriptionLabel}else{$null}
          $office=if($user.$officeLabel -notin $voidChars){$user.$officeLabel}else{$null}
          $managerDn=if($user.$managerDnLabel -notin $voidChars){$user.$managerDnLabel}else{$null}
          $department=if($user.$departmentLabel -notin $voidChars){$user.$departmentLabel}else{$null}
          $division=if($user.$divisionLabel -notin $voidChars){$user.$divisionLabel}else{$null}
          $hireDate=if($user.$hireDateLabel -notin $voidChars){$user.$hireDateLabel -AS [datetime]}else{$null}
          $managerDn=.{
            if($user.$supervisorNameLabel -notin $voidChars){
              $x=$user.$supervisorNameLabel.split(' ')
              if($x.count -eq 2){
                $supervisorLastname= $x|select -last 1
                $supervisorFirstname=$x|select -first 1
              }elseif($x.gettype().name -eq 'String'){
                $supervisorLastname= $null
                $supervisorFirstname=$x
              }else{
                $supervisorLastname= $x|select -first 2|select -Last 1  
                $supervisorFirstname=$x|select -first 1
              }
              $y=.{                
                $lastNameMatches=$existingUsers|?{$_.Surname -eq $supervisorLastname}
                $nameMatches=if($lastNameMatches){
                  $lastNameMatches|?{$_.Givenname -eq $supervisorFirstname}
                }else{$null}
                if($nameMatches.SamAccountName.count -eq 1){
                  return $nameMatches.DistinguishedName
                }else{
                  return $null
                }
              }
              return $y
            }else{
              return $null
            }
          }
          $proxyAddresses=.{
            [string[]]$x=@("SMTP:$primaryEmail","smtp:$proxyEmail","smtp:$givenEmail")|?{$_ -and $_ -notlike "*$removeProxyEmailSuffix" -and $_ -notmatch '@{2}' -and $_ -ne 'smtp:'}|select -Unique
            if($x.gettype().Name -ne 'String'){
              [System.Collections.ArrayList]$x=$x
            }else{
              return $x
            }
            $primaryDuplicates=$x|?{$_ -cmatch '^SMTP\:' -and $_ -ne "SMTP:$primaryEmail"}
            $primaryDuplicates|%{$null=$x.Remove("$_")}            
            do{
              $otherDuplicates=$x|group|?{$_.Count -gt 1}|select -ExpandProperty Group|?{$_ -cne "SMTP:$primaryEmail"}
              $otherDuplicates|select -first 1|%{$null=$x.Remove($_)}
            }until(!$otherDuplicates)
            return $x
          }

          # Generating a hash table as a splatting technique
          $params = @{        
            SamAccountName = $samAccountName;
            Path = $ou;
            Enabled = $true;        
            AccountPassword = $password;
            ChangePasswordAtLogon = $False;
            EmployeeID = $employeeId;        
            GivenName = $firstName;
            Surname = $lastName;
            Name = $displayName;
            DisplayName = $displayName;
            UserPrincipalName = $userPrincipleName;
            Initials = $userInitials;
            Description = $description;    
            Office = $office;
            Title = $jobTitle
            Manager = $managerDn;
            Company = $companyName;
            Department = $department;
            Division = $division;
            StreetAddress = $streetAddress;
            EmailAddress = $primaryEmail;
            City = $city
            State = $state
            PostalCode = $postalCode
            Country = $country
            OfficePhone = $telephone
            OtherAttributes = @{ 
                IPPhone = $extension
                proxyAddresses = $proxyAddresses
                proxyAddressesforgapps = $proxyAddresses
                # HireDate = $hiredate
                #extensionAttribute4 = $($User.extensionAttribute4);
              }
            }
        
          # Removing empty values
          @($params.OtherAttributes.Keys)|%{if(-not $params.OtherAttributes[$_]){$params.OtherAttributes.Remove($_)}}
          $voidCount=(@($params.OtherAttributes.Keys) | % {if ($params.OtherAttributes[$_] -in $voidChars) {$_}}).Count
          if($params.OtherAttributes.Keys.count -eq $voidCount){$params.Remove('OtherAttributes')}
          @($params.Keys) | % {if ($null -eq $params[$_]) {$params.Remove($_)}}
          
          try{       
            # Creating the user account
            if($pauses-- -ge 0){
              write-output $params
              pause
            }
            New-ADUser @params -PassThru #-Verbose       
            $successes+="$samAccountName with display name '$displayName' has been succesfully created"
          }catch{
            $failures+="$samAccountName creation has failed with error: $_"
          }
        }else{
          write-warning "$samAccountName already exists in $env:USERDNSDOMAIN"
          $usersAlreadyExist+="$samAccountName already exists"
        }
      }
  
      $accountCreationResult=$usersAlreadyExist+$failures+$successes
      $accountCreationResult|Out-File -FilePath $logFile -Append
    }
  }

  function updateAccounts{
    # Declare variables
    $successes=@()
    $failures=@()
    $erroractionpreference = "Continue"
    $pauses=3
    write-host "Gathering Active Directory Users Information..."
    # Gather user accounts in a defined OU
    $existingUsers=if($baseOu){
      #get-aduser -Filter * -searchbase $baseOu
      get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,Surname,DisplayName,Initials,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Description,Office,Manager,Company,Department,Division,StreetAddress,City,State,PostalCode,Country,OfficePhone,IPPhone
    }else{
      #get-aduser -Filter *
      get-aduser -Filter * -property SamAccountName,GivenName,Surname,DisplayName,Initials,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Description,Office,Manager,Company,Department,Division,StreetAddress,City,State,PostalCode,Country,OfficePhone,IPPhone
    }
    $fileExists=test-path $csvFile
    $csvContents=if($fileExists){import-csv $csvFile}else{return $false}
    if(!$csvContents){
      write-warning "$csvFile has no data."
      return $false
    }
    # Updating Accounts
    foreach($row in $csvContents){
      $givenSamAccount=$row.$samAccountLabel
      $firstname=$row.$firstNameLabel
      $lastName=$row.$lastNameLabel
      $alias=$row.$aliasLabel
      $aliasFirstname=($alias -split ' ')[0]
      $aliasLastname=($alias -split ' ')[1]
      $matchedSamAccount=$existingUsers|?{
        $condition1=if($givenSamAccount){$_.SamAccountName -eq $givenSamAccount}
        $condition2=if($_.Surname -eq $lastName -or $_.Surname -eq $aliasLastname){($_.Givenname -eq $firstName -or $_.Givenname -eq $aliasFirstname)}else{$false}
        $condition1 -or $condition2
      }
      if($matchedSamAccount.SamAccountname.count -gt 1){
        $failures+="WARNING: There are multiple matches for $firstname $lastName`: $($matchedSamAccount.SamAccountName)"
        write-warning "There are multiple matches for $firstname $lastName`: $($matchedSamAccount.SamAccountName)"
      }elseif($matchedSamAccount.SamAccountname.count -eq 1){
        if($pauses-- -gt 0){
          write-host "Pause #$pauses`: updating`r`n`r`n------FROM------ $($matchedSamAccount|out-string) ------TO------ $($row|out-string)"
          pause
        }
        $user=$matchedSamAccount
        $samAccountName=$user.SamAccountName
        $password = $row.$passwordLabel | ConvertTo-SecureString -AsPlainText -Force
        $streetAddress=if($row.$streetLabel -notin $voidChars){$row.$streetLabel+', '+$row.$streetLabel2}elseif($row.$streetLabel -notin $voidChars){$row.$streetLabel}else{$null}
        $city =if($row.$cityLabel -notin $voidChars){$row.$cityLabel}else{$null}
        $state =if($row.$stateLabel -notin $voidChars){$row.$stateLabel}else{$null}
        $postalCode=if($row.$postalLabel -notin $voidChars){$row.$postalLabel}else{$null}
        $country=if($row.$countryLabel -notin $voidChars){$row.$countryLabel}else{$null}      
        $telephone=if($row.$telephoneLabel -notin $voidChars){$row.$telephoneLabel}else{$null}
        $extension=if($row.$extensionLabel -notin $voidChars){$row.$extensionLabel}else{$null}
        $displayName=$lastName+', '+$firstName     
        $employeeId=if($row.$employeeIdLabel -notin $voidChars){$row.$employeeIdLabel}else{$null}
        $userInitials=if($row.$initialsLabel -notin $voidChars){$row.$initialsLabel}else{$null}
        $description=if($row.$descriptionLabel -notin $voidChars){$row.$descriptionLabel}else{$null}
        $office=if($row.$officeLabel -notin $voidChars){$row.$officeLabel}else{$null}
        $jobTitle=if($row.$jobTitleLabel -notin $voidChars){$row.$jobTitleLabel}else{$null}
        $managerDn=if($row.$managerDnLabel -notin $voidChars){$row.$managerDnLabel}else{$null}
        $department=if($row.$departmentLabel -notin $voidChars){$row.$departmentLabel}else{$null}
        $division=if($row.$divisionLabel -notin $voidChars){$row.$divisionLabel}else{$null}
        $givenEmail=$row.$emailLabel
        $proxyEmail=$user.SamAccountName+$proxyEmailSuffix
        $primaryEmail=$user.SamAccountName+$primaryEmailSuffix
        $oldEmail=$user.EmailAddress
        $oldProxyEmails=$user.ProxyAddresses
        $oldProxyEmailsForGapps=$user.proxyAddressesForGapps
        $finalProxyAddresses=.{
          $newProxyEmails=@("SMTP:$primaryEmail","smtp:$proxyEmail","smtp:$oldEmail","smtp:$givenEmail")
          [string[]]$x=$oldProxyEmails+$oldProxyEmailsForGapps+$newProxyEmails|?{$_ -and $_ -notlike "*$removeProxyEmailSuffix" -and $_ -notmatch '@{2}' -and $_ -ne 'smtp:'}|select -Unique
          if($x.gettype().Name -ne 'String'){
            [System.Collections.ArrayList]$x=$x
          }else{
            return $x
          }
          $primaryDuplicates=$x|?{$_ -cmatch '^SMTP\:' -and $_ -ne "SMTP:$primaryEmail"}
          $primaryDuplicates|%{$null=$x.Remove("$_")}
          do{ # Not the most efficient algo, but practical enough for a small set of data
            $otherDuplicates=$x|group|?{$_.Count -gt 1}|select -ExpandProperty Group|?{$_ -cne "SMTP:$primaryEmail"}
            $otherDuplicates|select -first 1|%{$null=$x.Remove($_)}
          }until(!$otherDuplicates)
          return $x
        }

        if($description -and $description -ne $user.Description){
          Set-ADUser -Identity $samAccountName -Description $description
          $successes+="Updated Description from '$($user.Description)' to '$description'..."
          write-host "Updated Description from '$($user.Description)' to '$description'..."
        }
        if($office -and $office -ne $user.Office){
          Set-ADUser -Identity $samAccountName -Office $office
          $successes+="Updated Office from '$($user.Office)' to '$office'..."
          write-host "Updated Office from '$($user.Office)' to '$office'..."
        }
        if($jobTitle -and $jobTitle -ne $user.Title){
          set-aduser -Identity $samAccountName -Title $jobTitle
          $successes+="Updated employee job title from '$($user.Title)' to '$jobTitle'..."
          write-host "Updated employee job title from '$($user.Title)' to '$jobTitle'..."
        }
        if($managerDn -and $managerDn -ne $user.Manager){
          set-aduser -Identity $samAccountName -Manager $managerDn
          $successes+="Updated Manager from '$($user.Manager)' to '$managerDn'..."
          write-host "Updated Manager from '$($user.Manager)' to '$managerDn'..."
        }
        if($companyName -and $companyName -ne $user.Company){
          set-aduser -Identity $samAccountName -company $companyName
          $successes+="Updated Company from '$($user.Company)' to '$companyName'..."
          write-host "Updated Company from '$($user.Company)' to '$companyName'..."
        }
        if($department -and $department -ne $user.Department){
          set-aduser -Identity $samAccountName -Department $department
          $successes+="Updated Department from '$($user.Department)' to '$department'..."
          write-host "Updated Department from '$($user.Department)' to '$department'..."
        }
        if($division -and $division -ne $user.Division){
          set-aduser -Identity $samAccountName -Division $division
          $successes+="Updated Division from '$($user.Division)' to '$division'..."
          write-host "Updated Division from '$($user.Division)' to '$division'..."
        }
        if($streetAddress -and $streetAddress -ne $user.StreetAddress){
          Set-ADUser -Identity $samAccountName -StreetAddress $streetAddress
          $successes+="Updated StreetAddress from '$($user.StreetAddress)' to '$streetAddress'..."
          write-host "Updated StreetAddress from '$($user.StreetAddress)' to '$streetAddress'..."
        }
        if($city -and $city -ne $user.City){
          Set-ADUser -Identity $samAccountName -City $city
          $successes+="Updated City from '$($user.City)' to '$city'..."
          write-host "Updated City from '$($user.City)' to '$city'..."
        }
        if($state -and $state -ne $user.State){
          Set-ADUser -Identity $samAccountName -State $state
          $successes+="Updated State from '$($user.State) to '$state'..."
          write-host "Updated State from '$($user.State)' to '$state'..."
        }
        if($postalCode -and $postalCode -ne $user.PostalCode){
          Set-ADUser -Identity $samAccountName -PostalCode $postalCode
          $successes+="Updated PostalCode from '$($user.PostalCode)' to '$postalCode'..."
          write-host "Updated PostalCode from '$($user.PostalCode)' to '$postalCode'..."
        }
        if($country -and $country -ne $user.Country){
          Set-ADUser -Identity $samAccountName -Country $country
          $successes+="Updated Country from $($user.Country) to $country..."
          write-host "Updated Country from $($user.Country) to $country..."
        }
        if($telephone -and $telephone -ne $user.OfficePhone){
          Set-ADUser -Identity $samAccountName -OfficePhone $telephone
          $successes+="Updated OfficePhone from $($user.OfficePhone) to $telephone..."
          write-host "Updated OfficePhone from $($user.OfficePhone) to $telephone..."
        }
        if($extension -and $extension -ne $user.IPPhone){
          Set-ADUser -Identity $samAccountName -IPPhone $extension
          $successes+="Updated IPPhone from $($user.IPPhone) to $extension..."
          write-host "Updated IPPhone from $($user.IPPhone) to $extension..."
        }
        if($displayName -and $displayName -ne $user.DisplayName){
          Set-ADUser -Identity $samAccountName -DisplayName $displayName
          $successes+="Updated DisplayName from $($user.DisplayName) to $displayName..."
          write-host "Updated DisplayName from $($user.DisplayName) to $displayName..."
        }
        if($userInitials -and $userInitials -ne $user.Initials){
          Set-ADUser -Identity $samAccountName -Initials $userInitials
          $successes+="Updated Initials from $($user.Initials) to $userInitials..."
          write-host "Updated Initials from $($user.Initials) to $userInitials..."
        }        
        if($oldEmail -ne $primaryEmail){
          $successes+="updating email addresses from $oldEmail to $primaryEmail..."
          write-host "updating email addresses from $oldEmail to $primaryEmail..."
          Set-ADUser -Identity $samAccountName -EmailAddress $primaryEmail
        }
        if($finalProxyAddresses -and ($oldProxyEmails|out-string) -cne ($finalProxyAddresses|out-string)){
          Set-ADUser -Identity $samAccountName -Clear proxyAddresses          
          $finalProxyAddresses|%{Set-ADUser -Identity $samAccountName -Add @{proxyAddresses = "$_"} }
          $successes+="Updated proxy addresses from '$oldProxyEmails' to '$finalProxyAddresses'..."
          write-host "Updated proxy addresses from '$oldProxyEmails' to '$finalProxyAddresses'..."
        }
        if($finalProxyAddresses -and ($oldProxyEmailsForGapps|out-string) -cne ($finalProxyAddresses|out-string)){  
          Set-ADUser -Identity $samAccountName -Clear proxyaddressesforgapps
          $finalProxyAddresses|%{Set-ADUser -Identity $samAccountName -Add @{proxyaddressesforgapps = "$_"} }
          $successes+="Updated Google proxy addresses from '$oldProxyEmailsForGapps' to '$finalProxyAddresses'..."
          write-host "Updated Google proxy addresses from '$oldProxyEmailsForGapps' to '$finalProxyAddresses'..."
        }
        if($employeeId -and $employeeId -ne $user.EmployeeID){
          set-aduser -Identity $samAccountName -Employeeid $employeeId
          $successes+="Updated EmployeeID from '$($user.EmployeeID)' to $employeeId..."
          write-host "Updated EmployeeID from '$($user.EmployeeID)' to $employeeId..."
        }
        if($password){
          Set-ADAccountPassword -Identity $samAccountName -Reset -NewPassword $password
          $successes+="Updated password for user $samAccountName..."
          write-host "Updated password for user $samAccountName..."
        }
      }else{
        $failures+="WARNING: $firstname $lastName doesn't match any existing AD account."
        write-warning "$firstname $lastName doesn't match any existing AD account."
      }
      
      # Setting the Proxy Address as required for Office 365 and Google Apps
      # If (-not [string]::IsNullOrWhiteSpace($proxyAddresses)){
      #   foreach( $proxyAddress in ( $proxyAddresses -split ';' ) ){
      #     write-host "adding proxy addresses to user $newSamAccountName" -ForegroundColor Yellow
      #     $proxyAddresses=if($emailAddress -eq $proxyEmailAddress){'SMTP:'+$emailAddress}else{@('SMTP:'+$emailAddress,'smtp:'+$proxyEmailAddress)}
      #     # $primaryEmail = 'SMTP:'+"[email protected]"
      #     # $aliasEmail='smtp:'+"[email protected]"
      #     # $proxyAddresses=@($primaryEmail,$aliasEmail)
      #     # Set-ADUser -Identity $newSamAccountName -EmailAddress $primaryEmail   
      #     # get-aduser $userID -properties proxyaddresses | % {$_.proxyaddresses | ? {$_.startswith('SMTP')} | % {$_.substring(5)}}
      #     # get-aduser $userID -properties proxyaddressesforgapps | % {$_.proxyaddressesforgapps | ? {$_.startswith('SMTP')} | % {$_.substring(5)}}         
      #     Set-ADUser -Identity $newSamAccountName -Add @{proxyAddresses = $proxyAddresses}
      #     Set-ADUser -Identity $newSamAccountName -Add @{proxyaddressesforgapps = $proxyAddresses}           
      #     get-aduser -Identity $newSamAccountName -properties emailaddress,proxyaddresses,proxyaddressesforgapps
      #   }
      # } 

    }
    $results=$failures+$successes
    $results|Out-File -FilePath $logFile -Append
  }

  # correcting just the username part, use when necessary
  function setDefaultEmailAddresses{
    
    $existingUsers=if($baseOu){
      #get-aduser - Filter * -searchbase $baseOu
      get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Enabled|?{$_.Enabled -eq $true}
    }else{
      #get-aduser -Filter *
      get-aduser -Filter * -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title,Enabled|?{$_.Enabled -eq $true}
    }
    $count=0
    $totalRecords=$existingUsers.count
    $results=@()
 
    $targetUsers=$existingUsers|?{$_.EmailAddress -notmatch '.com$'}
    foreach ($user in $targetUsers){      
      $samAccount=$user.SamAccountName
      $proxyEmail=$samAccount+$proxyEmailSuffix
      $primaryEmail=$samAccount+$primaryEmailSuffix
      $oldEmail=$user.EmailAddress
      $oldProxyEmails=$user.ProxyAddresses
      $oldProxyEmailsForGapps=$user.proxyAddressesForGapps
      $finalProxyAddresses=.{
        $newProxyEmails=if($primaryEmail -ne $oldEmail -and $proxyEmail -ne $oldEmail){
            @("SMTP:$primaryEmail","smtp:$proxyEmail","smtp:$oldEmail")
        }else{
             @("SMTP:$primaryEmail","smtp:$proxyEmail")
        }
        [string[]]$x=$oldProxyEmails+$oldProxyEmailsForGapps+$newProxyEmails|?{$_}|select -Unique
        if($x.gettype().Name -ne 'String'){
          [System.Collections.ArrayList]$x=$x
        }else{
          return $x
        }
        $primaryDuplicates=$x|?{$_ -cmatch '^SMTP\:' -and $_ -ne "SMTP:$primaryEmail"}
        $primaryDuplicates|%{$null=$x.Remove("$_")}
        $ht = @{}
        $x|%{$ht["$_"]+=1}
        $otherDuplicates=$ht.keys|?{$ht["$_"] -gt 1}
        $otherDuplicates|%{if($_ -cne "SMTP:$primaryEmail"){$null=$x.Remove($_)}}
        return $x
      }
      $count++
      write-host "Checking $samAccount - record $count of $totalRecords"
      $result=@()
      $pass=$true

      if($oldEmail -ne $primaryEmail){
        Set-ADUser -Identity $samAccount -EmailAddress $primaryEmail
        $result+="- Updated primary email address from $oldEmail to $primaryEmail."
        write-host "Updated primary email address from $oldEmail to $primaryEmail."
        $pass=$false
      }else{
        $result+="- Primary email address $oldEmail is unchanged."
        write-host "Primary email address $oldEmail is unchanged."       
      }
      if($($oldProxyEmails|out-string) -ne $($finalProxyAddresses|out-string)){
        Set-ADUser -Identity $samAccount -Clear proxyAddresses
        $finalProxyAddresses|%{Set-ADUser -Identity $samAccount -Add @{proxyAddresses = "$_"} }
        $result+="- Updated proxy addresses from '$oldProxyEmails' to '$finalProxyAddresses'."
        write-host "Updated proxy addresses from '$oldProxyEmails' to '$finalProxyAddresses'."
        $pass=$false
      }else{
        $updateMessages+="- Existing proxy email addresses '$oldProxyEmails' are unchanged."
        write-host "Existing proxy email addresses '$oldProxyEmails' are unchanged."       
      }
      if($($oldProxyEmailsForGapps|out-string) -ne $($finalProxyAddresses|out-string)){  
        Set-ADUser -Identity $samAccount -Clear proxyaddressesforgapps
        $finalProxyAddresses|%{Set-ADUser -Identity $samAccount -Add @{proxyaddressesforgapps = "$_"} }
        $result+="- Updated Google proxy addresses from '$oldProxyEmailsForGapps' to '$finalProxyAddresses'."
        write-host "Updated Google proxy addresses from '$oldProxyEmailsForGapps' to '$finalProxyAddresses'."
        $pass=$false
      }else{
        $result+="- Existing Google proxy email addresses '$oldProxyEmailsForGapps' are unchanged."
        write-host "Existing Google proxy email addresses '$oldProxyEmailsForGapps' are unchanged."       
      }
      if(!$pass){
        $results+=@("$count`: $samAccountName is CHANGED.")+$result
      }else{
        $results+=@("$count`: $samAccountName is unchanged.")
      }
    }
    $results|Out-File -FilePath $logFile -Append
  }
  # setDefaultEmailAddresses

  function checkEmailAddresses{
    $checkingResults=@()
    $existingUsers=if($baseOu){
      #get-aduser - Filter * -searchbase $baseOu
      get-aduser -Filter * -searchbase $baseOu -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title
    }else{
      #get-aduser -Filter *
      get-aduser -Filter * -property SamAccountName,GivenName,Surname,UserPrincipalName,EmailAddress,ProxyAddresses,proxyAddressesForGapps,EmployeeID,Title
    }
    $count=0
    $totalRecords=$existingUsers.count
    foreach ($user in $existingUsers){
      $samAccount=$user.SamAccountName
      $proxyEmail=$samAccount+$proxyEmailSuffix
      $primaryEmail=$samAccount+$primaryEmailSuffix
      $oldEmail=$user.EmailAddress
      $oldProxyEmails=$user.ProxyAddresses
      $oldProxyEmailsForGapps=$user.proxyAddressesForGapps
      $finalProxyAddresses=.{
        $newProxyEmails=if($primaryEmail -ne $oldEmail -and $proxyEmail -ne $oldEmail){
            @("SMTP:$primaryEmail","smtp:$proxyEmail","smtp:$oldEmail")
        }else{
             @("SMTP:$primaryEmail","smtp:$proxyEmail")
        }
        [string[]]$x=$oldProxyEmails+$oldProxyEmailsForGapps+$newProxyEmails|?{$_}|select -Unique
        if($x.gettype().Name -ne 'String'){
          [System.Collections.ArrayList]$x=$x
        }else{
          return $x
        }
        $primaryDuplicates=$x|?{$_ -cmatch '^SMTP\:' -and $_ -ne "SMTP:$primaryEmail"}
        $primaryDuplicates|%{$null=$x.Remove("$_")}
        $ht = @{}
        $x|%{$ht["$_"]+=1}
        $otherDuplicates=$ht.keys|?{$ht["$_"] -gt 1}
        $otherDuplicates|%{if($_ -cne "SMTP:$primaryEmail"){$null=$x.Remove($_)}}
        return $x
      }
      $count++
      write-host "Checking $samAccount - record $count of $totalRecords"
      $pass=$true
      $checkingResult=@()
      if($primaryEmail -ne $oldEmail){
        $checkingResult+="- Existing email '$oldEmail' does not match '$primaryEmail'"
        $pass=$false
      }
      if($($oldProxyEmails|out-string) -ne $($finalProxyAddresses|out-string)){
        $checkingResult+="- Proxy Email Addresses: '$oldProxyEmails' does not match '$finalProxyAddresses'"
        $pass=$false
      }
      if($($oldProxyEmailsForGapps|out-string) -ne $($finalProxyAddresses|out-string)){
        $checkingResult+="- Google Proxy Email Addresses: '$oldProxyEmailsForGapps' does not match '$finalProxyAddresses'"
        $pass=$false
      }
      if(!$pass){
        $checkingResults+=@("Username: $samAccount")+$checkingResult
      }
    }
    # write-output $checkingResults
    $checkingResults|Out-File -FilePath $logFile -Append
  }

  function updateManagers{
    if($updateManagers){
      $progress+="Updating Managers DNs..."
      write-host "Updating Managers DNs..."
      foreach ($row in $csvContents) {
        try{      
          if($row.newManagerDN -notin $voidChars -and $row.SamAccountName){
            Set-ADUser $row.SamAccountName -Manager $row.newManagerDN
            $progress+="$($row.SamAccountName) Manager DN has been updated..."
          }else{
            $progress+="$($row.SamAccountName) is skipped..."
          }
        }catch{
          $progress+="$($row.SamAccountName) Manager DN update has failed with this error: $_"
        }
      }
    }
  }
}