- The maximum TTL of a dynamic object is 31,556,926 seconds (1 year).
- A deleted dynamic object due to its TTL expiring does not leave a tombstone behind.
- All DCs holding replicas of dynamic objects must run on Windows Server 2003 or greater.
- Dynamic entries with TTL values are supported in all partitions except the Configuration partition and Schema partition.
- Active Directory Domain Services do not publish the optional dynamicSubtrees attribute, as described in the RFC 2589, in the root DSE object.
- Dynamic entries are handled similar to non-dynamic entries when processing search, compare, add, delete, modify, and modifyDN operations.
- There is no way to change a static entry into a dynamic entry and vice-versa.
- A non-dynamic entry cannot be added subordinate to a dynamic entry.
And remember, this script creates objects in Active Directory! Use at your own risk! I might have the best of intentions but my skill may betray you. Test, test and further test before implementing this code in a production environment.
Function Get-LocalDomainController($objectDomain) {
return ([System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()).Servers | Where-Object { $_.Domain.Name -eq $objectDomain } | ForEach-Object { $_.Name } | Select-Object -first 1
}
Function Get-ObjectADDomain($distinguishedName) {
return ((($distinguishedName -replace "(.*?)DC=(.*)",'$2') -replace "DC=","") -replace ",",".")
}
Function Get-ActiveDirectoryObject($distinguishedName) {
return [ADSI]("LDAP://" + (Get-LocalDomainController (Get-ObjectADDomain $distinguishedName)) + "/" + ($distinguishedName -replace "/","\/"))
}
Function Get-DomainDistinguishedName($domain) {
return ("dc=" + $domain.Replace(".",",dc="))
}
Function Test-sAMAccountName($sAMAccountName,$domain) {
$objectConnection = New-Object -comObject "ADODB.Connection"
$objectConnection.Open("Provider=ADsDSOObject;")
$objectCommand = New-Object -comObject "ADODB.Command"
$objectCommand.ActiveConnection = $objectConnection
$ldapBase = ("LDAP://" + (Get-LocalDomainController $domain) + "/" + (Get-DomainDistinguishedName $domain))
$ldapAttr = "sAMAccountName"
$ldapScope = "subtree"
$ldapFilter = "(&(objectClass=user)(sAMAccountName=$sAMAccountName))"
$ldapQuery= "<$ldapBase>;$ldapFilter;$ldapAttr;$ldapScope"
$objectCommand.CommandText = $ldapQuery
$objectRecordSet = $objectCommand.Execute()
if($objectRecordSet.RecordCount -gt 0) {
$found = $true
} else {
$found = $false
}
return $found
}
#--------------------------------------------------------------------------------------------------#
Set-Variable -name destinationOu -option Constant -value "ou=Finance Testing,dc=americas,dc=ad,dc=mycompany,dc=local"
Set-Variable -name totalNumberOfAccounts -option Constant -value 50
Set-Variable -name givenName -option Constant -value "Test"
Set-Variable -name sn -option Constant -value "Account"
Set-Variable -name passwordSize -option Constant -value 12
#--------------------------------------------------------------------------------------------------#
$randomNumber = New-Object System.Random
$accounts = @()
$endDate = "05/01/2011 14:30:00"
$entryTtlSeconds = [int]((Get-Date $endDate) - (Get-Date)).TotalSeconds
#######################################################################
# Or you can do a time span instead for the account time to live i.e.,
# $entryTtlSeconds = [int](New-TimeSpan -days 90).TotalSeconds
# $entryTtlSeconds = [int](New-TimeSpan -minutes 60).TotalSeconds
#######################################################################
if($entryTtlSeconds -gt 31556926) {
Write-Host "Time-to-live greater than 1 year. Exiting!" -foregroundColor Red
exit
}
$destinationOuObject = Get-ActiveDirectoryObject $destinationOu
if($destinationOuObject.distinguishedName -ne $destinationOu) {
Write-Host "Unable to connect to $destinationOu. Exiting!" -foregroundColor Red
exit
}
for($i = 1;$i -le $totalNumberOfAccounts;$i++) {
$accountName = ($givenName + $sn + "$i")
Write-Host "Creating $accountName..."
if(Test-sAMAccountName $accountName (Get-ObjectADDomain $destinationOu)) {
Write-Host "$accountName already exists, skipping..." -foregroundColor Yellow
continue
}
$userObject = $destinationOuObject.Create("user","CN=$accountName")
$userObject.PutEx(2,"objectClass",@("dynamicObject","user"))
$userObject.Put("entryTTL",$entryTtlSeconds)
$userObject.Put("sAMAccountName", $accountName) # Mandatory attribute
$userObject.Put("givenName",$givenName)
$userObject.Put("sn",($sn + "$i"))
$userObject.Put("displayName",($givenName + " " + $sn + "$i"))
$userObject.Put("description","Account Used for Application Testing")
$userObject.Put("wWWHomePage","http://sharepointsite/projects/newfinancesystem")
$userObject.Put("userPrincipalName",($accountName + "@" + (Get-ObjectADDomain $destinationOu)))
$userObject.SetInfo()
$password = ""
for($x = 1;$x -le $passwordSize;$x++) {
$password += [char]($randomNumber.Next(33,126))
}
$userObject.SetPassword($password)
$userObject.Put("userAccountControl", 512)
$userObject.SetInfo()
$account = New-Object -typeName PSObject
Add-Member -inputObject $account -type NoteProperty -name "domain" -value (Get-ObjectADDomain $destinationOu).Split(".")[0]
Add-Member -inputObject $account -type NoteProperty -name "sAMAccountName" -value ($userObject.sAMAccountName).ToString()
Add-Member -inputObject $account -type NoteProperty -name "givenName" -value ($userObject.givenName).ToString()
Add-Member -inputObject $account -type NoteProperty -name "sn" -value ($userObject.sn).ToString()
Add-Member -inputObject $account -type NoteProperty -name "userPrincipalName" -value ($userObject.userPrincipalName).ToString()
Add-Member -inputObject $account -type NoteProperty -name "password" -value $password
$accounts += $account
}
$accounts | Export-Csv -path "$givenName $sn List.csv" -noTypeInformation