1

I'm writing a script to be used by help desk staff to quickly (and accurately) create AD user accounts by inputting basic employee information. We use portions of a persons name in order to create the samAccountName. Which I've achieve by the following.

$GivenName = "Joe"
$Surname = "Smith"
$SamAccountName = $Surname.substring(0, [System.Math]::Min(5, $Surname.Length)) + $GivenName.Substring(0,1)

This works great as long as there isn't already a "Joe Smith" (or John or Jennifer Smithers, etc). The solution would be to add a number to the end. When manually creating accounts the help desk would search AD look at what number suffix to use if necessary. I'm trying to figure out how PowerShell can do that for us. I've gone through several ideas with help from what I've found online but so far I've been unsuccessful.

My first thought was to do something like this.

$SamSuffix = 2
If ((Get-ADUser -LDAPFilter "(SamAccountName=$samAccountName)")-eq $Null)
    {
        "$SamAccountName does not exist in AD" #out result for testing. 
    }
Else{
    do 
      {
      Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName + $SamSuffix++)"
      }
    until (Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName + $SamSuffix)")-eq $Null)
    }

This obviously doesn't work. Even if it did I don't know how I'd get to the 'next step' to create the account.

I also tried pulling the existing names into a list

$SamExist = (Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName*)" | Select SamAccountName)

    do  {$SamAccountName + $SamSuffix++}
    until ($SamExist -notcontains $SamAccountName -or $SamAccountName + $SamSuffix)

This also doesn't work but if it did I can see that it would automatically add the suffix even if it wasn't needed.

4
  • Do you care about gaps in numbers? Do you want just next one in the series? So if you had 1,2,4,5 are you looking for 3 or 6? Commented Apr 13, 2017 at 18:28
  • Hi. Yeah it should be the lowest available number starting with 2 (we don't use 1). We have a lot of users who rotate in and out so when their accounts get deleted we would reuse them. Thanks. Commented Apr 13, 2017 at 21:11
  • I got ansy and couldn't wait so I wrote both scenarios in my answer. Commented Apr 13, 2017 at 21:28
  • In most cases there is practical catch in AD queries like this: replication time. In a larger environment, the (helpdesk) agents might be connected different DCs. If two of those agents create a smithj# using the same script algorithm you will likely end up with a replication error and rolling out the same name for two different smithj’s users… Commented Apr 18, 2017 at 12:01

1 Answer 1

1

You approach where you get all the existing matches first would be where I would start. Lets assume $SamAccountName is smithj

$existingAccounts = Get-ADUser -Filter "samaccountname -like '$SamAccountName*'" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty samaccountname

So $existingaccounts that have a samaccountname's starting with smithj. If there are not any then $existingAccounts would be null and we can test for that.

if($existingAccounts){
    # Figure out what the suffix will be
    $highestValue = $existingAccounts -replace "^$SamAccountName" | 
        ForEach-Object{[int]$_} | 
        Measure-Object -Maximum | 
        Select-Object -ExpandProperty Maximum
} else {
    # Create the user as normal.
}

Pretending there are some accounts that exist we trim the leading characters from the samaccountname, convert the remaining to an integer and select the highest from that. So $highestValue is the last number used in a conflicting account.

Add one to that and you have a guaranteed username you can create assuming nothing changes in those moments i.e. two users making to smithj accounts.

If you are looking to fill gaps where a user might have left and you want to use the next available after 1 then you could do this.

$existingAccounts = "smithj1", "smithj5", "smithj10", "smithj2", "smithj3"
# Figure out what the next unused suffix will be
$existingSuffixes = $existingAccounts -replace "^$SamAccountName" | ForEach-Object{[int]$_}
# Once again determine the maximum one in use
$highestValue = $existingSuffixes |  Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
# Find the first gap between 1 and the max suffix
$nextAvailableSuffix = 1..($highestValue + 1) | Where-Object{$existingSuffixes -notcontains $_} | Sort-Object desc | Select -First 1

$nextAvailableSuffix would contain 4 using the above example. We add 1 to highest value in case the only other one is 2 so that way there will only be an answer to $nextAvailableSuffix

Sign up to request clarification or add additional context in comments.

5 Comments

I'll give it a shot when back at work tomorrow and let you know how it goes. Thanks!
Ok, it took me a bit but it looks like I've got it. For next available to begin at 2 I changed to $nextAvailableSuffix = 2..$highestValue | Where-Object{$existingSuffixes -notcontains $_} | Sort-Object | Select -First 1
To account for next available being null where $existingAccounts = "smithj", "smithj2" I used if ($highestValue -eq 2){$nextAvailableSuffix = 3}
Ahh yes that could happen. Easier just to add 1 to highest value
Oh, ok. Well I really appreciate the help. I've been working on this off and on for some time and just could not get this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.