Powershell ForEach 替换批量更改 AD 中的主 SMTP

问题描述

我需要从某个 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

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

你能告诉我如何使用相同的脚本来选择 first.last@domain1.com。 ForEach 应该更改为具有 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,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
    }