Last active
November 12, 2023 14:17
-
-
Save phyoewaipaing/7eccf9f77b2cbfd6734982c2c157c3bb to your computer and use it in GitHub Desktop.
Create AD Users in Nested OU v2.1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#################################################################################################################################################################### | |
##*********************************** Script to create OUs and sub-OUs and Users in Active Directory *************************************************************** | |
## What this script will do: | |
## 1) It will read the csv file and trim start/end whitespaces. | |
## 2) create OUs and sub-OUs automatically as listed in 'OU' column. Be sure to use slash (/) between OU and sub-OUs | |
## 3) Before creating OUs and Users, it will test the domain names in csv file against the DC the script is running | |
## 4) It will throw an error: | |
## if user list csv file does not exists and does not have correct extension | |
## ActiveDirectory Powershell Module is not installed | |
## If the required column headers are missing in csv file | |
## If duplicate "Name" are found | |
## If the domain name is different from the one listed in csv file | |
## If the user's password policy doesn't meet the requirements | |
## and finally.. | |
## If you do not have permissions to create users in Active Directory | |
## Author: Phyoe Wai Paing | |
## Country: Myanmar(Burma) | |
## Note: You can find this script and more at https://www.scriptinghouse.com/ | |
## Version: | |
##[8/5/16, v1.1] Initial Release | |
##[1/25/18, v1.2] Added First Name, Last Name, Employee ID Attributes | |
##[4/29/18, v2.0] Can export the current users to csv file when no parameter is specified. Use -ImportCsvFile to create new users | |
## Prompt to inlude the new domain name & password to save in csv file. | |
## Change some properties: First Name, Last Name, Employee ID, Office Phone, Email, Job Title, OU Properties are changed to GivenName, SurName, EmployeeID.OfficePhone, EmailAddress, Title, Path: same as the output of get-aduser | |
## SamAccountName Property is added. | |
## OU name starting with letter 'U' or 'O' caused errors in early versions is fixed | |
##[5/17/18, v2.1] The issue that users 'Names' needed to be unique in domain level is fixed. It only needs to be unique in each OU level. | |
## | |
## Admin must specify the csv file path. Column names of CSV file should be as below. | |
## EmployeeID, DisplayName, OU, Description, Name, GivenName, SurName, SamAccountName, Title, Departement, Domain, Office, OfficePhone, Company, EmailAddress, Password ## | |
## 1, Mr. Phyo Wai, ICT/System Support, ICT System Administrator, phyo.wai, Phyo, Wai, phyo.wai, System Admin, System Support Section, contoso.com, Myanmar Office, 95-9-99999999, Consoto Airway, phyo@contoso.com, 12345678910 | |
## ... ... ... | |
## ... ... ... | |
########################################################################################################################################################### | |
################## Validates csv headers so that it is not different from the input variable defined in script, but you can skip this check by removing the first lettet (#) of next line ########## | |
param([String]$ImportCsvFile) | |
$DomainName= (gwmi WIN32_ComputerSystem).Domain | |
If (!($ImportCsvFile)) | |
{ | |
Write-Host "No parameter is specified. The users and OUs of current domain will be exported to new domain." | |
$NewDomainName = Read-Host "Enter the new domain name(eg: contoso.com)" | |
$NewPasswords = Read-Host -AsSecureString "Enter new password (blank to insert manually in csv file)" | |
Write-Host "`nExporting Users of $DomainName domain. Please wait..." | |
$ExistingUsers = Get-aduser -Filter * -Properties * | select EmployeeID, DisplayName, Description, Name, GivenName, SurName, SamAccountName, Title, Department, Office, OfficePhone, Company, EmailAddress, @{N="OU";Exp={$Count=($_.DistinguishedName.split(',') -match 'dc=').count; $Arr1 = $_.DistinguishedName.split(','); [array]::reverse($Arr1); $Arr1[$Count..($Arr1.length-2)].substring(3) -join '/'}}, @{N="Domain";Exp={$NewDomainName}}, @{N="Password";Exp= { [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($NewPasswords)) }} | |
$NumOfOUs = (dsquery ou -limit 100000 | ? { $_ -NotLike "*OU=Domain Controllers,*" }).count | |
$ExistingUsers | export-csv -notype "AD_Users_Info_$DomainName.csv" ## Export current users | |
If (Test-Path AD_Users_Info_$DomainName.csv) | |
{ | |
Write-Host "CSV file saved to $((gci AD_Users_Info_$DomainName.csv).FullName) Successfully. Please use this file with -ImportCsvFile option to create new AD users." | |
Write-Host "Number of Users Exported: $($ExistingUsers.count)" | |
Write-Host "Number of OUs Exported: $NumOfOUs" | |
} | |
Else | |
{ Write-Host -fore Red "Error occurred: Cannot export the csv file." } | |
} | |
elseif ((Test-Path $ImportCsvFile) -AND (Get-ChildItem $ImportCsvFile -EA SilentlyContinue) -like "*.csv") ## check if csv file exists and it has correct extension | |
{ | |
$Total_OU_Created=0 | |
$Total_User_Created=0 | |
Import-module ActiveDirectory -EA SilentlyContinue | |
if(Get-Module | where {$_.Name -eq 'ActiveDirectory'}) ## check ActiveDirectory Powershell modules can be loaded. | |
{ | |
$usersinfo=import-csv $ImportCsvFile | |
$validator_set=@("EmployeeID","DisplayName","OU","Description","Name","SamAccountName","Title","Department","Domain","Office","OfficePhone","Company","EmailAddress","Password","GivenName","SurName") | |
$input_headers= ($usersinfo | Get-Member -MemberType NoteProperty).Name | |
$Mismatches=$validator_set | where { $input_headers -Notcontains $_ } | |
If ($Mismatches -is [array]) | |
{ | |
[string]$Mismatches_Quoted_String = (($Mismatches | foreach { "$([char]34)$_$([char]34)"}) -join (',')) | |
Write-Host -Fore Red "The following fields are invalid or blank in your csv columns. Please Check and correct." | |
Write-Host $Mismatches_Quoted_String | |
} | |
elseif ($Mismatches) | |
{ | |
Write-Host -Fore Red "The following csv header is invalid or blank. Please check and correct" | |
Write-Host $Mismatches | |
} | |
else | |
{ | |
$usersinfo | foreach { $_.PsObject.Properties | foreach { $_.value =$_.value.trim() } } ## Trim the whitespaces and group OUs | |
$ounames=($usersinfo | Group-Object OU).name | |
$Dup_Names = ($usersinfo | group -Property Name,OU | where { $_.count -gt 1 }).Name ## check if duplicate "Name" exists for each OU | |
$Dup_Names_Output = ($usersinfo | group -Property Name,OU | where { $_.count -gt 1 }) | % { "`'$($_.name.split(',')[0].Trim())`' in `'$($_.name.split(',')[1].Trim())`' OU" } | |
$DomainSplit = $DomainName.split('.') | |
$DomainJoin = ',DC='+($DomainSplit -join (',DC=')) | |
$Domain_DN=$DomainJoin.TrimStart(',') | |
if ($Dup_Names) ### If duplicate user names are found, do not run the script | |
{ | |
Write-Host -Fore Red "The following Name have duplicate entries. Please check and correct it." | |
$Dup_Names_Output; | |
} | |
else { | |
$Domains=($usersinfo | group-object -property Domain).Name ### Group the domain names listed in csv file | |
if ($Domains -isnot [array]) | |
{ | |
if( $Domains -match "$DomainName") ### check if domain name matches queried domain name, if not exits | |
{ Write-Host -Fore Green "Domain name matches:$DomainName" | |
######################### OU Operation, Create the nested sub-OUs ########################## | |
$ounames | foreach { | |
$OU_Split=$NULL | |
$Parent_OU=$NULL | |
$OU_Split = $_.split('/') | |
for($i=0;$i -lt $OU_Split.Length;$i++) | |
{ | |
if($i -eq 0) | |
{ | |
[string]$currentOU= ','+$OU_Split[$i] ###get the current OU and append ',' | |
[string]$Parent_OU=$currentOU | |
[string]$Parent_Current_OU=$currentOU ### put the current OU as root OU for next loops | |
$OU_DN= ($Parent_OU -replace(",",",OU=")).TrimStart(',') | |
$Full_DN=$OU_DN+$DomainJoin | |
$ou_exists = [adsi]::Exists("LDAP://$Full_DN") | |
} | |
else | |
{ | |
[string]$currentOU=$OU_Split[$i] | |
$Parent_Current_OU=','+$currentOU+$Parent_Current_OU ## get the current OU and append it to the previous OU path as stored in $Parent_OU | |
$OU_DN= ($Parent_Current_OU -replace(",",",OU=")).TrimStart(',') | |
$Full_DN=$OU_DN+$DomainJoin | |
$ou_exists = [adsi]::Exists("LDAP://$Full_DN") | |
} | |
if ($ou_exists) ## Check if OU exists and if not, create new OU | |
{ | |
Write-Host -fore cyan "OU already created:$OU_DN" | |
} | |
else | |
{ | |
$Full_DN_Split = $Full_DN.Split(',') | |
$FirstPart = $Full_DN_Split[0].substring($Full_DN_Split[0].indexof("=") +1 ) ## Remove "OU=" syntax from the pair | |
$Full_DN_Split[0] = $NULL | |
$SecondPart= ($Full_DN_Split -join(',')).trimstart(',') | |
try { | |
New-ADOrganizationalUnit -name $FirstPart -Path $SecondPart -ProtectedFromAccidentalDeletion $False | Out-Null | |
Write-Host -Fore Green "OU `'$FirstPart`' created successfully." | |
$Total_OU_Created++ | |
} | |
catch [Microsoft.ActiveDirectory.Management.ADException] | |
{ | |
Write-Host -Fore Red "Cannot create OU. The Object already exists:`'$FirstPart`'" | |
} | |
catch [System.UnauthorizedAccessException] | |
{ | |
Write-Host -Fore "Access Denied. Make sure your have necessary permission to create OUs" | |
} | |
} | |
} | |
} | |
$usersinfo | foreach { | |
$OU_Path_Split=$_.ou.split('/') | |
[array]::reverse($OU_Path_Split) | |
If ($OU_Path_Split[0] -eq "Users" -OR $OU_Path_Split[0] -eq 'BuiltIn' ) ## If the OU is 'Users' or 'BuiltIn', then append as 'CN=' instead of 'OU=' | |
{ $OU_Path_Join= 'CN='+($OU_Path_Split -join (',OU=')) } | |
else | |
{ $OU_Path_Join= 'OU='+($OU_Path_Split -join (',OU=')) } | |
$Domain_Split = $_.Domain.split('.') | |
$Domain_Path_Join = ',DC='+($Domain_Split -join (',DC=')) | |
$Path=$OU_Path_Join + $Domain_Path_Join | |
################### Creating users in the respective OUs ########################## | |
$userprinc = $_.SamAccountName | |
try { | |
$Name=$_.Name | |
New-ADUser -Name $Name ` | |
-SamAccountName $_.SamAccountName ` | |
-UserPrincipalName "$userprinc@$DomainName" ` | |
-DisplayName $_.DisplayName ` | |
-Department $_.Department ` | |
-AccountPassword (convertTo-SecureString $_.Password -asPlainText -Force) ` | |
-Enabled $true ` | |
-Description $_.Description ` | |
-Title $_.Title ` | |
-EmailAddress $_.EmailAddress ` | |
-Office $_.Office ` | |
-OfficePhone $_.OfficePhone ` | |
-Company $_.Company ` | |
-ChangePasswordAtLogon $false ` | |
-PasswordNeverExpires $false ` | |
-GivenName $_.GivenName ` | |
-SurName $_.SurName ` | |
-EmployeeID $_.EmployeeID ` | |
-Path $Path | Out-Null | |
Write-Host -Fore Green "User has been created successfully:`'$Name`' in `'$($_.OU)`'" | |
$Total_User_Created++ | |
} | |
catch [Microsoft.ActiveDirectory.Management.ADIdentityAlreadyExistsException] | |
{ | |
Write-Host -Fore Red "Cannot add user. The account already exists:`'$Name`'" | |
} | |
catch [Microsoft.ActiveDirectory.Management.ADPasswordComplexityException] | |
{ | |
Write-Host -Fore Red "Cannot add user due to password policy. Please use more complex one:`'$Name`'" | |
} | |
} | |
Write-Host "`nNumber of new OUs Created:$Total_OU_Created" | |
Write-Host "Number of new Users Created:$Total_User_Created" | |
} | |
else | |
{ | |
Write-Host -Fore Red "Domain Name Mismatch. Please check your domain name and try again" | |
} | |
} | |
else { | |
Write-Host -Fore Red "There are some invalid domain names in csv file" | |
Write-Host -fore Red "Domains is $($Domains -join(' ,')) ?" | |
} | |
} | |
} | |
} | |
else | |
{ Write-Host -Fore Red "Active Directory Powershell Modules is not found. Please make sure you are running this script on domain Controller or `nRSAT is installed" | |
} | |
} | |
elseif ((Get-ChildItem $ImportCsvFile -EA SilentlyContinue) -notlike "*.csv") | |
{ | |
Write-Host -Fore Red "The file name extension is invalid. Please ensure that you created user list file as csv(comma-separated) file." | |
} | |
else | |
{ | |
Write-Host -Fore Red "CSV file not found. Please put the correct file name and path." | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment