Skip to content

Commit 13a3273

Browse files
Update 2024-07-27-PowerShell-Generate-Unique-Upn.md
1 parent f894832 commit 13a3273

File tree

1 file changed

+143
-86
lines changed

1 file changed

+143
-86
lines changed

_posts/2024-07-27-PowerShell-Generate-Unique-Upn.md

Lines changed: 143 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -111,116 +111,173 @@ This function generates a unique UPN based on given name components and ensures
111111
```powershell
112112
function Get-UniqueUPN
113113
{
114-
[CmdletBinding()]
115-
param (
116-
[Parameter(Mandatory = $true, ParameterSetName = "ADObject")]
117-
[object]$ADObject,
114+
<#
115+
.SYNOPSIS
116+
Cmdlet will generate a forest wide unique UPN.
117+
118+
.DESCRIPTION
119+
Cmdlet will generate a forest wide unique UPN according to generation rules
120+
defined by the user.
118121
119-
[Parameter(Mandatory = $true, ParameterSetName = "Strings")]
120-
[string]$FirstName,
122+
Cmdlet accept different types of objects to generate the UPN to allow greater flexibility
121123
122-
[Parameter(Mandatory = $true, ParameterSetName = "Strings")]
124+
ADObject - For example and object from Get-AdUser cmdlet
125+
Strings - Representing First Name, Last Name etc.
126+
DirectoryService Objects - For example when using native .Net methods to retrieve the identity
127+
128+
.PARAMETER ADObject
129+
An ADObject for example output of the Get-ADUser cmdlet
130+
131+
.PARAMETER FirstName
132+
A string representing the First Name of the user
133+
134+
.PARAMETER LastName
135+
A string representing the Last Name of the user
136+
137+
.PARAMETER MiddleName
138+
A string representing the Middle Name of the user, parameter is optional.
139+
140+
.PARAMETER UPNSuffix
141+
A string representing the UPN suffix to be used.
142+
143+
.PARAMETER FirstNameFormat
144+
A string representing the format to be for the First Name part of the UPN.
145+
146+
.PARAMETER LastNameFormat
147+
A string representing the format to be for the Last Name part of the UPN.
148+
149+
.PARAMETER IncludeMiddleName
150+
When paramenter is specified user Middle Name, if present, will be included in the UPN generation process.
151+
152+
.PARAMETER ADServer
153+
A string representing the name of the AD Domain Controller that will be used to query Active Directory.
154+
155+
If no server is specified the closest Global Catalog will be automatically selected.
156+
157+
.PARAMETER Separator
158+
A string representing the separator to be used between UPN parts, defaults to a '.'.
159+
#>
160+
161+
[CmdletBinding(DefaultParameterSetName = 'Strings')]
162+
param
163+
(
164+
[Parameter(ParameterSetName = 'ADObject',
165+
Mandatory = $true)]
166+
[object]$ADObject,
167+
[Parameter(ParameterSetName = 'Strings',
168+
Mandatory = $true)]
169+
[ValidateNotNullOrEmpty()]
170+
[string]$FirstName,
171+
[Parameter(ParameterSetName = 'Strings',
172+
Mandatory = $true)]
173+
[ValidateNotNullOrEmpty()]
123174
[string]$LastName,
124-
125-
[Parameter(ParameterSetName = "Strings")]
175+
[Parameter(ParameterSetName = 'Strings')]
176+
[ValidateNotNullOrEmpty()]
126177
[string]$MiddleName,
127-
128178
[Parameter(Mandatory = $true)]
179+
[ValidateNotNullOrEmpty()]
129180
[string]$UPNSuffix,
130-
131-
[string]$FirstNameFormat = "Full",
181+
[ValidateSet('FullName', 'FirstLetter', IgnoreCase = $true)]
182+
[ValidateNotNullOrEmpty()]
183+
[string]$FirstNameFormat = 'Full',
184+
[ValidateSet('FullName', 'FirstLetter', IgnoreCase = $true)]
185+
[ValidateNotNullOrEmpty()]
186+
[string]$LastNameFormat = 'FullName',
132187
[switch]$IncludeMiddleName,
133-
[string]$DuplicateSuffix = "Numeric",
134-
[string]$CustomDuplicateSuffix,
135-
[string]$Server,
136-
[string]$Separator = "."
188+
[ValidateNotNullOrEmpty()]
189+
[string]$ADServer,
190+
[ValidateNotNullOrEmpty()]
191+
[string]$Separator = '.'
137192
)
138-
139-
try
193+
194+
if ($PSCmdlet.ParameterSetName -eq 'ADObject')
140195
{
141-
if ($PSCmdlet.ParameterSetName -eq "ADObject")
196+
switch ($ADObject.GetType().FullName)
142197
{
143-
Write-Verbose "Processing AD Object"
144-
switch ($ADObject.GetType().FullName)
198+
'Microsoft.ActiveDirectory.Management.ADUser'
199+
{
200+
[string]$firstName = $ADObject.GivenName
201+
[string]$lastName = $ADObject.Surname
202+
[string]$middleName = $ADObject.MiddleName
203+
204+
break
205+
}
206+
'System.DirectoryServices.DirectoryEntry'
207+
{
208+
[string]$firstName = $ADObject.Properties['givenName'][0]
209+
[string]$lastName = $ADObject.Properties['sn'][0]
210+
[string]$middleName = $ADObject.Properties['middleName'][0]
211+
212+
break
213+
}
214+
'System.DirectoryServices.SearchResult'
145215
{
146-
"Microsoft.ActiveDirectory.Management.ADUser"
147-
{
148-
$firstName = $ADObject.GivenName
149-
$lastName = $ADObject.Surname
150-
$middleName = $ADObject.MiddleName
151-
break
152-
}
153-
"System.DirectoryServices.DirectoryEntry"
154-
{
155-
$firstName = $ADObject.Properties["givenName"][0]
156-
$lastName = $ADObject.Properties["sn"][0]
157-
$middleName = $ADObject.Properties["middleName"][0]
158-
break
159-
}
160-
"System.DirectoryServices.SearchResult"
161-
{
162-
$firstName = $ADObject.Properties["givenName"][0]
163-
$lastName = $ADObject.Properties["sn"][0]
164-
$middleName = $ADObject.Properties["middleName"][0]
165-
break
166-
}
167-
default
168-
{
169-
throw "Unsupported AD object type: $($ADObject.GetType().FullName)"
170-
}
216+
[string]$firstName = $ADObject.Properties['givenName'][0]
217+
[string]$lastName = $ADObject.Properties['sn'][0]
218+
[string]$middleName = $ADObject.Properties['middleName'][0]
219+
220+
break
221+
}
222+
default
223+
{
224+
throw "Unsupported AD object type: $($ADObject.GetType().FullName)"
171225
}
172226
}
173-
else
227+
}
228+
else
229+
{
230+
[string]$firstName = $FirstName
231+
[string]$lastName = $LastName
232+
[string]$middleName = $MiddleName
233+
}
234+
235+
# Format first name
236+
$firstName = switch ($FirstNameFormat)
237+
{
238+
'FullName'
174239
{
175-
Write-Verbose "Processing string inputs"
176-
$firstName = $FirstName
177-
$lastName = $LastName
178-
$middleName = $MiddleName
240+
$firstName
179241
}
180-
181-
Write-Verbose "First Name: $firstName, Last Name: $lastName, Middle Name: $middleName"
182-
183-
$firstName = switch ($FirstNameFormat)
242+
'FirstLetter'
184243
{
185-
"Full" { $firstName }
186-
"FirstLetter" { $firstName.Substring(0, 1) }
187-
default { $firstName }
244+
$firstName.Substring(0, 1)
188245
}
189-
190-
$middleNamePart = if ($IncludeMiddleName -and $middleName)
246+
}
247+
248+
# Format last name
249+
$LastName = switch ($FirstNameFormat)
250+
{
251+
'FullName'
191252
{
192-
"$Separator$middleName"
253+
$LastName
193254
}
194-
else { "" }
195-
196-
$baseUPN = "$firstName$middleNamePart$Separator$lastName@$UPNSuffix".ToLower()
197-
Write-Verbose "Base UPN: $baseUPN"
198-
199-
$uniqueUPN = $baseUPN
200-
$counter = 1
201-
202-
while (Test-UPNExist -UPN $uniqueUPN -Server $Server)
255+
'FirstLetter'
203256
{
204-
Write-Verbose "UPN $uniqueUPN already exists, generating alternative"
205-
if ($DuplicateSuffix -eq "Numeric")
206-
{
207-
$uniqueUPN = "{0}{1}@{2}" -f ($baseUPN.Split('@')[0]), $counter, $UPNSuffix
208-
}
209-
else
210-
{
211-
$uniqueUPN = "{0}{1}@{2}" -f ($baseUPN.Split('@')[0]), $CustomDuplicateSuffix, $UPNSuffix
212-
}
213-
$counter++
257+
$LastName.Substring(0, 1)
214258
}
215-
216-
Write-Verbose "Final Unique UPN: $uniqueUPN"
217-
return $uniqueUPN
218259
}
219-
catch
260+
261+
# Use middle name
262+
[string]$middleNamePart = if ($IncludeMiddleName -and $MiddleName)
263+
{
264+
'{0}{1}' -f $Separator, $MiddleName
265+
}
266+
267+
# Setup required attributes
268+
[string]$baseUPN = ('{0}{1}{2}{3}@{4}' -f $FirstName, $middleNamePart, $Separator, $LastName, $UPNSuffix).ToLower()
269+
[string]$uniqueUPN = $baseUPN
270+
[int]$counter = 1
271+
272+
while (Test-UPNExist -UPN $uniqueUPN -Server $ADServer)
220273
{
221-
Write-Error "Error generating UPN: $_"
222-
throw
274+
275+
$uniqueUPN = '{0}{1}@{2}' -f ($baseUPN.Split('@')[0]), $counter, $UPNSuffix
276+
277+
$counter++
223278
}
279+
280+
return $uniqueUPN
224281
}
225282
```
226283

0 commit comments

Comments
 (0)