Powershell ForEach 替换(在 AD 中批量更改主 SMTP)

Powershell ForEach replace (Bulk change primary SMTP in AD)

我需要从某个OU的用户批量切换AD中的主SMTP地址。

挑战;

User1  
smtp:first.last@domain1.com  
smtp:flast@domain1.com  
SMTP:first.last@domain2.net  
smtp:flast@domain2.net  

我需要将 first.last@domain1 设为主 SMTP。

到此为止;

$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
    }

问题:

当我 运行 上面的脚本时,它显然通过将 smtp 替换为 SMTP 在它找到的所有匹配 domain1.com.

问:怎样才能做到只替换一个?

我希望我能很好地解释自己。预先感谢您提供的任何帮助

因为没有必要选择一个特定的 domain1.com 地址,试试这个。

我添加了一个标志变量来为每个用户设置一次主地址。 此外,我切换到 -like 运算符,因为 -match 运算符不是必需的,如果使用不当只会产生更多开销。

并且我已将“字符串开头”正则表达式字符添加到您的替换部分(-replace 也使用正则表达式模式)

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
        }

更新 2021-01-13

这是根据您在下方评论中的要求进行的更新。

Could you show me how I could use the same script that would choose first.last@domain1.com. The ForEach should change to primary the one that has first.last.

现在正则表达式更有意义 ;)

该代码未针对 Active Directory 进行测试,但应该可以工作。

简而言之正则表达式模式:

(?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

更多详情请看:https://regex101.com/r/atKdSw/1/

当由于任何原因没有匹配时,我另外添加了警告。然后地址不会返回到源 属性(地址保持原始状态)。

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

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
    }