- 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