Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.8k views
in Technique[技术] by (71.8m points)

active directory - Powershell ForEach replace (Bulk change primary SMTP in AD)

I need switch the primary SMTP address in AD in bulk from users of an certain OU.

The challenge;

User1  
smtp:[email protected]  
smtp:[email protected]  
SMTP:[email protected]  
smtp:[email protected]  

I need to make the first.last@domain1 the primary SMTP.

So far I have come to this;

$proxies = $null
Get-ADUser -Filter * -SearchBase "OU=users_test,OU=Test,DC=test,DC=local" -Properties name,mail,ProxyAddresses |
    Foreach {  
        $proxies = $_.ProxyAddresses | 
            ForEach-Object{
                $a = $_ -replace 'SMTP','smtp'
                if($a -match 'domain1.com'){
                    $a -replace 'smtp','SMTP'
                    Write-Host $a
                }else{
                    $a
                }
            }
        $_.ProxyAddresses = $proxies
        #Set-ADUser -instance $_
        Write-host $proxies
    }

The problem:

When I run the above script it obviously make both aliases with domain1.com the primary by replacing the smtp with SMTP on all that it finds matching the domain1.com.

Question: How can I make so it replaces only one?

I hope I explain myself good enough. Thank you in advance for any coming help ??


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since it's not necessary to pick one particular domain1.com address, try this.

I've added a flag variable to set the primary address only once per user. Furthermore I switched to the -like operator, as the -match operator isn't necessary and just produces more overhead if not used correctly.

And I've added the "start of string" regex character to your replacement parts (-replace also uses regex pattern)

Get-ADUser -Filter * -SearchBase 'OU=users_test,OU=Test,DC=test,DC=local' -Properties name, mail, ProxyAddresses |
    ForEach-Object {  
        # flag to avoid further processing after first match
        $userDone = $false
        
        $proxies = $_.ProxyAddresses | 
            ForEach-Object {
                $proxyAddress = $_ -replace '^SMTP', 'smtp'
                if (!$userDone -and $proxyAddress -like '*@domain1.com') {
                    $proxyAddress -replace '^smtp', 'SMTP'
                    
                    $userDone = $true
                } else {
                    $proxyAddress
                }
            }
            $_.ProxyAddresses = $proxies
            #Set-ADUser -instance $_
            Write-Host $proxies
        }

Update 2021-01-13

Here's an update according to your request in the comments below.

Could you show me how I could use the same script that would choose [email protected]. The ForEach should change to primary the one that has first.last.

Now regex makes more sense ;)

The code is untested against Active Directory, but should work.

The regex pattern in short:

(?i)             >case-insensitive match (=regex option)
^                >start of string
(?:              >non-capturing group (capturing is not required in your case)  
  smtp:          >starts with 'smtp:'
  [^.@]+       >matches any char at least once excluding '.' and '@'
  .             >matches '.' once
  [^.@]+       >matches any char at least once excluding '.' and '@'
  @domain1.com  >matches '@domain1.com'
)
$                >end of string

For more details please look at: https://regex101.com/r/atKdSw/1/

I've additionally added a warning when no match has been made due to whatever reason. The addresses are then not returned back to the source property (the addresses remain original).

# pattern matches only addresses with format "*.*@domain.com" --> <anythingButDotOr(at)>.<anythingButDotOr(at)>@domain.com
$newPrimaryAddressMatchPattern = '(?i)^(?:smtp:[^.@]+.[^.@][email protected])$'

Get-ADUser -Filter * -SearchBase 'OU=users_test,OU=Test,DC=test,DC=local' -Properties name, mail, ProxyAddresses |
    ForEach-Object {
        # flag to avoid further processing after first match
        $userDone = $false

        $proxies = $_.ProxyAddresses |
            ForEach-Object {
                $proxyAddress = $_ -replace '^SMTP', 'smtp'
                
                if (!$userDone -and $proxyAddress -match $newPrimaryAddressMatchPattern) {
                    $proxyAddress -replace '^smtp', 'SMTP'

                    $userDone = $true
                } else {
                    $proxyAddress
                }
            }

            if (!$userDone) {
                # if no address matched the pattern required for setting the new primary one
                Write-Warning "Unable to set new primary address for $($_.UserPrincipalName) | $($_.CanonicalName)!"

            } else {
                $_.ProxyAddresses = $proxies
            }

            #Set-ADUser -instance $_
            Write-Host $proxies
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...