Skip to content

Instantly share code, notes, and snippets.

@sean-m
Created August 5, 2022 18:05
Show Gist options
  • Save sean-m/dc7a0e1bb8e16b1c13898191362324c9 to your computer and use it in GitHub Desktop.
Save sean-m/dc7a0e1bb8e16b1c13898191362324c9 to your computer and use it in GitHub Desktop.
For loading users into an ldap directory from a CSV file. Will create new users and update attributes as needed on existing users.
#Requires -Module ActiveDirectory
[CmdletBinding()]
param ($users_file, [switch]$WhatIf)
if (-not $users_file) {
Write-Warning "Must pass file name as `$users_file"
return 1
}
Write-Host -ForegroundColor Cyan $users_file
cd $(Split-Path -parent "$($MyInvocation.MyCommand.Definition)")
function ToPages {
param (
[Parameter(ValueFromPipeline=$true, Position=0)]
[object]$InputObject,
[Parameter(Mandatory=$true, Position=1)]
[int]$PageSize)
begin {
$book = New-Object System.Collections.Generic.List[object]
$page = @()
}
process {
$page += $InputObject
if ($page.Count -ge $PageSize) {
$book.Add($page)
$page = @()
}
}
end {
$book.Add($page)
$book.ToArray()
}
}
$ldap_server = 'localhost:389'
$ldap_root = 'DC=McAttributes,DC=or,DC=gov'
$ldap_active_root = 'CN=Users,DC=McAttributes,DC=or,DC=gov'
$ldap_property_map = @{
'name'="aadId"
'displayName'="displayName"
'employeeId'="employeeId"
'givenName'="givenName"
'surname'="surname"
'comment'="pronouns"
'personalTitle'="suffix"
}
$name_attribute = $ldap_property_map['name']
$ldap_properties = @($ldap_property_map.Keys)
$user_properties = @($ldap_property_map.Values)
## Load CSV
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Importing user records'
$users = Import-Csv $users_file
$users_hashset = New-Object System.Collections.Generic.HashSet[string]
$users | % { $users_hashset.Add($_.($ldap_property_map['name'])) } | Out-Null
Write-Host "Loaded $($users.Count) user records"
## Load active LDS users
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Loading LDS current users'
$active_users = @(Get-ADUser -Server $ldap_server -SearchBase $ldap_active_root -LDAPFilter "(objectClass=person)" -Properties $ldap_properties)
$active_hashset = New-Object System.Collections.Generic.HashSet[string]
$active_users | % { $active_hashset.Add($_.Name) } | Out-Null
Write-Host "Loaded $($active_users.Count) active LDS user records"
## Compute new users
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Resolving new users'
$new_users = @($users | ? { -not $active_hashset.Contains($_.($ldap_property_map['name'])) })
Write-Host "New user records $($new_users.Count)"
## Create users
Write-Host "Creating new users"
filter Percent { param ([int]$count=0, [int]$total=0) if ($total -eq 0) { return 0 } [Math]::Min(100,[Math]::Round((($count/$total) * 100))) }
$count = 0
if ($new_users) {
foreach ($user in $new_users) {
$count++
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Creating user accounts' -PercentComplete (Percent $count $new_users.Count)
$params = @{
'WhatIf'=$WhatIf
}
if ($user.($ldap_property_map['displayName'])) {
$params.Add('DisplayName', $user.($ldap_property_map['displayName']))
}
if ($user.($ldap_property_map['givenName'])) {
$params.Add('GivenName', $user.($ldap_property_map['givenName']))
}
if ($user.($ldap_property_map['surname'])) {
$params.Add('Surname', $user.($ldap_property_map['surname']))
}
New-ADUser -Server $ldap_server -Path $ldap_active_root `
-Name $user.$name_attribute `
-Verbose `
@params
}
}
else {
Write-Host "No new users to add"
}
## Reload active user objects
if ($new_users.Count -gt 0) {
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Refreshing active user list'
$active_users = @(Get-ADUser -Server $ldap_server -SearchBase $ldap_active_root -LDAPFilter "(objectClass=user)" -Properties $ldap_properties)
Write-Host "Loaded $($active_users.Count) active LDS user records"
}
$active_user_ht = @{}
$active_users | % { $active_user_ht.Add($_.Name, $_) } | Out-Null
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Refreshing active user list' -Completed
## Update Attributes
function CleanChars {
param ([string]$InputString)
if ([String]::IsNullOrEmpty($InputString)) { return $InputString }
$sb = New-Object System.Text.StringBuilder ($InputString.Length)
foreach ($c in $InputString.ToCharArray()) {
switch ($c) {
'[' { } #do nothing
']' { } #do nothing
'*' { } #do nothing
'?' { } #do nothing
default { $sb.Append($c) | Out-Null }
}
}
return $sb.ToString()
}
$count = 0
foreach ($user in $users) {
$count++
Write-Progress -Activity 'Provisioning LDS Users' -CurrentOperation 'Updating user attributes' -PercentComplete (Percent $count $users.Count)
$lds_user = $active_user_ht[$user.$name_attribute]
if ($lds_user) {
$params = @{
'Verbose'=$true
'WhatIf'=$WhatIf
'Server'=$ldap_server
}
$replace_vals = @{}
$set_vals = @{}
$clear_vals = @()
foreach ($p in $ldap_properties) {
$up = $ldap_property_map[$p]
if ($user.$up -notlike (CleanChars $lds_user.$p)) {
# destination has value, source doesn't. Clear destination.
if (-not $user.$up -and $lds_user.$p) {
$clear_vals += $ldap_property_map[$p]
}
elseif ($user.$up -and ($lds_user.$p)) {
$replace_vals.Add($p, $user.$up)
}
elseif ($user.$up -and (-not $lds_user.$p)) {
$set_vals.Add($p, $user.$up)
}
else {
Write-Warning "No match for ldap property: $p to user property: $up"
}
}
}
if ($replace_vals.Count -gt 0) { $params.Add("Replace", $replace_vals) }
if ($set_vals.Count -gt 0) { $params.Add("Add", $set_vals) }
if ($clear_vals) { $params.Add("Clear", $clear_vals) }
if ($params.Count -gt 3) {
$lds_user | Set-ADObject @params
}
}
else {
Write-Warning "User: $($user.$name_attribute) not found, skipping..."
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment