question

EavenHuang avatar image
0 Votes"
EavenHuang asked EavenHuang commented

Powershell to compare and modify mailNickname against UserPrincipalName

Dear friends,

I'm looking for a script to compare the AD user attributes of mailNickName and UserPrincipalName. The condition is that UserPrincipleName has a suffix of username@domain.com while there is none for mailNickName. The ideal solution is:

  1. Compare the username part in mailNickName and UserPrincipalName, export only those users are with different values in these 2 fields.

  2. Replace mailNickName with the prefix of UserPrincipalName (without @domain.com)

  3. Make this script check on our AD environment regularly, I can add this script into Windows Task Scheduler if possible?

Following is my current script used to export the attributes, but I would need to manually remove @domain.com via excel then compare them in excel for another run, this seems quite time-consuming. So I'm wondering how to make these more automatic in the script?

   $OUs="OU=Users,xxx,DC=edu,DC=cn"
  foreach ($OU in $OUs) {
      Get-ADUser -Filter * -SearchBase $OU -Properties samAccountName,userPrincipalName,mailNickname,Enabled | 
      Where-Object {$_.Enabled -eq $True -and $_.userPrincipalName -ne $_.mailNickname} | Export-Csv -NoType 'C:\tmp\userPrincipalName_vs_mailNickname.csv'
  }

Basically my current script exports all the users because there is @domain.com in userPrincipalName field while there is none in mailNickName field.



windows-server-powershell
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered EavenHuang commented

As written, the script is supposed to replace the mailNickname -- but I think the replace will fail if the mailNickname property has a null or empty value. If that's true, it's easy enough to handle that by ADDing the missing property:

 $OUs = "OU=Users,xxx,DC=edu,DC=cn"
 foreach ($OU in $OUs) {
     Get-ADUser -Filter * -SearchBase $OU -Properties samAccountName, userPrincipalName, mailNickname, Enabled | 
         Where-Object { $_.Enabled -eq $True} |
             ForEach-Object{
                 $parts = $_.userPrincipalName -split '@'
                 if ($_.mailNickname){
                     if ($parts[0] -ne $_.mailNickname){
                         $was = $_.mailNickName
                         Set-ADUser -Identity $_.samAccountName -Replace @{mailNickname=$parts[0]}
                     }
                 }
                 else{
                     $was = "EMPTY"
                     Set-ADUser -Identity $_.samAccountName -Add @{mailNickname=$parts[0]}
                 }
                 [PSCustomObject]@{
                     Identity = $_.samAccountName
                     UPN = $_.userPrincipalName
                     NicknameWas = $was
                     NickNameNow = $parts[0]
                 }
             }
         } | Export-Csv -NoType 'C:\tmp\userPrincipalName_vs_mailNickname.csv'
 }
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi Rich,

The script seems working fine after I removed the "}" before | Export-Csv:)
Thanks a million for the sharing!!

If you don't mind, I have some questions regarding the PowerShell syntax knowledge, I doubt if my understanding is correct or not.

  1. "EMPTY" is a dedicated word that refers to empty value in AD field, is it correct?

  2. $was variable is declared to be used in exported csv?

  3. [PSCustomObject]@{ : is a custom array defined to have some elements, and these elements are defined to be used in the exported csv only?

  4. Identity, UPN, NicknameWas, NickNameNow are defined as the header of the .csv?

0 Votes 0 ·

"EMPTY" was used only to signify that either the mailNickname property of the user object was either not populated with a value or that the mailNickname property held a string object with a length of zero.

Yes, the $was variable was created only to serve as a way to let you see the original value of the mailNickname property if the value was changed.

The PSCustomObject is a construct that allows you to create an object and populate it with properties with arbitrary names of your own creation and structures of your own (e.g., integers, arrays, hashes, etc.). Its use in the script(s) is solely to allow PowerShell to pass along an object thru the pipeline (in this case to the Export-CSV).

Yes, the properties in the PSCustomObject that the script created (which are of type "NoteProperty") are used by the Export-CSV to create the column names in the CSV.

1 Vote 1 ·

Thanks Rich!!! This is more than helpful!!!

0 Votes 0 ·

Hi Rich,

Please disregard my previous comments about the thrown error, turned out it was a slight error in line 8 where there should NOT be "-" on front of $_.mailNickname.

All good and it works just great now!

0 Votes 0 ·

I corrected both of the scripts to remove that spurious "-". Sorry for not noticing that it was there.

0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered EavenHuang commented

Try this on a limited set of users (or add "-WhatIf:$true" to the Set-ADUser) -- but watch out, because not all AD User objects are maibox- or mail-enabled! You'd probably want to adjust the Where-Object conditions to verify the user is supposed to have a mailNickName!

 $OUs = "OU=Users,xxx,DC=edu,DC=cn"
 foreach ($OU in $OUs) {
     Get-ADUser -Filter * -SearchBase $OU -Properties samAccountName, userPrincipalName, mailNickname, Enabled | 
         Where-Object { $_.Enabled -eq $True} |
             ForEach-Object{
                 $parts = $_.userPrincipalName -split '@'
                 if ($parts[0] -ne $_.mailNickname){
                     $was = $_.mailNickName
                     Set-ADUser -Identity $_.samAccountName -Replace @{mailNickname=$parts[0]}
                     [PSCustomObject]@{
                         Identity = $_.samAccountName
                         UPN = $_.userPrincipalName
                         NicknameWas = $was
                         NickNameNow = $parts[0]
                     }
                 }
             } | Export-Csv -NoType 'C:\tmp\userPrincipalName_vs_mailNickname.csv'
 }
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi Rich,

Thanks a lot for your comment.

II exported the list from AD first and manually checked that most of our AD users have a BLANK mailNickName field. So the idea is that even when we have a BLANK field of mailNickname, we will still need to replace it with the existing UPN prefix. Is it working this way?

0 Votes 0 ·

See modified code to deal with null/empty mailNickname property.

0 Votes 0 ·

Hi Rich,

So we have another issue with the script, I found that the script works perfectly with EMPTY mailNickName field, but when there is already value in mailNickName filed, it threw this error:

Any idea how we can fix it? I can't figure out why it will be treated as "System.Int32" type for mailNickNamefield?


 Cannot convert value "test2.mcs" to type "System.Int32". Error: "Input string was not in a correct format."
 At D:\OneDrive - GTIIT\IT Dept\PowerShell\Scripts\Case_Study\Replace mailNickName with UPN prefix\test.ps1:8 char:26
 +                      if ($parts[0] -ne -$_.mailNickname){
 +                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
     + FullyQualifiedErrorId : InvalidCastFromStringToInteger
     
 Cannot convert value "test2.mcs" to type "System.Int32". Error: "Input string was not in a correct format."
 At D:\OneDrive - GTIIT\IT Dept\PowerShell\Scripts\Case_Study\Replace mailNickName with UPN prefix\test.ps1:12 char:26
 +                      if ($parts[0] -eq -$_.mailNickname){
 +                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
     + FullyQualifiedErrorId : InvalidCastFromStringToInteger
0 Votes 0 ·

There was a spurious "-" in both versions of the code. I removed it in both of the code samples I supplied.

The "-" in front of a variable was trying to coerce a string that held only alphabetic characters into an integer value. That resulted in an error.

1 Vote 1 ·

Thanks Rich for your prompt action, this avoids future misleading if anyone needed the same or similar script:)

0 Votes 0 ·

The scripts have been corrected by removing the spurious "-".

0 Votes 0 ·