This script works off the OnPostCreate event handler for Group and User objects.

Set the minimum UID and GID number variable and the script will then continue to allocate the next available UID or GID and set this on the user or group respectively.

Note: This handler can take a long time to execute in environments with more than 10K user accounts. If your environment is larger than this see the alternative solution below.

# UID / GID Generation (Post Create)
#
# Modification History:-
# 21/07/2015 - Victor Meyer - Initial Release
 
# Set the base UID and GID numbers
Set-Variable -name baseUidNumber -value 1000000
Set-Variable -name baseGidNumber -value 1000000
 
# Get next available ID Function
function GetNextAvailableID
{
    param($objectType)
    end
    {
		#Setup the Next ID variable and set it to 0
		Set-Variable -name NextID -value 0
		#Check an set either a UID or GID
		if($objectType -eq "user")
			{
				# Get the greatest UID number in use
				$NextID = Get-QADUser -LDAPFilter "(uidNumber=*)" -Properties uidNumber |
   				Measure-Object -Property uidNumber -Maximum |
    			Select-Object -ExpandProperty Maximum
				# Increment the UID
				$NextID = $NextID + 1
				# Check if the NextID should be the base number
				if($NextID -lt $baseUidNumber)
					{
						$NextID = $baseUidNumber
					}
				# Return the Next available ID
				return $NextID
			}
		elseif($objectType -eq "group")
			{
				# Get the greatest GID number in use
				$NextID = Get-QADGroup -LDAPFilter "(gidNumber=*)" -Properties gidNumber |
   				Measure-Object -Property gidNumber -Maximum |
    			Select-Object -ExpandProperty Maximum
				# Increment the GID and Return the value
				$NextID = $NextID + 1
				# Check if the NextID should be the base number
				if($NextID -lt $baseGidNumber)
					{
						$NextID = $baseGidNumber
					}
				# Return the Next available ID
				return $NextID
			}	
    }
}
 
# Set ID Attribute Function
function SetIDAttribute
{
    param($objectType, $id)
    end
    {
		#Check an set either a UID or GID
		if($objectType -eq "user")
			{
				# Set UIDNumber
				$DirObj.Put("uidNumber", $id)
  				$DirObj.SetInfo()
			}
		elseif($objectType -eq "group")
			{
				# Set GIDNumber
				$DirObj.Put("gidNumber", $id)
  				$DirObj.SetInfo()
			}
 
    }
}
 
# Master Function
function onPostCreate($Request)
{
	# Check inbound connection type
	if($Request.Class -eq "user") # Request is a user
		{
			# Set the objectType variable
			Set-Variable -name objectType -value "user"
			# Call function to get next available uid
			$NextID = GetNextAvailableID -objectType $objectType 
			# Call function to set the uid
			SetIDAttribute -objectType $objectType -id $NextID
 
		}
	elseif($Request.Class -eq "group") # Request is a group
		{
			# Set the objectType variable
			Set-Variable -name objectType -value "group"
			# Call function to get next available gid
			$NextID = GetNextAvailableID -objectType $objectType 
			# Call function to set the gid
			SetIDAttribute -objectType $objectType -id $NextID
		}
}

Fore environments larger than 10 000 users its more efficient to create a central counter and call off that counter.

The script sample below queries two, custom, optional attributes that have been set on the domain object within the Active Directory Schema.

maxuid maxgid

domain.uid.gid

The PowerShell sample below shows how to extract and update the max attributes:-

Function Get-MaxID # Get the maximum in-use UID / GID according to the domain
{
    param($objectType)
    end
    {
        # Set the domain DN which will be queried for maximum uid / gid values
        Set-Variable -Name domainDN -Value "DC=lab,DC=local"
        If($objectType -eq "user") 
        {
            $Object = Get-ADObject -Identity $domainDN -Properties maxUIDNumber
            Return $Object.maxUIDNumber
        }
        Elseif($objectType -eq "group")  
        {
            $Object = Get-ADObject -Identity $domainDN -Properties maxGIDNumber
            Return $Object.maxGIDNumber      
        }
    }
}
 
Function Set-MaxID # Set the maximum in-use UID / GID domain attribute
{
    param($objectType,$id)
    end
    {
        # Set the domain DN which will be queried for maximum uid / gid values
        Set-Variable -Name domainDN -Value "DC=lab,DC=local"
        If($objectType -eq "user") 
        {
            Set-ADDomain -Identity $domainDN -Replace @{maxUIDNumber=$id}
        }
        Elseif($objectType -eq "group") 
        {
            Set-ADDomain -Identity $domainDN -Replace @{maxGIDNumber=$id}      
        }
    }
}
 
# Set the object type - user|group
set-variable -name objectType -Value "user"
 
# Get the next available ID
[int]$id = Get-MaxID -objectType $objectType
$id = $id + 1
 
# Set the max ID
Set-MaxID -objectType $objectType -id $id
 
# Return the new max ID
Get-MaxID -objectType $objectType

The PowerShell sample below shows the associated Quest ActiveRoles OnPostCreate handler:-

# UID / GID Generation (Post Create)
#
# Modification History:-
# 23/07/2015 - Victor Meyer - Initial Release
 
function Get-MaxID # Get the maximum in-use UID / GID according to the domain
{
    param($objectType)
    end
    {
        # Set the domain DN which will be queried for maximum uid / gid values
        Set-Variable -Name domainDN -Value "DC=lab,DC=local"
        if($objectType -eq "user") 
        {
            $Object = Get-QADObject -Identity $domainDN -Properties maxUIDNumber
            return $Object.maxUIDNumber
        }
        elseif($objectType -eq "group")  
        {
            $Object = Get-QADObject -Identity $domainDN -Properties maxGIDNumber
            return $Object.maxGIDNumber      
        }
    }
}
 
function Set-MaxID # Set the maximum in-use UID / GID domain attribute
{
    param($objectType,$id)
    end
    {
        # Set the domain DN which will be queried for maximum uid / gid values
        Set-Variable -Name domainDN -Value "DC=lab,DC=local"
        if($objectType -eq "user") 
        {
            Set-QADObject -Identity $domainDN -ObjectAttributes @{maxUIDNumber=$id}
        }
        elseif($objectType -eq "group") 
        {
            Set-QADObject -Identity $domainDN -ObjectAttributes @{maxGIDNumber=$id}    
        }
    }
}
 
function onPostCreate($Request) # The calling routine
{
 
    	# Check inbound connection type
	if($Request.Class -eq "user") # Request is a user
		{
		    # Set the objectType variable
		    Set-Variable -name objectType -value "user"
 
                # Get the next available ID
                [int]$id = Get-MaxID -objectType $objectType
                $id = $id + 1
 
                # Update the User Object
		    $DirObj.Put("uidNumber", $id)
  		    $DirObj.SetInfo()
 
                # Set the max ID
                Set-MaxID -objectType $objectType -id $id
 
		}
	elseif($Request.Class -eq "group") # Request is a group
		{
		    # Set the objectType variable
		    Set-Variable -name objectType -value "group"
 
                # Get the next available ID
                [int]$id = Get-MaxID -objectType $objectType
                $id = $id + 1
 
                # Update the User Object
		    $DirObj.Put("gidNumber", $id)
  		    $DirObj.SetInfo()
 
                # Set the max ID
                Set-MaxID -objectType $objectType -id $id
 
		}
 
}