Author Posts

February 25, 2016 at 1:18 am

Hey all,

So i am in the process of cleaning up active directory at a client and part of that clean up is amending UPNs that have invalid characters in them, such as ?/#$%^&*'

I want to right a script that searches the whole forest. Now i know that i can do this using:

Where-object {$_.UPN -like "/" -or "'"}

And continue the or statement until i have included all the characters i want to search for. My question is there a neater way to perform the search instead of individually listing them between -or?

February 25, 2016 at 4:11 am

read about regex

-match '[\?/#\$%^&*'']'

February 25, 2016 at 6:42 am

Actually your first example is incorrect. That's not how the -or operator works. And the syntax for the -like operand is incorrect. You would have to use ...

Where-object {$_.UPN -like "*/*" -or $_.UPN -like "*'*"}

RegEx would definitely be a better option.

February 25, 2016 at 6:54 am

Based on Max's pattern above, you could do something along these lines.

# Sample data for the demo, good and bad samples.
$upnList = @'
bob$mccoy$foo.com
david@tango.com
silvia#jones@foo.com
Margo@delata.net
jon^bon&jovey@bar.fiddlesticks.com
Test/User@contoso.com
bill/gates@microsoft.com
'@ -split "`r`n"

$pattern = [regex]'[\?/#\$\\%^&*'']'

foreach ($upn in $upnList)
{
    # This script assumes you are replacing bad characters with an
    # underscore.  Or you could change the replacement to '' in order
    # to just delete the bad characters.
    $upn = $upn -replace $pattern,'_'
    $upn
}

February 25, 2016 at 9:22 am

This will replace non alpha-numeric characters from the loginname part of the UPN. You don't have to worry about selecting characters. This is fine for the English language. I used Bob's list with my example.

# Separate UPN, remove non alpha-numeric characters
# Display new UPN
foreach ($upn in $upnList)
{$m = $upn -match "(?'name'.*)(?'domain'@.*)"
    $newname = $Matches['name'] -replace '\W'
    $newupn = "{0}{1}" -f $newname,$Matches['domain']
$newupn}

February 25, 2016 at 12:25 pm

Hi all, this will be my first post on these forums so don't kill me 😉

Mix and match from above and from my habits

I'd take all users first to a variable, just to play with it faster and not to roll all the users again and again. Also based on my experience it's fast to play with it when it's in the memory.

$pattern = [regex]'[\?\/\#\$\\\%\^\&\*'']'
$ADUsers = get-aduser -fi * | select userprincipalname 
$ADUsers.count
$ADUsers | where {$_ -match $pattern}

If you are searching something else from the UPN then I would split it from @ and look only in to the prefix part

February 26, 2016 at 2:46 am

Thanks so much for all the responses!

Here is my final script. I am always open to crits on ways to better fine tune or do it differently. Always looking to learn more!

Can the same regex principle apply to objectclass? So for example would the following work:
$ObjectClass = [regex]'[\group\user\contact]'

Final script__________________________________________

$Domains = $null
$Domain = $null
$DomainList = $null

$pattern = [regex]'[\?\/\#\$\\\%\^\&\*"]'

$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = @($objForest.Domains | Select-Object Name)
$Domains = $DomainList | foreach {$_.Name}

#This will search each email through all domains
foreach($Domain in ($Domains))
{
Get-ADObject -filter {ObjectClass -eq "User"} -Server $domain -Properties * |
Where-Object {$_.mail -match $pattern} |
select DistinguishedName, userPrincipalName, mail, ObjectClass |
Export-csv -NoTypeInformation -Delimiter ";" -Path c:\Folder\file.csv -Append

}

February 26, 2016 at 6:15 am

I don't see where 'mail' is a property of Get-ADObject. And since that is the heart of your match statement, I can't make this work. You may want to use the EmailAddress property of the Get-ADUser cmdlet.

February 26, 2016 at 6:21 am

You really don't need to initialize you variables to $null.

This ...

$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = @($objForest.Domains | Select-Object Name)
$Domains = $DomainList | foreach {$_.Name}

... can be reduced to this ...

$domains = ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).Name

February 29, 2016 at 2:21 am

Awesome thanks bob, appreciate all the help!

As far as the email attribute:

Get-ADObject -filter {ObjectClass -eq "User"} -Server $domain -Properties * |
Where-Object {$_.mail -match $pattern}

I search for all properties and then single it out in the where-object {$_.Mail). I probably could change -properties * to -properties Mail.

February 29, 2016 at 6:30 am

$re = "[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"

$user = (get-aduser someone).userprincipalname

([regex]::MAtch($user, $re, "IgnoreCase ")).success

February 29, 2016 at 6:33 am

$user = (get-aduser someone).userprincipalname

This assumes that the UPN is the same as the email address, which is not universally the case.

February 29, 2016 at 11:05 am

oops. try this.

'^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$'